/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/bedding.py

  • Committer: Martin
  • Date: 2019-06-16 01:03:51 UTC
  • mto: This revision was merged to the branch mainline in revision 7340.
  • Revision ID: gzlist@googlemail.com-20190616010351-uz89ydnwdoal4ve4
Split non-ini config methods to bedding

Functions that determine filesystem paths to use for config and default
username are now outside of the main (large) config module.

Also move cache_dir function from osutils and normalise logic.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005-2014, 2016 Canonical Ltd
 
2
# Copyright (C) 2019 Breezy developers
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
17
 
 
18
"""Functions for deriving user configuration from system environment."""
 
19
 
 
20
from __future__ import absolute_import
 
21
 
 
22
import os
 
23
import sys
 
24
 
 
25
from .lazy_import import lazy_import
 
26
lazy_import(globals(), """
 
27
from breezy import (
 
28
    errors,
 
29
    osutils,
 
30
    trace,
 
31
    win32utils,
 
32
    )
 
33
""")
 
34
from .sixish import (
 
35
    PY3,
 
36
    )
 
37
 
 
38
 
 
39
def ensure_config_dir_exists(path=None):
 
40
    """Make sure a configuration directory exists.
 
41
 
 
42
    This makes sure that the directory exists.
 
43
    On windows, since configuration directories are 2 levels deep,
 
44
    it makes sure both the directory and the parent directory exists.
 
45
    """
 
46
    if path is None:
 
47
        path = config_dir()
 
48
    if not os.path.isdir(path):
 
49
        if sys.platform == 'win32':
 
50
            parent_dir = os.path.dirname(path)
 
51
            if not os.path.isdir(parent_dir):
 
52
                trace.mutter(
 
53
                    'creating config parent directory: %r', parent_dir)
 
54
                os.mkdir(parent_dir)
 
55
        trace.mutter('creating config directory: %r', path)
 
56
        os.mkdir(path)
 
57
        osutils.copy_ownership_from_path(path)
 
58
 
 
59
 
 
60
def bazaar_config_dir():
 
61
    """Return per-user configuration directory as unicode string
 
62
 
 
63
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
 
64
    and Linux.  On Mac OS X and Linux, if there is a $XDG_CONFIG_HOME/bazaar
 
65
    directory, that will be used instead
 
66
 
 
67
    TODO: Global option --config-dir to override this.
 
68
    """
 
69
    base = osutils.path_from_environ('BZR_HOME')
 
70
    if sys.platform == 'win32':
 
71
        if base is None:
 
72
            base = win32utils.get_appdata_location()
 
73
        if base is None:
 
74
            base = win32utils.get_home_location()
 
75
        return osutils.pathjoin(base, 'bazaar', '2.0')
 
76
    if base is None:
 
77
        xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
 
78
        if xdg_dir is None:
 
79
            xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
 
80
        xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
 
81
        if osutils.isdir(xdg_dir):
 
82
            trace.mutter(
 
83
                "Using configuration in XDG directory %s." % xdg_dir)
 
84
            return xdg_dir
 
85
        base = osutils._get_home_dir()
 
86
    return osutils.pathjoin(base, ".bazaar")
 
87
 
 
88
 
 
89
def _config_dir():
 
90
    """Return per-user configuration directory as unicode string
 
91
 
 
92
    By default this is %APPDATA%/breezy on Windows, $XDG_CONFIG_HOME/breezy on
 
93
    Mac OS X and Linux. If the breezy config directory doesn't exist but
 
94
    the bazaar one (see bazaar_config_dir()) does, use that instead.
 
95
    """
 
96
    # TODO: Global option --config-dir to override this.
 
97
    base = osutils.path_from_environ('BRZ_HOME')
 
98
    if sys.platform == 'win32':
 
99
        if base is None:
 
100
            base = win32utils.get_appdata_location()
 
101
        if base is None:
 
102
            base = win32utils.get_home_location()
 
103
    if base is None:
 
104
        base = osutils.path_from_environ('XDG_CONFIG_HOME')
 
105
        if base is None:
 
106
            base = osutils.pathjoin(osutils._get_home_dir(), ".config")
 
107
    breezy_dir = osutils.pathjoin(base, 'breezy')
 
108
    if osutils.isdir(breezy_dir):
 
109
        return (breezy_dir, 'breezy')
 
110
    # If the breezy directory doesn't exist, but the bazaar one does, use that:
 
111
    bazaar_dir = bazaar_config_dir()
 
112
    if osutils.isdir(bazaar_dir):
 
113
        trace.mutter(
 
114
            "Using Bazaar configuration directory (%s)", bazaar_dir)
 
115
        return (bazaar_dir, 'bazaar')
 
116
    return (breezy_dir, 'breezy')
 
117
 
 
118
 
 
119
def config_dir():
 
120
    """Return per-user configuration directory as unicode string
 
121
 
 
122
    By default this is %APPDATA%/breezy on Windows, $XDG_CONFIG_HOME/breezy on
 
123
    Mac OS X and Linux. If the breezy config directory doesn't exist but
 
124
    the bazaar one (see bazaar_config_dir()) does, use that instead.
 
125
    """
 
126
    return _config_dir()[0]
 
127
 
 
128
 
 
129
def config_path():
 
130
    """Return per-user configuration ini file filename."""
 
131
    path, kind = _config_dir()
 
132
    if kind == 'bazaar':
 
133
        return osutils.pathjoin(path, 'bazaar.conf')
 
134
    else:
 
135
        return osutils.pathjoin(path, 'breezy.conf')
 
136
 
 
137
 
 
138
def locations_config_path():
 
139
    """Return per-user configuration ini file filename."""
 
