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