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
if sys.platform in "win32":
173
base = win32utils.get_local_appdata_location()
175
base = win32utils.get_home_location()
177
base = osutils.path_from_environ('XDG_CACHE_HOME')
179
base = osutils.pathjoin(osutils._get_home_dir(), ".cache")
181
cache_dir = osutils.pathjoin(base, "breezy")
183
# GZ 2019-06-15: Move responsibility for ensuring dir exists elsewhere?
184
if not os.path.exists(cache_dir):
185
os.makedirs(cache_dir)
190
def _get_default_mail_domain(mailname_file='/etc/mailname'):
191
"""If possible, return the assumed default email domain.
193
:returns: string mail domain, or None.
195
if sys.platform == 'win32':
196
# No implementation yet; patches welcome
199
f = open(mailname_file)
200
except (IOError, OSError):
203
domain = f.readline().strip()
210
v = os.environ.get('BRZ_EMAIL')
213
v = v.decode(osutils.get_user_encoding())
215
v = os.environ.get('EMAIL')
218
v = v.decode(osutils.get_user_encoding())
220
name, email = _auto_user_id()
222
return u'%s <%s>' % (name, email)
225
raise errors.NoWhoami()
229
"""Calculate automatic user identification.
231
:returns: (realname, email), either of which may be None if they can't be
234
Only used when none is set in the environment or the id file.
236
This only returns an email address if we can be fairly sure the
237
address is reasonable, ie if /etc/mailname is set on unix.
239
This doesn't use the FQDN as the default domain because that may be
240
slow, and it doesn't use the hostname alone because that's not normally
241
a reasonable address.
243
if sys.platform == 'win32':
244
# No implementation to reliably determine Windows default mail
245
# address; please add one.
248
default_mail_domain = _get_default_mail_domain()
249
if not default_mail_domain:
255
w = pwd.getpwuid(uid)
257
trace.mutter('no passwd entry for uid %d?' % uid)
260
# we try utf-8 first, because on many variants (like Linux),
261
# /etc/passwd "should" be in utf-8, and because it's unlikely to give
262
# false positives. (many users will have their user encoding set to
263
# latin-1, which cannot raise UnicodeError.)
265
if isinstance(gecos, bytes):
267
gecos = gecos.decode('utf-8')
271
encoding = osutils.get_user_encoding()
272
gecos = gecos.decode(encoding)
274
trace.mutter("cannot decode passwd entry %s" % w)
278
if isinstance(username, bytes):
280
username = username.decode(encoding)
282
trace.mutter("cannot decode passwd entry %s" % w)
285
comma = gecos.find(',')
289
realname = gecos[:comma]
291
return realname, (username + '@' + default_mail_domain)