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