10a8c90248264a8b26970b4473770bcc3df8515fJosh Gao"""distutils.command.register
20a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
30a8c90248264a8b26970b4473770bcc3df8515fJosh GaoImplements the Distutils 'register' command (register with the repository).
40a8c90248264a8b26970b4473770bcc3df8515fJosh Gao"""
50a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
60a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# created 2002/10/21, Richard Jones
70a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
80a8c90248264a8b26970b4473770bcc3df8515fJosh Gao__revision__ = "$Id$"
90a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
100a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport urllib2
110a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport getpass
120a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport urlparse
130a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom warnings import warn
140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
150a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom distutils.core import PyPIRCCommand
160a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom distutils import log
170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
180a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass register(PyPIRCCommand):
190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    description = ("register the distribution with the Python package index")
210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    user_options = PyPIRCCommand.user_options + [
220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ('list-classifiers', None,
230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         'list the valid Trove classifiers'),
240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ('strict', None ,
250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         'Will stop the registering if the meta-data are not fully compliant')
260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ]
270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    boolean_options = PyPIRCCommand.boolean_options + [
280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        'verify', 'list-classifiers', 'strict']
290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    sub_commands = [('check', lambda self: True)]
310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def initialize_options(self):
330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        PyPIRCCommand.initialize_options(self)
340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.list_classifiers = 0
350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.strict = 0
360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def finalize_options(self):
380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        PyPIRCCommand.finalize_options(self)
390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # setting options for the `check` subcommand
400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        check_options = {'strict': ('register', self.strict),
410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                         'restructuredtext': ('register', 1)}
420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.distribution.command_options['check'] = check_options
430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def run(self):
450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.finalize_options()
460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self._set_config()
470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # Run sub commands
490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        for cmd_name in self.get_sub_commands():
500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.run_command(cmd_name)
510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.dry_run:
530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.verify_metadata()
540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        elif self.list_classifiers:
550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.classifiers()
560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        else:
570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.send_metadata()
580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def check_metadata(self):
600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Deprecated API."""
610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        warn("distutils.command.register.check_metadata is deprecated, \
620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao              use the check command instead", PendingDeprecationWarning)
630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        check = self.distribution.get_command_obj('check')
640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        check.ensure_finalized()
650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        check.strict = self.strict
660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        check.restructuredtext = 1
670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        check.run()
680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def _set_config(self):
700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ''' Reads the configuration file and set attributes.
710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        '''
720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        config = self._read_pypirc()
730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if config != {}:
740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.username = config['username']
750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.password = config['password']
760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.repository = config['repository']
770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.realm = config['realm']
780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.has_config = True
790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        else:
800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if self.repository not in ('pypi', self.DEFAULT_REPOSITORY):
810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                raise ValueError('%s not found in .pypirc' % self.repository)
820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if self.repository == 'pypi':
830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                self.repository = self.DEFAULT_REPOSITORY
840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.has_config = False
850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def classifiers(self):
870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ''' Fetch the list of classifiers from the server.
880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        '''
890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        response = urllib2.urlopen(self.repository+'?:action=list_classifiers')
900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        log.info(response.read())
910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def verify_metadata(self):
930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ''' Send the metadata to the package index server to be checked.
940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        '''
950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # send the info to the server and report the result
960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        (code, result) = self.post_to_server(self.build_post_data('verify'))
970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        log.info('Server response (%s): %s' % (code, result))
980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def send_metadata(self):
1010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ''' Send the metadata to the package index server.
1020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            Well, do the following:
1040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            1. figure who the user is, and then
1050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            2. send the data as a Basic auth'ed POST.
1060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            First we try to read the username/password from $HOME/.pypirc,
1080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            which is a ConfigParser-formatted file with a section
1090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            [distutils] containing username and password entries (both
1100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            in clear text). Eg:
1110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                [distutils]
1130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                index-servers =
1140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    pypi
1150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                [pypi]
1170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                username: fred
1180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                password: sekrit
1190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            Otherwise, to figure who the user is, we offer the user three
1210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            choices:
1220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao             1. use existing login,
1240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao             2. register as a new user, or
1250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao             3. set the password to a random string and email the user.
1260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        '''
1280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # see if we can short-cut and get the username/password from the
1290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # config
1300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.has_config:
1310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            choice = '1'
1320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            username = self.username
1330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            password = self.password
1340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        else:
1350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            choice = 'x'
1360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            username = password = ''
1370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # get the user's login info
1390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        choices = '1 2 3 4'.split()
1400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        while choice not in choices:
1410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.announce('''\
1420a8c90248264a8b26970b4473770bcc3df8515fJosh GaoWe need to know who you are, so please choose either:
1430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1. use your existing login,
1440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2. register as a new user,
1450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3. have the server generate a new password for you (and email it to you), or
1460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4. quit
1470a8c90248264a8b26970b4473770bcc3df8515fJosh GaoYour selection [default 1]: ''', log.INFO)
1480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            choice = raw_input()
1500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if not choice:
1510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                choice = '1'
1520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            elif choice not in choices:
1530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                print 'Please choose one of the four options!'
1540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if choice == '1':
1560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # get the username and password
1570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            while not username:
1580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                username = raw_input('Username: ')
1590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            while not password:
1600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                password = getpass.getpass('Password: ')
1610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # set up the authentication
1630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            auth = urllib2.HTTPPasswordMgr()
1640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            host = urlparse.urlparse(self.repository)[1]
1650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            auth.add_password(self.realm, host, username, password)
1660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # send the info to the server and report the result
1670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            code, result = self.post_to_server(self.build_post_data('submit'),
1680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                auth)
1690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.announce('Server response (%s): %s' % (code, result),
1700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                          log.INFO)
1710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # possibly save the login
1730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if code == 200:
1740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                if self.has_config:
1750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    # sharing the password in the distribution instance
1760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    # so the upload command can reuse it
1770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    self.distribution.password = password
1780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                else:
1790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    self.announce(('I can store your PyPI login so future '
1800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                   'submissions will be faster.'), log.INFO)
1810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    self.announce('(the login will be stored in %s)' % \
1820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                  self._get_rc_file(), log.INFO)
1830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    choice = 'X'
1840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    while choice.lower() not in 'yn':
1850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                        choice = raw_input('Save your login (y/N)?')
1860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                        if not choice:
1870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                            choice = 'n'
1880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    if choice.lower() == 'y':
1890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                        self._store_pypirc(username, password)
1900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        elif choice == '2':
1920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            data = {':action': 'user'}
1930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            data['name'] = data['password'] = data['email'] = ''
1940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            data['confirm'] = None
1950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            while not data['name']:
1960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                data['name'] = raw_input('Username: ')
1970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            while data['password'] != data['confirm']:
1980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                while not data['password']:
1990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    data['password'] = getpass.getpass('Password: ')
2000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                while not data['confirm']:
2010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    data['confirm'] = getpass.getpass(' Confirm: ')
2020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                if data['password'] != data['confirm']:
2030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    data['password'] = ''
2040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    data['confirm'] = None
2050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    print "Password and confirm don't match!"
2060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            while not data['email']:
2070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                data['email'] = raw_input('   EMail: ')
2080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            code, result = self.post_to_server(data)
2090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if code != 200:
2100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                log.info('Server response (%s): %s' % (code, result))
2110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            else:
2120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                log.info('You will receive an email shortly.')
2130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                log.info(('Follow the instructions in it to '
2140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                          'complete registration.'))
2150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        elif choice == '3':
2160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            data = {':action': 'password_reset'}
2170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            data['email'] = ''
2180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            while not data['email']:
2190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                data['email'] = raw_input('Your email address: ')
2200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            code, result = self.post_to_server(data)
2210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            log.info('Server response (%s): %s' % (code, result))
2220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def build_post_data(self, action):
2240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # figure the data to send - the metadata plus some additional
2250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # information used by the package server
2260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        meta = self.distribution.metadata
2270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        data = {
2280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            ':action': action,
2290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'metadata_version' : '1.0',
2300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'name': meta.get_name(),
2310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'version': meta.get_version(),
2320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'summary': meta.get_description(),
2330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'home_page': meta.get_url(),
2340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'author': meta.get_contact(),
2350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'author_email': meta.get_contact_email(),
2360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'license': meta.get_licence(),
2370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'description': meta.get_long_description(),
2380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'keywords': meta.get_keywords(),
2390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'platform': meta.get_platforms(),
2400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'classifiers': meta.get_classifiers(),
2410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'download_url': meta.get_download_url(),
2420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # PEP 314
2430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'provides': meta.get_provides(),
2440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'requires': meta.get_requires(),
2450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'obsoletes': meta.get_obsoletes(),
2460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        }
2470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if data['provides'] or data['requires'] or data['obsoletes']:
2480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            data['metadata_version'] = '1.1'
2490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return data
2500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def post_to_server(self, data, auth=None):
2520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ''' Post a query to the server, and return a string response.
2530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        '''
2540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if 'name' in data:
2550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.announce('Registering %s to %s' % (data['name'],
2560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                                   self.repository),
2570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                                   log.INFO)
2580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # Build up the MIME payload for the urllib2 POST data
2590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
2600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        sep_boundary = '\n--' + boundary
2610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        end_boundary = sep_boundary + '--'
2620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        chunks = []
2630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        for key, value in data.items():
2640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # handle multiple entries for the same name
2650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if type(value) not in (type([]), type( () )):
2660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                value = [value]
2670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            for value in value:
2680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                chunks.append(sep_boundary)
2690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                chunks.append('\nContent-Disposition: form-data; name="%s"'%key)
2700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                chunks.append("\n\n")
2710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                chunks.append(value)
2720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                if value and value[-1] == '\r':
2730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    chunks.append('\n')  # write an extra newline (lurve Macs)
2740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        chunks.append(end_boundary)
2750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        chunks.append("\n")
2760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # chunks may be bytes (str) or unicode objects that we need to encode
2780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        body = []
2790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        for chunk in chunks:
2800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if isinstance(chunk, unicode):
2810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                body.append(chunk.encode('utf-8'))
2820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            else:
2830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                body.append(chunk)
2840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        body = ''.join(body)
2860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # build the Request
2880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        headers = {
2890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'%boundary,
2900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            'Content-length': str(len(body))
2910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        }
2920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        req = urllib2.Request(self.repository, body, headers)
2930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # handle HTTP and include the Basic Auth handler
2950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        opener = urllib2.build_opener(
2960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            urllib2.HTTPBasicAuthHandler(password_mgr=auth)
2970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        )
2980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        data = ''
2990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        try:
3000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            result = opener.open(req)
3010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        except urllib2.HTTPError, e:
3020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if self.show_response:
3030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                data = e.fp.read()
3040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            result = e.code, e.msg
3050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        except urllib2.URLError, e:
3060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            result = 500, str(e)
3070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        else:
3080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if self.show_response:
3090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                data = result.read()
3100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            result = 200, 'OK'
3110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.show_response:
3120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            dashes = '-' * 75
3130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.announce('%s%s%s' % (dashes, data, dashes))
3140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return result
316