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."""
23
from .lazy_import import lazy_import
24
lazy_import(globals(), """
36
def ensure_config_dir_exists(path=None):
37
"""Make sure a configuration directory exists.
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.
45
if not os.path.isdir(path):
46
parent_dir = os.path.dirname(path)
47
if not os.path.isdir(parent_dir):
49
'creating config parent directory: %r', parent_dir)
51
osutils.copy_ownership_from_path(parent_dir)
52
trace.mutter('creating config directory: %r', path)
54
osutils.copy_ownership_from_path(path)
57
def bazaar_config_dir():
58
"""Return per-user configuration directory as unicode string
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
64
TODO: Global option --config-dir to override this.
66
base = os.environ.get('BZR_HOME')
67
if sys.platform == 'win32':
69
base = win32utils.get_appdata_location()
71
base = win32utils.get_home_location()
72
return osutils.pathjoin(base, 'bazaar', '2.0')
74
xdg_dir = os.environ.get('XDG_CONFIG_HOME')
76
xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
77
xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
78
if osutils.isdir(xdg_dir):
80
"Using configuration in XDG directory %s." % xdg_dir)
82
base = osutils._get_home_dir()
83
return osutils.pathjoin(base, ".bazaar")
87
"""Return per-user configuration directory as unicode string
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.
93
# TODO: Global option --config-dir to override this.
94
base = os.environ.get('BRZ_HOME')
95
if sys.platform == 'win32':
97
base = win32utils.get_appdata_location()
99
base = win32utils.get_home_location()
101
base = os.environ.get('XDG_CONFIG_HOME')
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):
111
"Using Bazaar configuration directory (%s)", bazaar_dir)
112
return (bazaar_dir, 'bazaar')
113
return (breezy_dir, 'breezy')
117
"""Return per-user configuration directory as unicode string
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.
123
return _config_dir()[0]
127
"""Return per-user configuration ini file filename."""
128
path, kind = _config_dir()
130
return osutils.pathjoin(path, 'bazaar.conf')
132
return osutils.pathjoin(path, 'breezy.conf')
135
def locations_config_path():
136
"""Return per-user configuration ini file filename."""
137
return osutils.pathjoin(config_dir(), 'locations.conf')
140
def authentication_config_path():
141
"""Return per-user authentication ini file filename."""
142
return osutils.pathjoin(config_dir(), 'authentication.conf')
145
def user_ignore_config_path():
146
"""Return per-user authentication ini file filename."""
147
return osutils.pathjoin(config_dir(), 'ignore')
151
"""Return the directory name to store crash files.
153
This doesn't implicitly create it.
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
159
if sys.platform == 'win32':
160
return osutils.pathjoin(config_dir(), 'Crash')
162
# XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
164
return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
168
"""Return the cache directory to use."""
169
base = os.environ.get('BRZ_HOME')
170
if sys.platform in "win32":
172
base = win32utils.get_local_appdata_location()
174
base = win32utils.get_home_location()
176
base = os.environ.get('XDG_CACHE_HOME')
178
base = osutils.pathjoin(osutils._get_home_dir(), ".cache")
180
cache_dir = osutils.pathjoin(base, "breezy")
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)
189
def _get_default_mail_domain(mailname_file='/etc/mailname'):
190
"""If possible, return the assumed default email domain.
192
:returns: string mail domain, or None.
194
if sys.platform == 'win32':
195
# No implementation yet; patches welcome
198
f = open(mailname_file)
199
except (IOError, OSError):
202
domain = f.readline().strip()
209
v = os.environ.get('BRZ_EMAIL')
212
v = os.environ.get('EMAIL')
215
name, email = _auto_user_id()
217
return u'%s <%s>' % (name, email)
220
raise errors.NoWhoami()
224
"""Calculate automatic user identification.
226
:returns: (realname, email), either of which may be None if they can't be
229
Only used when none is set in the environment or the id file.
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.
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.
238
if sys.platform == 'win32':
239
# No implementation to reliably determine Windows default mail
240
# address; please add one.
243
default_mail_domain = _get_default_mail_domain()
244
if not default_mail_domain:
250
w = pwd.getpwuid(uid)
252
trace.mutter('no passwd entry for uid %d?' % uid)
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.)
260
if isinstance(gecos, bytes):
262
gecos = gecos.decode('utf-8')
266
encoding = osutils.get_user_encoding()
267
gecos = gecos.decode(encoding)
269
trace.mutter("cannot decode passwd entry %s" % w)
273
if isinstance(username, bytes):
275
username = username.decode(encoding)
277
trace.mutter("cannot decode passwd entry %s" % w)
280
comma = gecos.find(',')
284
realname = gecos[:comma]
286
return realname, (username + '@' + default_mail_domain)