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(), """
41
def ensure_config_dir_exists(path=None):
42
"""Make sure a configuration directory exists.
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.
50
if not os.path.isdir(path):
51
if sys.platform == 'win32':
52
parent_dir = os.path.dirname(path)
53
if not os.path.isdir(parent_dir):
55
'creating config parent directory: %r', parent_dir)
57
trace.mutter('creating config directory: %r', path)
59
osutils.copy_ownership_from_path(path)
62
def bazaar_config_dir():
63
"""Return per-user configuration directory as unicode string
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
69
TODO: Global option --config-dir to override this.
71
base = osutils.path_from_environ('BZR_HOME')
72
if sys.platform == 'win32':
74
base = win32utils.get_appdata_location()
76
base = win32utils.get_home_location()
77
return osutils.pathjoin(base, 'bazaar', '2.0')
79
xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
81
xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
82
xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
83
if osutils.isdir(xdg_dir):
85
"Using configuration in XDG directory %s." % xdg_dir)
87
base = osutils._get_home_dir()
88
return osutils.pathjoin(base, ".bazaar")
92
"""Return per-user configuration directory as unicode string
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.
98
# TODO: Global option --config-dir to override this.
99
base = osutils.path_from_environ('BRZ_HOME')
100
if sys.platform == 'win32':
102
base = win32utils.get_appdata_location()
104
base = win32utils.get_home_location()
106
base = osutils.path_from_environ('XDG_CONFIG_HOME')
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):
116
"Using Bazaar configuration directory (%s)", bazaar_dir)
117
return (bazaar_dir, 'bazaar')
118
return (breezy_dir, 'breezy')
122
"""Return per-user configuration directory as unicode string
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.
128
return _config_dir()[0]
132
"""Return per-user configuration ini file filename."""
133
path, kind = _config_dir()
135
return osutils.pathjoin(path, 'bazaar.conf')
137
return osutils.pathjoin(path, 'breezy.conf')
140
def locations_config_path():
141
"""Return per-user configuration ini file filename."""
142
return osutils.pathjoin(config_dir(), 'locations.conf')
145
def authentication_config_path():
146
"""Return per-user authentication ini file filename."""
147
return osutils.pathjoin(config_dir(), 'authentication.conf')
150
def user_ignore_config_path():
151
"""Return per-user authentication ini file filename."""
152
return osutils.pathjoin(config_dir(), 'ignore')
156
"""Return the directory name to store crash files.
158
This doesn't implicitly create it.
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
164
if sys.platform == 'win32':
165
return osutils.pathjoin(config_dir(), 'Crash')
167
# XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
169
return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
173
"""Return the cache directory to use."""
174
base = osutils.path_from_environ('BRZ_HOME')
175
if sys.platform in "win32":
177
base = win32utils.get_local_appdata_location()
179
base = win32utils.get_home_location()
181
base = osutils.path_from_environ('XDG_CACHE_HOME')
183
base = osutils.pathjoin(osutils._get_home_dir(), ".cache")
185
cache_dir = osutils.pathjoin(base, "breezy")
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)
194
def _get_default_mail_domain(mailname_file='/etc/mailname'):
195
"""If possible, return the assumed default email domain.
197
:returns: string mail domain, or None.
199
if sys.platform == 'win32':
200
# No implementation yet; patches welcome
203
f = open(mailname_file)
204
except (IOError, OSError):
207
domain = f.readline().strip()
214
v = os.environ.get('BRZ_EMAIL')
217
v = v.decode(osutils.get_user_encoding())
219
v = os.environ.get('EMAIL')
222
v = v.decode(osutils.get_user_encoding())
224
name, email = _auto_user_id()
226
return u'%s <%s>' % (name, email)
229
raise errors.NoWhoami()
233
"""Calculate automatic user identification.
235
:returns: (realname, email), either of which may be None if they can't be
238
Only used when none is set in the environment or the id file.
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.
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.
247
if sys.platform == 'win32':
248
# No implementation to reliably determine Windows default mail
249
# address; please add one.
252
default_mail_domain = _get_default_mail_domain()
253
if not default_mail_domain:
259
w = pwd.getpwuid(uid)
261
trace.mutter('no passwd entry for uid %d?' % uid)
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.)
269
if isinstance(gecos, bytes):
271
gecos = gecos.decode('utf-8')
275
encoding = osutils.get_user_encoding()
276
gecos = gecos.decode(encoding)
278
trace.mutter("cannot decode passwd entry %s" % w)
282
if isinstance(username, bytes):
284
username = username.decode(encoding)
286
trace.mutter("cannot decode passwd entry %s" % w)
289
comma = gecos.find(',')
293
realname = gecos[:comma]
295
return realname, (username + '@' + default_mail_domain)