183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh"""distutils.command.register
283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehImplements the Distutils 'register' command (register with the repository).
483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh"""
583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# created 2002/10/21, Richard Jones
783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh__revision__ = "$Id$"
983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
1083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport urllib2
1183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport getpass
1283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport urlparse
1383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom warnings import warn
1483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
1583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom distutils.core import PyPIRCCommand
1683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom distutils import log
1783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
1883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass register(PyPIRCCommand):
1983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    description = ("register the distribution with the Python package index")
2183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    user_options = PyPIRCCommand.user_options + [
2283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ('list-classifiers', None,
2383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh         'list the valid Trove classifiers'),
2483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ('strict', None ,
2583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh         'Will stop the registering if the meta-data are not fully compliant')
2683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ]
2783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    boolean_options = PyPIRCCommand.boolean_options + [
2883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        'verify', 'list-classifiers', 'strict']
2983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
3083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    sub_commands = [('check', lambda self: True)]
3183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
3283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def initialize_options(self):
3383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        PyPIRCCommand.initialize_options(self)
3483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.list_classifiers = 0
3583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.strict = 0
3683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
3783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def finalize_options(self):
3883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        PyPIRCCommand.finalize_options(self)
3983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # setting options for the `check` subcommand
4083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        check_options = {'strict': ('register', self.strict),
4183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                         'restructuredtext': ('register', 1)}
4283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.distribution.command_options['check'] = check_options
4383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def run(self):
4583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.finalize_options()
4683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._set_config()
4783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Run sub commands
4983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for cmd_name in self.get_sub_commands():
5083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.run_command(cmd_name)
5183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if self.dry_run:
5383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.verify_metadata()
5483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        elif self.list_classifiers:
5583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.classifiers()
5683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
5783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.send_metadata()
5883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def check_metadata(self):
6083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        """Deprecated API."""
6183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        warn("distutils.command.register.check_metadata is deprecated, \
6283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh              use the check command instead", PendingDeprecationWarning)
6383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        check = self.distribution.get_command_obj('check')
6483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        check.ensure_finalized()
6583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        check.strict = self.strict
6683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        check.restructuredtext = 1
6783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        check.run()
6883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
6983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def _set_config(self):
7083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ''' Reads the configuration file and set attributes.
7183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        '''
7283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        config = self._read_pypirc()
7383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if config != {}:
7483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.username = config['username']
7583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.password = config['password']
7683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.repository = config['repository']
7783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.realm = config['realm']
7883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.has_config = True
7983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
8083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if self.repository not in ('pypi', self.DEFAULT_REPOSITORY):
8183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                raise ValueError('%s not found in .pypirc' % self.repository)
8283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if self.repository == 'pypi':
8383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                self.repository = self.DEFAULT_REPOSITORY
8483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.has_config = False
8583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
8683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def classifiers(self):
8783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ''' Fetch the list of classifiers from the server.
8883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        '''
8983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        response = urllib2.urlopen(self.repository+'?:action=list_classifiers')
9083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        log.info(response.read())
9183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
9283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def verify_metadata(self):
9383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ''' Send the metadata to the package index server to be checked.
9483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        '''
9583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # send the info to the server and report the result
9683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        (code, result) = self.post_to_server(self.build_post_data('verify'))
9783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        log.info('Server response (%s): %s' % (code, result))
9883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
9983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
10083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def send_metadata(self):
10183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ''' Send the metadata to the package index server.
10283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
10383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            Well, do the following:
10483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            1. figure who the user is, and then
10583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            2. send the data as a Basic auth'ed POST.
10683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
10783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            First we try to read the username/password from $HOME/.pypirc,
10883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            which is a ConfigParser-formatted file with a section
10983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            [distutils] containing username and password entries (both
11083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            in clear text). Eg:
11183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
11283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                [distutils]
11383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                index-servers =
11483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    pypi
11583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
11683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                [pypi]
11783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                username: fred
11883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                password: sekrit
11983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
12083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            Otherwise, to figure who the user is, we offer the user three
12183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            choices:
12283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
12383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh             1. use existing login,
12483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh             2. register as a new user, or
12583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh             3. set the password to a random string and email the user.
12683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
12783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        '''
12883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # see if we can short-cut and get the username/password from the
12983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # config
13083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if self.has_config:
13183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            choice = '1'
13283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            username = self.username
13383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            password = self.password
13483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
13583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            choice = 'x'
13683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            username = password = ''
13783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
13883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # get the user's login info
13983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        choices = '1 2 3 4'.split()
14083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        while choice not in choices:
14183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.announce('''\
14283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehWe need to know who you are, so please choose either:
14383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 1. use your existing login,
14483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 2. register as a new user,
14583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3. have the server generate a new password for you (and email it to you), or
14683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 4. quit
14783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehYour selection [default 1]: ''', log.INFO)
14883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
14983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            choice = raw_input()
15083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if not choice:
15183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                choice = '1'
15283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            elif choice not in choices:
15383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                print 'Please choose one of the four options!'
15483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
15583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if choice == '1':
15683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            # get the username and password
15783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            while not username:
15883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                username = raw_input('Username: ')
15983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            while not password:
16083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                password = getpass.getpass('Password: ')
16183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
16283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            # set up the authentication
16383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            auth = urllib2.HTTPPasswordMgr()
16483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            host = urlparse.urlparse(self.repository)[1]
16583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            auth.add_password(self.realm, host, username, password)
16683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            # send the info to the server and report the result
16783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            code, result = self.post_to_server(self.build_post_data('submit'),
16883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                auth)
16983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.announce('Server response (%s): %s' % (code, result),
17083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                          log.INFO)
17183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
17283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            # possibly save the login
17383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if code == 200:
17483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if self.has_config:
17583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # sharing the password in the distribution instance
17683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # so the upload command can reuse it
17783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    self.distribution.password = password
17883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                else:
17983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    self.announce(('I can store your PyPI login so future '
18083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                   'submissions will be faster.'), log.INFO)
18183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    self.announce('(the login will be stored in %s)' % \
18283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                  self._get_rc_file(), log.INFO)
18383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    choice = 'X'
18483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    while choice.lower() not in 'yn':
18583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        choice = raw_input('Save your login (y/N)?')
18683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        if not choice:
18783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                            choice = 'n'
18883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    if choice.lower() == 'y':
18983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        self._store_pypirc(username, password)
19083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
19183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        elif choice == '2':
19283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            data = {':action': 'user'}
19383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            data['name'] = data['password'] = data['email'] = ''
19483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            data['confirm'] = None
19583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            while not data['name']:
19683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                data['name'] = raw_input('Username: ')
19783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            while data['password'] != data['confirm']:
19883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                while not data['password']:
19983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    data['password'] = getpass.getpass('Password: ')
20083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                while not data['confirm']:
20183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    data['confirm'] = getpass.getpass(' Confirm: ')
20283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if data['password'] != data['confirm']:
20383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    data['password'] = ''
20483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    data['confirm'] = None
20583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    print "Password and confirm don't match!"
20683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            while not data['email']:
20783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                data['email'] = raw_input('   EMail: ')
20883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            code, result = self.post_to_server(data)
20983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if code != 200:
21083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                log.info('Server response (%s): %s' % (code, result))
21183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            else:
21283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                log.info('You will receive an email shortly.')
21383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                log.info(('Follow the instructions in it to '
21483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                          'complete registration.'))
21583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        elif choice == '3':
21683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            data = {':action': 'password_reset'}
21783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            data['email'] = ''
21883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            while not data['email']:
21983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                data['email'] = raw_input('Your email address: ')
22083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            code, result = self.post_to_server(data)
22183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            log.info('Server response (%s): %s' % (code, result))
22283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
22383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def build_post_data(self, action):
22483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # figure the data to send - the metadata plus some additional
22583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # information used by the package server
22683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        meta = self.distribution.metadata
22783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        data = {
22883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            ':action': action,
22983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'metadata_version' : '1.0',
23083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'name': meta.get_name(),
23183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'version': meta.get_version(),
23283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'summary': meta.get_description(),
23383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'home_page': meta.get_url(),
23483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'author': meta.get_contact(),
23583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'author_email': meta.get_contact_email(),
23683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'license': meta.get_licence(),
23783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'description': meta.get_long_description(),
23883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'keywords': meta.get_keywords(),
23983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'platform': meta.get_platforms(),
24083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'classifiers': meta.get_classifiers(),
24183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'download_url': meta.get_download_url(),
24283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            # PEP 314
24383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'provides': meta.get_provides(),
24483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'requires': meta.get_requires(),
24583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'obsoletes': meta.get_obsoletes(),
24683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        }
24783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if data['provides'] or data['requires'] or data['obsoletes']:
24883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            data['metadata_version'] = '1.1'
24983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return data
25083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
25183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def post_to_server(self, data, auth=None):
25283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ''' Post a query to the server, and return a string response.
25383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        '''
25483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if 'name' in data:
25583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.announce('Registering %s to %s' % (data['name'],
25683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                                   self.repository),
25783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                                   log.INFO)
25883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Build up the MIME payload for the urllib2 POST data
25983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
26083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        sep_boundary = '\n--' + boundary
26183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        end_boundary = sep_boundary + '--'
26283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        chunks = []
26383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for key, value in data.items():
26483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            # handle multiple entries for the same name
26583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if type(value) not in (type([]), type( () )):
26683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                value = [value]
26783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            for value in value:
26883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                chunks.append(sep_boundary)
26983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                chunks.append('\nContent-Disposition: form-data; name="%s"'%key)
27083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                chunks.append("\n\n")
27183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                chunks.append(value)
27283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if value and value[-1] == '\r':
27383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    chunks.append('\n')  # write an extra newline (lurve Macs)
27483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        chunks.append(end_boundary)
27583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        chunks.append("\n")
27683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
27783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # chunks may be bytes (str) or unicode objects that we need to encode
27883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        body = []
27983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for chunk in chunks:
28083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if isinstance(chunk, unicode):
28183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                body.append(chunk.encode('utf-8'))
28283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            else:
28383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                body.append(chunk)
28483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
28583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        body = ''.join(body)
28683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
28783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # build the Request
28883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        headers = {
28983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'%boundary,
29083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            'Content-length': str(len(body))
29183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        }
29283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        req = urllib2.Request(self.repository, body, headers)
29383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
29483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # handle HTTP and include the Basic Auth handler
29583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        opener = urllib2.build_opener(
29683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            urllib2.HTTPBasicAuthHandler(password_mgr=auth)
29783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        )
29883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        data = ''
29983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        try:
30083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            result = opener.open(req)
30183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        except urllib2.HTTPError, e:
30283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if self.show_response:
30383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                data = e.fp.read()
30483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            result = e.code, e.msg
30583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        except urllib2.URLError, e:
30683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            result = 500, str(e)
30783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
30883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if self.show_response:
30983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                data = result.read()
31083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            result = 200, 'OK'
31183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if self.show_response:
31283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            dashes = '-' * 75
31383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.announce('%s%s%s' % (dashes, data, dashes))
31483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
31583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return result
316