/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: Gustav Hartvigsson
  • Date: 2021-01-09 21:36:27 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210109213627-h1xwcutzy9m7a99b
Added 'Case Preserving Working Tree Use Cases' from Canonical Wiki

* Addod a page from the Canonical Bazaar wiki
  with information on the scmeatics of case
  perserving filesystems an a case insensitive
  filesystem works.
  
  * Needs re-work, but this will do as it is the
    same inforamoton as what was on the linked
    page in the currint documentation.

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