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(), """
39
def ensure_config_dir_exists(path=None):
40
"""Make sure a configuration directory exists.
42
This makes sure that the directory exists.
43
On windows, since configuration directories are 2 levels deep,
44
it makes sure both the directory and the parent directory exists.
48
if not os.path.isdir(path):
49
if sys.platform == 'win32':
50
parent_dir = os.path.dirname(path)
51
if not os.path.isdir(parent_dir):
53
'creating config parent directory: %r', parent_dir)
55
trace.mutter('creating config directory: %r', path)
57
osutils.copy_ownership_from_path(path)
60
def bazaar_config_dir():
61
"""Return per-user configuration directory as unicode string
63
By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
64
and Linux. On Mac OS X and Linux, if there is a $XDG_CONFIG_HOME/bazaar
65
directory, that will be used instead
67
TODO: Global option --config-dir to override this.
69
base = osutils.path_from_environ('BZR_HOME')
70
if sys.platform == 'win32':
72
base = win32utils.get_appdata_location()
74
base = win32utils.get_home_location()
75
return osutils.pathjoin(base, 'bazaar', '2.0')
77
xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
79
xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
80
xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
81
if osutils.isdir(xdg_dir):
83
"Using configuration in XDG directory %s." % xdg_dir)
85
base = osutils._get_home_dir()
86
return osutils.pathjoin(base, ".bazaar")
90
"""Return per-user configuration directory as unicode string
92
By default this is %APPDATA%/breezy on Windows, $XDG_CONFIG_HOME/breezy on
93
Mac OS X and Linux. If the breezy config directory doesn't exist but
94
the bazaar one (see bazaar_config_dir()) does, use that instead.
96
# TODO: Global option --config-dir to override this.
97
base = osutils.path_from_environ('BRZ_HOME')
98
if sys.platform == 'win32':
100
base = win32utils.get_appdata_location()
102
base = win32utils.get_home_location()
104
base = osutils.path_from_environ('XDG_CONFIG_HOME')
106
base = osutils.pathjoin(osutils._get_home_dir(), ".config")
107
breezy_dir = osutils.pathjoin(base, 'breezy')
108
if osutils.isdir(breezy_dir):
109
return (breezy_dir, 'breezy')
110
# If the breezy directory doesn't exist, but the bazaar one does, use that:
111
bazaar_dir = bazaar_config_dir()
112
if osutils.isdir(bazaar_dir):
114
"Using Bazaar configuration directory (%s)", bazaar_dir)
115
return (bazaar_dir, 'bazaar')
116
return (breezy_dir, 'breezy')
120
"""Return per-user configuration directory as unicode string
122
By default this is %APPDATA%/breezy on Windows, $XDG_CONFIG_HOME/breezy on
123
Mac OS X and Linux. If the breezy config directory doesn't exist but
124
the bazaar one (see bazaar_config_dir()) does, use that instead.
126
return _config_dir()[0]
130
"""Return per-user configuration ini file filename."""
131
path, kind = _config_dir()
133
return osutils.pathjoin(path, 'bazaar.conf')
135
return osutils.pathjoin(path, 'breezy.conf')
138
def locations_config_path():
139
"""Return per-user configuration ini file filename."""
140
return osutils.pathjoin(config_dir(), 'locations.conf')
143
def authentication_config_path():
144
"""Return per-user authentication ini file filename."""
145
return osutils.pathjoin(config_dir(), 'authentication.conf')
148
def user_ignore_config_path():
149
"""Return per-user authentication ini file filename."""
150
return osutils.pathjoin(config_dir(), 'ignore')
154
"""Return the directory name to store crash files.
156
This doesn't implicitly create it.
158
On Windows it's in the config directory; elsewhere it's /var/crash
159
which may be monitored by apport. It can be overridden by
162
if sys.platform == 'win32':
163
return osutils.pathjoin(config_dir(), 'Crash')
165
# XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
167
return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
171
"""Return the cache directory to use."""
172
base = osutils.path_from_environ('BRZ_HOME')
173
if sys.platform in "win32":
175
base = win32utils.get_local_appdata_location()
177
base = win32utils.get_home_location()
179
base = osutils.path_from_environ('XDG_CACHE_HOME')
181
base = osutils.pathjoin(osutils._get_home_dir(), ".cache")
183
cache_dir = osutils.pathjoin(base, "breezy")
185
# GZ 2019-06-15: Move responsibility for ensuring dir exists elsewhere?
186
if not os.path.exists(cache_dir):
187
os.makedirs(cache_dir)
192
def _get_default_mail_domain(mailname_file='/etc/mailname'):
193
"""If possible, return the assumed default email domain.
195
:returns: string mail domain, or None.
197
if sys.platform == 'win32':
198
# No implementation yet; patches welcome
201
f = open(mailname_file)
202
except (IOError, OSError):
205
domain = f.readline().strip()
212
v = os.environ.get('BRZ_EMAIL')
215
v = v.decode(osutils.get_user_encoding())
217
v = os.environ.get('EMAIL')
220
v = v.decode(osutils.get_user_encoding())
222
name, email = _auto_user_id()
224
return u'%s <%s>' % (name, email)
227
raise errors.NoWhoami()
231
"""Calculate automatic user identification.
233
:returns: (realname, email), either of which may be None if they can't be
236
Only used when none is set in the environment or the id file.
238
This only returns an email address if we can be fairly sure the
239
address is reasonable, ie if /etc/mailname is set on unix.
241
This doesn't use the FQDN as the default domain because that may be
242
slow, and it doesn't use the hostname alone because that's not normally
243
a reasonable address.
245
if sys.platform == 'win32':
246
# No implementation to reliably determine Windows default mail
247
# address; please add one.
250
default_mail_domain = _get_default_mail_domain()
251
if not default_mail_domain:
257
w = pwd.getpwuid(uid)
259
trace.mutter('no passwd entry for uid %d?' % uid)
262
# we try utf-8 first, because on many variants (like Linux),
263
# /etc/passwd "should" be in utf-8, and because it's unlikely to give
264
# false positives. (many users will have their user encoding set to
265
# latin-1, which cannot raise UnicodeError.)
267
if isinstance(gecos, bytes):
269
gecos = gecos.decode('utf-8')
273
encoding = osutils.get_user_encoding()
274
gecos = gecos.decode(encoding)
276
trace.mutter("cannot decode passwd entry %s" % w)
280
if isinstance(username, bytes):
282
username = username.decode(encoding)
284
trace.mutter("cannot decode passwd entry %s" % w)
287
comma = gecos.find(',')
291
realname = gecos[:comma]
293
return realname, (username + '@' + default_mail_domain)