/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: Jelmer Vernooij
  • Date: 2020-02-07 02:14:30 UTC
  • mto: This revision was merged to the branch mainline in revision 7492.
  • Revision ID: jelmer@jelmer.uk-20200207021430-m49iq3x4x8xlib6x
Drop python2 support.

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