1"""distutils.pypirc
2
3Provides the PyPIRCCommand class, the base class for the command classes
4that uses .pypirc in the distutils.command package.
5"""
6import os
7from configparser import RawConfigParser
8
9from distutils.cmd import Command
10
11DEFAULT_PYPIRC = """\
12[distutils]
13index-servers =
14    pypi
15
16[pypi]
17username:%s
18password:%s
19"""
20
21class PyPIRCCommand(Command):
22    """Base command that knows how to handle the .pypirc file
23    """
24    DEFAULT_REPOSITORY = 'https://upload.pypi.org/legacy/'
25    DEFAULT_REALM = 'pypi'
26    repository = None
27    realm = None
28
29    user_options = [
30        ('repository=', 'r',
31         "url of repository [default: %s]" % \
32            DEFAULT_REPOSITORY),
33        ('show-response', None,
34         'display full response text from server')]
35
36    boolean_options = ['show-response']
37
38    def _get_rc_file(self):
39        """Returns rc file path."""
40        return os.path.join(os.path.expanduser('~'), '.pypirc')
41
42    def _store_pypirc(self, username, password):
43        """Creates a default .pypirc file."""
44        rc = self._get_rc_file()
45        with os.fdopen(os.open(rc, os.O_CREAT | os.O_WRONLY, 0o600), 'w') as f:
46            f.write(DEFAULT_PYPIRC % (username, password))
47
48    def _read_pypirc(self):
49        """Reads the .pypirc file."""
50        rc = self._get_rc_file()
51        if os.path.exists(rc):
52            self.announce('Using PyPI login from %s' % rc)
53            repository = self.repository or self.DEFAULT_REPOSITORY
54
55            config = RawConfigParser()
56            config.read(rc)
57            sections = config.sections()
58            if 'distutils' in sections:
59                # let's get the list of servers
60                index_servers = config.get('distutils', 'index-servers')
61                _servers = [server.strip() for server in
62                            index_servers.split('\n')
63                            if server.strip() != '']
64                if _servers == []:
65                    # nothing set, let's try to get the default pypi
66                    if 'pypi' in sections:
67                        _servers = ['pypi']
68                    else:
69                        # the file is not properly defined, returning
70                        # an empty dict
71                        return {}
72                for server in _servers:
73                    current = {'server': server}
74                    current['username'] = config.get(server, 'username')
75
76                    # optional params
77                    for key, default in (('repository',
78                                          self.DEFAULT_REPOSITORY),
79                                         ('realm', self.DEFAULT_REALM),
80                                         ('password', None)):
81                        if config.has_option(server, key):
82                            current[key] = config.get(server, key)
83                        else:
84                            current[key] = default
85
86                    # work around people having "repository" for the "pypi"
87                    # section of their config set to the HTTP (rather than
88                    # HTTPS) URL
89                    if (server == 'pypi' and
90                        repository in (self.DEFAULT_REPOSITORY, 'pypi')):
91                        current['repository'] = self.DEFAULT_REPOSITORY
92                        return current
93
94                    if (current['server'] == repository or
95                        current['repository'] == repository):
96                        return current
97            elif 'server-login' in sections:
98                # old format
99                server = 'server-login'
100                if config.has_option(server, 'repository'):
101                    repository = config.get(server, 'repository')
102                else:
103                    repository = self.DEFAULT_REPOSITORY
104                return {'username': config.get(server, 'username'),
105                        'password': config.get(server, 'password'),
106                        'repository': repository,
107                        'server': server,
108                        'realm': self.DEFAULT_REALM}
109
110        return {}
111
112    def _read_pypi_response(self, response):
113        """Read and decode a PyPI HTTP response."""
114        import cgi
115        content_type = response.getheader('content-type', 'text/plain')
116        encoding = cgi.parse_header(content_type)[1].get('charset', 'ascii')
117        return response.read().decode(encoding)
118
119    def initialize_options(self):
120        """Initialize options."""
121        self.repository = None
122        self.realm = None
123        self.show_response = 0
124
125    def finalize_options(self):
126        """Finalizes options."""
127        if self.repository is None:
128            self.repository = self.DEFAULT_REPOSITORY
129        if self.realm is None:
130            self.realm = self.DEFAULT_REALM
131