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