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