PageRenderTime 83ms CodeModel.GetById 24ms app.highlight 55ms RepoModel.GetById 1ms app.codeStats 0ms

/External.LCA_RESTRICTED/Languages/IronPython/27/Lib/distutils/command/register.py

https://github.com/rpattabi/ironruby
Python | 307 lines | 294 code | 6 blank | 7 comment | 7 complexity | 285315f128010820a8833c96d173017e MD5 | raw file
  1"""distutils.command.register
  2
  3Implements the Distutils 'register' command (register with the repository).
  4"""
  5
  6# created 2002/10/21, Richard Jones
  7
  8__revision__ = "$Id: register.py 77717 2010-01-24 00:33:32Z tarek.ziade $"
  9
 10import urllib2
 11import getpass
 12import urlparse
 13import StringIO
 14from warnings import warn
 15
 16from distutils.core import PyPIRCCommand
 17from distutils import log
 18
 19class register(PyPIRCCommand):
 20
 21    description = ("register the distribution with the Python package index")
 22    user_options = PyPIRCCommand.user_options + [
 23        ('list-classifiers', None,
 24         'list the valid Trove classifiers'),
 25        ('strict', None ,
 26         'Will stop the registering if the meta-data are not fully compliant')
 27        ]
 28    boolean_options = PyPIRCCommand.boolean_options + [
 29        'verify', 'list-classifiers', 'strict']
 30
 31    sub_commands = [('check', lambda self: True)]
 32
 33    def initialize_options(self):
 34        PyPIRCCommand.initialize_options(self)
 35        self.list_classifiers = 0
 36        self.strict = 0
 37
 38    def finalize_options(self):
 39        PyPIRCCommand.finalize_options(self)
 40        # setting options for the `check` subcommand
 41        check_options = {'strict': ('register', self.strict),
 42                         'restructuredtext': ('register', 1)}
 43        self.distribution.command_options['check'] = check_options
 44
 45    def run(self):
 46        self.finalize_options()
 47        self._set_config()
 48
 49        # Run sub commands
 50        for cmd_name in self.get_sub_commands():
 51            self.run_command(cmd_name)
 52
 53        if self.dry_run:
 54            self.verify_metadata()
 55        elif self.list_classifiers:
 56            self.classifiers()
 57        else:
 58            self.send_metadata()
 59
 60    def check_metadata(self):
 61        """Deprecated API."""
 62        warn("distutils.command.register.check_metadata is deprecated, \
 63              use the check command instead", PendingDeprecationWarning)
 64        check = self.distribution.get_command_obj('check')
 65        check.ensure_finalized()
 66        check.strict = self.strict
 67        check.restructuredtext = 1
 68        check.run()
 69
 70    def _set_config(self):
 71        ''' Reads the configuration file and set attributes.
 72        '''
 73        config = self._read_pypirc()
 74        if config != {}:
 75            self.username = config['username']
 76            self.password = config['password']
 77            self.repository = config['repository']
 78            self.realm = config['realm']
 79            self.has_config = True
 80        else:
 81            if self.repository not in ('pypi', self.DEFAULT_REPOSITORY):
 82                raise ValueError('%s not found in .pypirc' % self.repository)
 83            if self.repository == 'pypi':
 84                self.repository = self.DEFAULT_REPOSITORY
 85            self.has_config = False
 86
 87    def classifiers(self):
 88        ''' Fetch the list of classifiers from the server.
 89        '''
 90        response = urllib2.urlopen(self.repository+'?:action=list_classifiers')
 91        log.info(response.read())
 92
 93    def verify_metadata(self):
 94        ''' Send the metadata to the package index server to be checked.
 95        '''
 96        # send the info to the server and report the result
 97        (code, result) = self.post_to_server(self.build_post_data('verify'))
 98        log.info('Server response (%s): %s' % (code, result))
 99
