/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
7336.2.1 by Martin
Split non-ini config methods to bedding
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)