1
# Copyright (C) 2005 by Canonical Ltd
2
# Authors: Robert Collins <robert.collins@canonical.com>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
"""Configuration that affects the behaviour of Bazaar.
20
Currently this configuration resides in ~/.bazaar/bazaar.conf
21
and ~/.bazaar/branches.conf, which is written to by bzr.
23
In bazaar.conf the following options may be set:
25
editor=name-of-program
26
email=Your Name <your@email.address>
27
check_signatures=require|ignore|check-available(default)
28
create_signatures=always|never|when-required(default)
29
gpg_signing_command=name-of-program
31
in branches.conf, you specify the url of a branch and options for it.
32
Wildcards may be used - * and ? as normal in shell completion. Options
33
set in both bazaar.conf and branches.conf are overriden by the branches.conf
35
[/home/robertc/source]
36
recurse=False|True(default)
38
check_signatures= as abive
39
create_signatures= as above.
41
explanation of options
42
----------------------
43
editor - this option sets the pop up editor to use during commits.
44
email - this option sets the user id bzr will use when committing.
45
check_signatures - this option controls whether bzr will require good gpg
46
signatures, ignore them, or check them if they are
48
create_signatures - this option controls whether bzr will always create
49
gpg signatures, never create them, or create them if the
50
branch is configured to require them.
51
NB: This option is planned, but not implemented yet.
54
from ConfigParser import ConfigParser
56
from fnmatch import fnmatch
61
import bzrlib.errors as errors
70
"""A configuration policy - what username, editor, gpg needs etc."""
73
"""Get the users pop up editor."""
74
raise NotImplementedError
76
def _get_signature_checking(self):
77
"""Template method to override signature checking policy."""
79
def gpg_signing_command(self):
80
"""What program should be used to sign signatures?"""
81
result = self._gpg_signing_command()
86
def _gpg_signing_command(self):
87
"""See gpg_signing_command()."""
91
super(Config, self).__init__()
94
"""Return just the email component of a username."""
96
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
98
raise BzrError("%r doesn't seem to contain "
99
"a reasonable email address" % e)
103
"""Return email-style username.
105
Something similar to 'Martin Pool <mbp@sourcefrog.net>'
107
$BZREMAIL can be set to override this, then
108
the concrete policy type is checked, and finally
110
but if none is found, a reasonable default is (hopefully)
113
TODO: Check it's reasonably well-formed.
115
v = os.environ.get('BZREMAIL')
117
return v.decode(bzrlib.user_encoding)
119
v = self._get_user_id()
123
v = os.environ.get('EMAIL')
125
return v.decode(bzrlib.user_encoding)
127
name, email = _auto_user_id()
129
return '%s <%s>' % (name, email)
133
def signature_checking(self):
134
"""What is the current policy for signature checking?."""
135
policy = self._get_signature_checking()
136
if policy is not None:
138
return CHECK_IF_POSSIBLE
140
def signature_needed(self):
141
"""Is a signature needed when committing ?."""
142
policy = self._get_signature_checking()
143
if policy == CHECK_ALWAYS:
148
class IniBasedConfig(Config):
149
"""A configuration policy that draws from ini files."""
151
def _get_parser(self, file=None):
152
if self._parser is not None:
154
parser = ConfigParser()
158
parser.read([self._get_filename()])
159
self._parser = parser
162
def _get_section(self):
163
"""Override this to define the section used by the config."""
166
def _get_signature_checking(self):
167
"""See Config._get_signature_checking."""
168
section = self._get_section()
171
if self._get_parser().has_option(section, 'check_signatures'):
172
return self._string_to_signature_policy(
173
self._get_parser().get(section, 'check_signatures'))
175
def _get_user_id(self):
176
"""Get the user id from the 'email' key in the current section."""
177
section = self._get_section()
178
if section is not None:
179
if self._get_parser().has_option(section, 'email'):
180
return self._get_parser().get(section, 'email')
182
def _gpg_signing_command(self):
183
"""See Config.gpg_signing_command."""
184
section = self._get_section()
185
if section is not None:
186
if self._get_parser().has_option(section, 'gpg_signing_command'):
187
return self._get_parser().get(section, 'gpg_signing_command')
189
def __init__(self, get_filename):
190
super(IniBasedConfig, self).__init__()
191
self._get_filename = get_filename
194
def _string_to_signature_policy(self, signature_string):
195
"""Convert a string to a signing policy."""
196
if signature_string.lower() == 'check-available':
197
return CHECK_IF_POSSIBLE
198
if signature_string.lower() == 'ignore':
200
if signature_string.lower() == 'require':
202
raise errors.BzrError("Invalid signatures policy '%s'"
206
class GlobalConfig(IniBasedConfig):
207
"""The configuration that should be used for a specific location."""
209
def get_editor(self):
210
if self._get_parser().has_option(self._get_section(), 'editor'):
211
return self._get_parser().get(self._get_section(), 'editor')
214
super(GlobalConfig, self).__init__(config_filename)
217
class LocationConfig(IniBasedConfig):
218
"""A configuration object that gives the policy for a location."""
220
def __init__(self, location):
221
super(LocationConfig, self).__init__(branches_config_filename)
222
self._global_config = None
223
self.location = location
225
def _get_global_config(self):
226
if self._global_config is None:
227
self._global_config = GlobalConfig()
228
return self._global_config
230
def _get_section(self):
231
"""Get the section we should look in for config items.
233
Returns None if none exists.
234
TODO: perhaps return a NullSection that thunks through to the
237
sections = self._get_parser().sections()
238
location_names = self.location.split('/')
239
if self.location.endswith('/'):
240
del location_names[-1]
242
for section in sections:
243
section_names = section.split('/')
244
if section.endswith('/'):
245
del section_names[-1]
246
names = zip(location_names, section_names)
249
if not fnmatch(name[0], name[1]):
254
# so, for the common prefix they matched.
255
# if section is longer, no match.
256
if len(section_names) > len(location_names):
258
# if path is longer, and recurse is not true, no match
259
if len(section_names) < len(location_names):
260
if (self._get_parser().has_option(section, 'recurse')
261
and not self._get_parser().getboolean(section, 'recurse')):
263
matches.append((len(section_names), section))
266
matches.sort(reverse=True)
269
def _gpg_signing_command(self):
270
"""See Config.gpg_signing_command."""
271
command = super(LocationConfig, self)._gpg_signing_command()
272
if command is not None:
274
return self._get_global_config()._gpg_signing_command()
276
def _get_user_id(self):
277
user_id = super(LocationConfig, self)._get_user_id()
278
if user_id is not None:
280
return self._get_global_config()._get_user_id()
282
def _get_signature_checking(self):
283
"""See Config._get_signature_checking."""
284
check = super(LocationConfig, self)._get_signature_checking()
285
if check is not None:
287
return self._get_global_config()._get_signature_checking()
290
class BranchConfig(Config):
291
"""A configuration object giving the policy for a branch."""
293
def _get_location_config(self):
294
if self._location_config is None:
295
self._location_config = LocationConfig(self.branch.base)
296
return self._location_config
298
def _get_user_id(self):
299
"""Return the full user id for the branch.
301
e.g. "John Hacker <jhacker@foo.org>"
302
This is looked up in the email controlfile for the branch.
305
return (self.branch.controlfile("email", "r")
307
.decode(bzrlib.user_encoding)
309
except errors.NoSuchFile, e:
312
return self._get_location_config()._get_user_id()
314
def _get_signature_checking(self):
315
"""See Config._get_signature_checking."""
316
return self._get_location_config()._get_signature_checking()
318
def _gpg_signing_command(self):
319
"""See Config.gpg_signing_command."""
320
return self._get_location_config()._gpg_signing_command()
322
def __init__(self, branch):
323
super(BranchConfig, self).__init__()
324
self._location_config = None
329
"""Return per-user configuration directory.
331
By default this is ~/.bazaar/
333
TODO: Global option --config-dir to override this.
335
return os.path.join(os.path.expanduser("~"), ".bazaar")
338
def config_filename():
339
"""Return per-user configuration ini file filename."""
340
return os.path.join(config_dir(), 'bazaar.conf')
343
def branches_config_filename():
344
"""Return per-user configuration ini file filename."""
345
return os.path.join(config_dir(), 'branches.conf')
349
"""Calculate automatic user identification.
351
Returns (realname, email).
353
Only used when none is set in the environment or the id file.
355
This previously used the FQDN as the default domain, but that can
356
be very slow on machines where DNS is broken. So now we simply
361
# XXX: Any good way to get real user name on win32?
366
w = pwd.getpwuid(uid)
367
gecos = w.pw_gecos.decode(bzrlib.user_encoding)
368
username = w.pw_name.decode(bzrlib.user_encoding)
369
comma = gecos.find(',')
373
realname = gecos[:comma]
379
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
381
return realname, (username + '@' + socket.gethostname())
384
def extract_email_address(e):
385
"""Return just the address part of an email string.
387
That is just the user@domain part, nothing else.
388
This part is required to contain only ascii characters.
389
If it can't be extracted, raises an error.
391
>>> extract_email_address('Jane Tester <jane@test.com>')
394
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
396
raise BzrError("%r doesn't seem to contain "
397
"a reasonable email address" % e)