100
101    def send_metadata(self):
102        ''' Send the metadata to the package index server.
103
104            Well, do the following:
105            1. figure who the user is, and then
106            2. send the data as a Basic auth'ed POST.
107
108            First we try to read the username/password from $HOME/.pypirc,
109            which is a ConfigParser-formatted file with a section
110            [distutils] containing username and password entries (both
111            in clear text). Eg:
112
113                [distutils]
114                index-servers =
115                    pypi
116
117                [pypi]
118                username: fred
119                password: sekrit
120
121            Otherwise, to figure who the user is, we offer the user three
122            choices:
123
124             1. use existing login,
125             2. register as a new user, or
126             3. set the password to a random string and email the user.
127
128        '''
129        # see if we can short-cut and get the username/password from the
130        # config
131        if self.has_config:
132            choice = '1'
133            username = self.username
134            password = self.password
135        else:
136            choice = 'x'
137            username = password = ''
138
139        # get the user's login info
140        choices = '1 2 3 4'.split()
141        while choice not in choices:
142            self.announce('''\
143We need to know who you are, so please choose either:
144 1. use your existing login,
145 2. register as a new user,
146 3. have the server generate a new password for you (and email it to you), or
147 4. quit
148Your selection [default 1]: ''', log.INFO)
149
150            choice = raw_input()
151            if not choice:
152                choice = '1'
153            elif choice not in choices:
154                print 'Please choose one of the four options!'
155
156        if choice == '1':
157            # get the username and password
158            while not username:
159                username = raw_input('Username: ')
160            while not password:
161                password = getpass.getpass('Password: ')
162
163            # set up the authentication
164            auth = urllib2.HTTPPasswordMgr()
165            host = urlparse.urlparse(self.repository)[1]
166            auth.add_password(self.realm, host, username, password)
167            # send the info to the server and report the result
168            code, result = self.post_to_server(self.build_post_data('submit'),
169                auth)
170            self.announce('Server response (%s): %s' % (code, result),
171                          log.INFO)
172
173            # possibly save the login
174            if code == 200:
175                if self.has_config:
176                    # sharing the password in the distribution instance
177                    # so the upload command can reuse it
178                    self.distribution.password = password
179                else:
180                    self.announce(('I can store your PyPI login so future '
181                                   'submissions will be faster.'), log.INFO)
182                    self.announce('(the login will be stored in %s)' % \
183                                  self._get_rc_file(), log.INFO)
184                    choice = 'X'
185                    while choice.lower() not in 'yn':
186                        choice = raw_input('Save your login (y/N)?')
187                        if not choice:
188                            choice = 'n'
189                    if choice.lower() == 'y':
190                        self._store_pypirc(username, password)
191
192        elif choice == '2':
193            data = {':action': 'user'}
194            data['name'] = data['password'] = data['email'] = ''
195            data['confirm'] = None
196            while not data['name']:
197                data['name'] = raw_input('Username: ')
198            while data['password'] != data['confirm']:
199                while not data['password']:
200                    data['password'] = getpass.getpass('Password: ')
201                while not data['confirm']:
202                    data['confirm'] = getpass.getpass(' Confirm: ')
203                if data['password'] != data['confirm']:
204                    data['password'] = ''
205                    data['confirm'] = None
206                    print "Password and confirm don't match!"
207            while not data['email']:
208                data['email'] = raw_input('   EMail: ')
209            code, result = self.post_to_server(data)
210            if code != 200:
211                log.info('Server response (%s): %s' % (code, result))
212            else:
213                log.info('You will receive an email shortly.')
214                log.info(('Follow the instructions in it to '
215                          'complete registration.'))
216        elif choice == '3':
217            data = {':action': 'password_reset'}
218            data['email'] = ''
219            while not data['email']:
220                data['email'] = raw_input('Your email address: ')
221            code, result = self.post_to_server(data)
222            log.info('Server response (%s): %s' % (code, result))
223
224    def build_post_data(self, action):
225        # figure the data to send - the metadata plus some additional
226        # information used by the package server
227        meta = self.distribution.metadata
228        data = {
229            ':action': action,
230            'metadata_version' : '1.0',
231            'name': meta.get_name(),
232            'version': meta.get_version(),
233            'summary': meta.get_description(),
234            'home_page': meta.get_url(),
235            'author': meta.get_contact(),
236            'author_email': meta.get_contact_email(),
237            'license': meta.get_licence(),
238            'description': meta.get_long_description(),
239            'keywords': meta.get_keywords(),
240            'platform': meta.get_platforms(),
241            'classifiers': meta.get_classifiers(),
242            'download_url': meta.get_download_url(),
243            # PEP 314
244            'provides': meta.get_provides(),
245            'requires': meta.get_requires(),
246            'obsoletes': meta.get_obsoletes(),
247        }
248        if data['provides'] or data['requires'] or data['obsoletes']:
249            data['metadata_version'] = '1.1'
250        return data
251
252    def post_to_server(self, data, auth=None):
253        ''' Post a query to the server, and return a string response.
254        '''
255        if 'name' in data:
256            self.announce('Registering %s to %s' % (data['name'],
257                                                   self.repository),
258                                                   log.INFO)
259        # Build up the MIME payload for the urllib2 POST data
260        boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
261        sep_boundary = '\n--' + boundary
262        end_boundary = sep_boundary + '--'
263        body = StringIO.StringIO()
264        for key, value in data.items():
265            # handle multiple entries for the same name
266            if type(value) not in (type([]), type( () )):
267                value = [value]
268            for value in value:
269                body.write(sep_boundary)
270                body.write('\nContent-Disposition: form-data; name="%s"'%key)
271                body.write("\n\n")
272                body.write(value)
273                if value and value[-1] == '\r':
274                    body.write('\n')  # write an extra newline (lurve Macs)
275        body.write(end_boundary)
276        body.write("\n")
277        body = body.getvalue()
278
279        # build the Request
280        headers = {
281            'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'%boundary,
282            'Content-length': str(len(body))
283        }
284        req = urllib2.Request(self.repository, body, headers)
285
286        # handle HTTP and include the Basic Auth handler
287        opener = urllib2.build_opener(
288            urllib2.HTTPBasicAuthHandler(password_mgr=auth)
289        )
290        data = ''
291        try:
292            result = opener.open(req)
293        except urllib2.HTTPError, e:
294            if self.show_response:
295                data = e.fp.read()
296            result = e.code, e.msg
297        except urllib2.URLError, e:
298            result = 500, str(e)
299        else:
300            if self.show_response:
301                data = result.read()
302            result = 200, 'OK'
303        if self.show_response:
304            dashes = '-' * 75
305            self.announce('%s%s%s' % (dashes, data, dashes))
306
307        return result