140
    return osutils.pathjoin(config_dir(), 'locations.conf')
 
141
 
 
142
 
 
143
def authentication_config_path():
 
144
    """Return per-user authentication ini file filename."""
 
145
    return osutils.pathjoin(config_dir(), 'authentication.conf')
 
146
 
 
147
 
 
148
def user_ignore_config_path():
 
149
    """Return per-user authentication ini file filename."""
 
150
    return osutils.pathjoin(config_dir(), 'ignore')
 
151
 
 
152
 
 
153
def crash_dir():
 
154
    """Return the directory name to store crash files.
 
155
 
 
156
    This doesn't implicitly create it.
 
157
 
 
158
    On Windows it's in the config directory; elsewhere it's /var/crash
 
159
    which may be monitored by apport.  It can be overridden by
 
160
    $APPORT_CRASH_DIR.
 
161
    """
 
162
    if sys.platform == 'win32':
 
163
        return osutils.pathjoin(config_dir(), 'Crash')
 
164
    else:
 
165
        # XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
 
166
        # 2010-01-31
 
167
        return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
 
168
 
 
169
 
 
170
def cache_dir():
 
171
    """Return the cache directory to use."""
 
172
    if sys.platform in "win32":
 
173
        base = win32utils.get_local_appdata_location()
 
174
        if base is None:
 
175
            base = win32utils.get_home_location()
 
176
    else:
 
177
        base = osutils.path_from_environ('XDG_CACHE_HOME')
 
178
        if base is None:
 
179
            base = osutils.pathjoin(osutils._get_home_dir(), ".cache")
 
180
 
 
181
    cache_dir = osutils.pathjoin(base, "breezy")
 
182
 
 
183
    # GZ 2019-06-15: Move responsibility for ensuring dir exists elsewhere?
 
184
    if not os.path.exists(cache_dir):
 
185
        os.makedirs(cache_dir)
 
186
 
 
187
    return cache_dir
 
188
 
 
189
 
 
190
def _get_default_mail_domain(mailname_file='/etc/mailname'):
 
191
    """If possible, return the assumed default email domain.
 
192
 
 
193
    :returns: string mail domain, or None.
 
194
    """
 
195
    if sys.platform == 'win32':
 
196
        # No implementation yet; patches welcome
 
197
        return None
 
198
    try:
 
199
        f = open(mailname_file)
 
200
    except (IOError, OSError):
 
201
        return None
 
202
    try:
 
203
        domain = f.readline().strip()
 
204
        return domain
 
205
    finally:
 
206
        f.close()
 
207
 
 
208
 
 
209
def default_email():
 
210
    v = os.environ.get('BRZ_EMAIL')
 
211
    if v:
 
212
        if not PY3:
 
213
            v = v.decode(osutils.get_user_encoding())
 
214
        return v
 
215
    v = os.environ.get('EMAIL')
 
216
    if v:
 
217
        if not PY3:
 
218
            v = v.decode(osutils.get_user_encoding())
 
219
        return v
 
220
    name, email = _auto_user_id()
 
221
    if name and email:
 
222
        return u'%s <%s>' % (name, email)
 
223
    elif email:
 
224
        return email
 
225
    raise errors.NoWhoami()
 
226
 
 
227
 
 
228
def _auto_user_id():
 
229
    """Calculate automatic user identification.
 
230
 
 
231
    :returns: (realname, email), either of which may be None if they can't be
 
232
    determined.
 
233
 
 
234
    Only used when none is set in the environment or the id file.
 
235
 
 
236
    This only returns an email address if we can be fairly sure the
 
237
    address is reasonable, ie if /etc/mailname is set on unix.
 
238
 
 
239
    This doesn't use the FQDN as the default domain because that may be
 
240
    slow, and it doesn't use the hostname alone because that's not normally
 
241
    a reasonable address.
 
242
    """
 
243
    if sys.platform == 'win32':
 
244
        # No implementation to reliably determine Windows default mail
 
245
        # address; please add one.
 
246
        return None, None
 
247
 
 
248
    default_mail_domain = _get_default_mail_domain()
 
249
    if not default_mail_domain:
 
250
        return None, None
 
251
 
 
252
    import pwd
 
253
    uid = os.getuid()
 
254
    try:
 
255
        w = pwd.getpwuid(uid)
 
256
    except KeyError:
 
257
        trace.mutter('no passwd entry for uid %d?' % uid)
 
258
        return None, None
 
259
 
 
260
    # we try utf-8 first, because on many variants (like Linux),
 
261
    # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
262
    # false positives.  (many users will have their user encoding set to
 
263
    # latin-1, which cannot raise UnicodeError.)
 
264
    gecos = w.pw_gecos
 
265
    if isinstance(gecos, bytes):
 
266
        try:
 
267
            gecos = gecos.decode('utf-8')
 
268
            encoding = 'utf-8'
 
269
        except UnicodeError:
 
270
            try:
 
271
                encoding = osutils.get_user_encoding()
 
272
                gecos = gecos.decode(encoding)
 
273
            except UnicodeError:
 
274
                trace.mutter("cannot decode passwd entry %s" % w)
 
275
                return None, None
 
276
 
 
277
    username = w.pw_name
 
278
    if isinstance(username, bytes):
 
279
        try:
 
280
            username = username.decode(encoding)
 
281
        except UnicodeError:
 
282
            trace.mutter("cannot decode passwd entry %s" % w)
 
283
            return None, None
 
284
 
 
285
    comma = gecos.find(',')
 
286
    if comma == -1:
 
287
        realname = gecos
 
288
    else:
 
289
        realname = gecos[:comma]
 
290
 
 
291
    return realname, (username + '@' + default_mail_domain)