1
# Copyright (C) 2005-2014, 2016 Canonical Ltd
2
# Copyright (C) 2019 Breezy developers
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.
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.
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
18
"""Functions for deriving user configuration from system environment."""
20
from __future__ import absolute_import
25
from .lazy_import import lazy_import
26
lazy_import(globals(), """
38
def ensure_config_dir_exists(path=None):
39
"""Make sure a configuration directory exists.
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.
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):
52
'creating config parent directory: %r', parent_dir)
54
trace.mutter('creating config directory: %r', path)
56
osutils.copy_ownership_from_path(path)
59
def bazaar_config_dir():
60
"""Return per-user configuration directory as unicode string
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
66
TODO: Global option --config-dir to override this.
68
base = osutils.path_from_environ('BZR_HOME')
69
if sys.platform == 'win32':
71
base = win32utils.get_appdata_location()
73
base = win32utils.get_home_location()
74
return osutils.pathjoin(base, 'bazaar', '2.0')
76
xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
78
xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
79
xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
80
if osutils.isdir(xdg_dir):
82
"Using configuration in XDG directory %s." % xdg_dir)
84
base = osutils._get_home_dir()
85
return osutils.pathjoin(base, ".bazaar")
89
"""Return per-user configuration directory as unicode string
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.
95
# TODO: Global option --config-dir to override this.
96
base = osutils.path_from_environ('BRZ_HOME')
97
if sys.platform == 'win32':
99
base = win32utils.get_appdata_location()
101
base = win32utils.get_home_location()
103
base = osutils.path_from_environ('XDG_CONFIG_HOME')
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):
113
"Using Bazaar configuration directory (%s)", bazaar_dir)
114
return (bazaar_dir, 'bazaar')
115
return (breezy_dir, 'breezy')
119
"""Return per-user configuration directory as unicode string
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.
125
return _config_dir()[0]
129
"""Return per-user configuration ini file filename."""
130
path, kind = _config_dir()
132
return osutils.pathjoin(path, 'bazaar.conf')
134
return osutils.pathjoin(path, 'breezy.conf')
137
def locations_config_path():
138
"""Return per-user configuration ini file filename."""
139
return osutils.pathjoin(config_dir(), 'locations.conf')
142
def authentication_config_path():
143
"""Return per-user authentication ini file filename."""
144
return osutils.pathjoin(config_dir(), 'authentication.conf')
147
def user_ignore_config_path():
148
"""Return per-user authentication ini file filename."""
149
return osutils.pathjoin(config_dir(), 'ignore')
153
"""Return the directory name to store crash files.
155
This doesn't implicitly create it.
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
161
if sys.platform == 'win32':
162
return osutils.pathjoin(config_dir(), 'Crash')
164
# XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
166
return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
170
"""Return the cache directory to use."""
171
base = osutils.path_from_environ('BRZ_HOME')
172
if sys.platform in "win32":
174
base = win32utils.get_local_appdata_location()
176
base = win32utils.get_home_location()
178
base = osutils.path_from_environ('XDG_CACHE_HOME')
180
base = osutils.pathjoin(osutils._get_home_dir(), ".cache")
182
cache_dir = osutils.pathjoin(base, "breezy")
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)
191
def _get_default_mail_domain(mailname_file='/etc/mailname'):
192
"""If possible, return the assumed default email domain.
194
:returns: string mail domain, or None.
196
if sys.platform == 'win32':
197
# No implementation yet; patches welcome
200
f = open(mailname_file)
201
except (IOError, OSError):
204
domain = f.readline().strip()
211
v = os.environ.get('BRZ_EMAIL')
214
v = os.environ.get('EMAIL')
217
name, email = _auto_user_id()
219
return u'%s <%s>' % (name, email)
222
raise errors.NoWhoami()
226
"""Calculate automatic user identification.
228
:returns: (realname, email), either of which may be None if they can't be
231
Only used when none is set in the environment or the id file.
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.
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.
240
if sys.platform == 'win32':
241
# No implementation to reliably determine Windows default mail
242
# address; please add one.
245
default_mail_domain = _get_default_mail_domain()
246
if not default_mail_domain:
252
w = pwd.getpwuid(uid)
254
trace.mutter('no passwd entry for uid %d?' % uid)
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.)
262
if isinstance(gecos, bytes):
264
gecos = gecos.decode('utf-8')
268
encoding = osutils.get_user_encoding()
269
gecos = gecos.decode(encoding)
271
trace.mutter("cannot decode passwd entry %s" % w)
275
if isinstance(username, bytes):
277
username = username.decode(encoding)
279
trace.mutter("cannot decode passwd entry %s" % w)
282
comma = gecos.find(',')
286
realname = gecos[:comma]
288
return realname, (username + '@' + default_mail_domain)