1
# Copyright (C) 2005, 2007 Canonical Ltd
2
# Authors: Robert Collins <robert.collins@canonical.com>
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
"""Configuration that affects the behaviour of Bazaar.
21
Currently this configuration resides in ~/.bazaar/bazaar.conf
22
and ~/.bazaar/locations.conf, which is written to by bzr.
24
In bazaar.conf the following options may be set:
26
editor=name-of-program
27
email=Your Name <your@email.address>
28
check_signatures=require|ignore|check-available(default)
29
create_signatures=always|never|when-required(default)
30
gpg_signing_command=name-of-program
31
log_format=name-of-format
33
in locations.conf, you specify the url of a branch and options for it.
34
Wildcards may be used - * and ? as normal in shell completion. Options
35
set in both bazaar.conf and locations.conf are overridden by the locations.conf
37
[/home/robertc/source]
38
recurse=False|True(default)
40
check_signatures= as above
41
create_signatures= as above.
43
explanation of options
44
----------------------
45
editor - this option sets the pop up editor to use during commits.
46
email - this option sets the user id bzr will use when committing.
47
check_signatures - this option controls whether bzr will require good gpg
48
signatures, ignore them, or check them if they are
50
create_signatures - this option controls whether bzr will always create
51
gpg signatures, never create them, or create them if the
52
branch is configured to require them.
53
log_format - this option sets the default log format. Possible values are
54
long, short, line, or a plugin can register new formats.
56
In bazaar.conf you can also define aliases in the ALIASES sections, example
59
lastlog=log --line -r-10..-1
60
ll=log --line -r-10..-1
68
from bzrlib.lazy_import import lazy_import
69
lazy_import(globals(), """
71
from fnmatch import fnmatch
73
from StringIO import StringIO
85
import bzrlib.util.configobj.configobj as configobj
88
from bzrlib.trace import mutter, warning
103
POLICY_APPENDPATH = 2
107
POLICY_NORECURSE: 'norecurse',
108
POLICY_APPENDPATH: 'appendpath',
113
'norecurse': POLICY_NORECURSE,
114
'appendpath': POLICY_APPENDPATH,
118
STORE_LOCATION = POLICY_NONE
119
STORE_LOCATION_NORECURSE = POLICY_NORECURSE
120
STORE_LOCATION_APPENDPATH = POLICY_APPENDPATH
125
class ConfigObj(configobj.ConfigObj):
127
def get_bool(self, section, key):
128
return self[section].as_bool(key)
130
def get_value(self, section, name):
131
# Try [] for the old DEFAULT section.
132
if section == "DEFAULT":
137
return self[section][name]
140
class Config(object):
141
"""A configuration policy - what username, editor, gpg needs etc."""
143
def get_editor(self):
144
"""Get the users pop up editor."""
145
raise NotImplementedError
147
def get_mail_client(self):
148
"""Get a mail client to use"""
149
selected_client = self.get_user_option('mail_client')
151
mail_client_class = {
152
None: mail_client.DefaultMail,
154
'evolution': mail_client.Evolution,
155
'kmail': mail_client.KMail,
156
'mutt': mail_client.Mutt,
157
'thunderbird': mail_client.Thunderbird,
159
'default': mail_client.DefaultMail,
160
'editor': mail_client.Editor,
161
'mapi': mail_client.MAPIClient,
162
'xdg-email': mail_client.XDGEmail,
165
raise errors.UnknownMailClient(selected_client)
166
return mail_client_class(self)
168
def _get_signature_checking(self):
169
"""Template method to override signature checking policy."""
171
def _get_signing_policy(self):
172
"""Template method to override signature creation policy."""
174
def _get_user_option(self, option_name):
175
"""Template method to provide a user option."""
178
def get_user_option(self, option_name):
179
"""Get a generic option - no special process, no default."""
180
return self._get_user_option(option_name)
182
def gpg_signing_command(self):
183
"""What program should be used to sign signatures?"""
184
result = self._gpg_signing_command()
189
def _gpg_signing_command(self):
190
"""See gpg_signing_command()."""
193
def log_format(self):
194
"""What log format should be used"""
195
result = self._log_format()
200
def _log_format(self):
201
"""See log_format()."""
205
super(Config, self).__init__()
207
def post_commit(self):
208
"""An ordered list of python functions to call.
210
Each function takes branch, rev_id as parameters.
212
return self._post_commit()
214
def _post_commit(self):
215
"""See Config.post_commit."""
218
def user_email(self):
219
"""Return just the email component of a username."""
220
return extract_email_address(self.username())
223
"""Return email-style username.
225
Something similar to 'Martin Pool <mbp@sourcefrog.net>'
227
$BZR_EMAIL can be set to override this (as well as the
228
deprecated $BZREMAIL), then
229
the concrete policy type is checked, and finally
231
If none is found, a reasonable default is (hopefully)
234
TODO: Check it's reasonably well-formed.
236
v = os.environ.get('BZR_EMAIL')
238
return v.decode(bzrlib.user_encoding)
239
v = os.environ.get('BZREMAIL')
241
warning('BZREMAIL is deprecated in favor of BZR_EMAIL. Please update your configuration.')
242
return v.decode(bzrlib.user_encoding)
244
v = self._get_user_id()
248
v = os.environ.get('EMAIL')
250
return v.decode(bzrlib.user_encoding)
252
name, email = _auto_user_id()
254
return '%s <%s>' % (name, email)
258
def signature_checking(self):
259
"""What is the current policy for signature checking?."""
260
policy = self._get_signature_checking()
261
if policy is not None:
263
return CHECK_IF_POSSIBLE
265
def signing_policy(self):
266
"""What is the current policy for signature checking?."""
267
policy = self._get_signing_policy()
268
if policy is not None:
270
return SIGN_WHEN_REQUIRED
272
def signature_needed(self):
273
"""Is a signature needed when committing ?."""
274
policy = self._get_signing_policy()
276
policy = self._get_signature_checking()
277
if policy is not None:
278
warning("Please use create_signatures, not check_signatures "
279
"to set signing policy.")
280
if policy == CHECK_ALWAYS:
282
elif policy == SIGN_ALWAYS:
286
def get_alias(self, value):
287
return self._get_alias(value)
289
def _get_alias(self, value):
292
def get_nickname(self):
293
return self._get_nickname()
295
def _get_nickname(self):
299
class IniBasedConfig(Config):
300
"""A configuration policy that draws from ini files."""
302
def _get_parser(self, file=None):
303
if self._parser is not None:
306
input = self._get_filename()
310
self._parser = ConfigObj(input, encoding='utf-8')
311
except configobj.ConfigObjError, e:
312
raise errors.ParseConfigError(e.errors, e.config.filename)
315
def _get_matching_sections(self):
316
"""Return an ordered list of (section_name, extra_path) pairs.
318
If the section contains inherited configuration, extra_path is
319
a string containing the additional path components.
321
section = self._get_section()
322
if section is not None:
323
return [(section, '')]
327
def _get_section(self):
328
"""Override this to define the section used by the config."""
331
def _get_option_policy(self, section, option_name):
332
"""Return the policy for the given (section, option_name) pair."""
335
def _get_signature_checking(self):
336
"""See Config._get_signature_checking."""
337
policy = self._get_user_option('check_signatures')
339
return self._string_to_signature_policy(policy)
341
def _get_signing_policy(self):
342
"""See Config._get_signing_policy"""
343
policy = self._get_user_option('create_signatures')
345
return self._string_to_signing_policy(policy)
347
def _get_user_id(self):
348
"""Get the user id from the 'email' key in the current section."""
349
return self._get_user_option('email')
351
def _get_user_option(self, option_name):
352
"""See Config._get_user_option."""
353
for (section, extra_path) in self._get_matching_sections():
355
value = self._get_parser().get_value(section, option_name)
358
policy = self._get_option_policy(section, option_name)
359
if policy == POLICY_NONE:
361
elif policy == POLICY_NORECURSE:
362
# norecurse items only apply to the exact path
367
elif policy == POLICY_APPENDPATH:
369
value = urlutils.join(value, extra_path)
372
raise AssertionError('Unexpected config policy %r' % policy)
376
def _gpg_signing_command(self):
377
"""See Config.gpg_signing_command."""
378
return self._get_user_option('gpg_signing_command')
380
def _log_format(self):
381
"""See Config.log_format."""
382
return self._get_user_option('log_format')
384
def __init__(self, get_filename):
385
super(IniBasedConfig, self).__init__()
386
self._get_filename = get_filename
389
def _post_commit(self):
390
"""See Config.post_commit."""
391
return self._get_user_option('post_commit')
393
def _string_to_signature_policy(self, signature_string):
394
"""Convert a string to a signing policy."""
395
if signature_string.lower() == 'check-available':
396
return CHECK_IF_POSSIBLE
397
if signature_string.lower() == 'ignore':
399
if signature_string.lower() == 'require':
401
raise errors.BzrError("Invalid signatures policy '%s'"
404
def _string_to_signing_policy(self, signature_string):
405
"""Convert a string to a signing policy."""
406
if signature_string.lower() == 'when-required':
407
return SIGN_WHEN_REQUIRED
408
if signature_string.lower() == 'never':
410
if signature_string.lower() == 'always':
412
raise errors.BzrError("Invalid signing policy '%s'"
415
def _get_alias(self, value):
417
return self._get_parser().get_value("ALIASES",
422
def _get_nickname(self):
423
return self.get_user_option('nickname')
426
class GlobalConfig(IniBasedConfig):
427
"""The configuration that should be used for a specific location."""
429
def get_editor(self):
430
return self._get_user_option('editor')
433
super(GlobalConfig, self).__init__(config_filename)
435
def set_user_option(self, option, value):
436
"""Save option and its value in the configuration."""
437
# FIXME: RBC 20051029 This should refresh the parser and also take a
438
# file lock on bazaar.conf.
439
conf_dir = os.path.dirname(self._get_filename())
440
ensure_config_dir_exists(conf_dir)
441
if 'DEFAULT' not in self._get_parser():
442
self._get_parser()['DEFAULT'] = {}
443
self._get_parser()['DEFAULT'][option] = value
444
f = open(self._get_filename(), 'wb')
445
self._get_parser().write(f)
449
class LocationConfig(IniBasedConfig):
450
"""A configuration object that gives the policy for a location."""
452
def __init__(self, location):
453
name_generator = locations_config_filename
454
if (not os.path.exists(name_generator()) and
455
os.path.exists(branches_config_filename())):
456
if sys.platform == 'win32':
457
warning('Please rename %s to %s'
458
% (branches_config_filename(),
459
locations_config_filename()))
461
warning('Please rename ~/.bazaar/branches.conf'
462
' to ~/.bazaar/locations.conf')
463
name_generator = branches_config_filename
464
super(LocationConfig, self).__init__(name_generator)
465
# local file locations are looked up by local path, rather than
466
# by file url. This is because the config file is a user
467
# file, and we would rather not expose the user to file urls.
468
if location.startswith('file://'):
469
location = urlutils.local_path_from_url(location)
470
self.location = location
472
def _get_matching_sections(self):
473
"""Return an ordered list of section names matching this location."""
474
sections = self._get_parser()
475
location_names = self.location.split('/')
476
if self.location.endswith('/'):
477
del location_names[-1]
479
for section in sections:
480
# location is a local path if possible, so we need
481
# to convert 'file://' urls to local paths if necessary.
482
# This also avoids having file:///path be a more exact
483
# match than '/path'.
484
if section.startswith('file://'):
485
section_path = urlutils.local_path_from_url(section)
487
section_path = section
488
section_names = section_path.split('/')
489
if section.endswith('/'):
490
del section_names[-1]
491
names = zip(location_names, section_names)
494
if not fnmatch(name[0], name[1]):
499
# so, for the common prefix they matched.
500
# if section is longer, no match.
501
if len(section_names) > len(location_names):
503
matches.append((len(section_names), section,
504
'/'.join(location_names[len(section_names):])))
505
matches.sort(reverse=True)
507
for (length, section, extra_path) in matches:
508
sections.append((section, extra_path))
509
# should we stop looking for parent configs here?
511
if self._get_parser()[section].as_bool('ignore_parents'):
517
def _get_option_policy(self, section, option_name):
518
"""Return the policy for the given (section, option_name) pair."""
519
# check for the old 'recurse=False' flag
521
recurse = self._get_parser()[section].as_bool('recurse')
525
return POLICY_NORECURSE
527
policy_key = option_name + ':policy'
529
policy_name = self._get_parser()[section][policy_key]
533
return _policy_value[policy_name]
535
def _set_option_policy(self, section, option_name, option_policy):
536
"""Set the policy for the given option name in the given section."""
537
# The old recurse=False option affects all options in the
538
# section. To handle multiple policies in the section, we
539
# need to convert it to a policy_norecurse key.
541
recurse = self._get_parser()[section].as_bool('recurse')
545
symbol_versioning.warn(
546
'The recurse option is deprecated as of 0.14. '
547
'The section "%s" has been converted to use policies.'
550
del self._get_parser()[section]['recurse']
552
for key in self._get_parser()[section].keys():
553
if not key.endswith(':policy'):
554
self._get_parser()[section][key +
555
':policy'] = 'norecurse'
557
policy_key = option_name + ':policy'
558
policy_name = _policy_name[option_policy]
559
if policy_name is not None:
560
self._get_parser()[section][policy_key] = policy_name
562
if policy_key in self._get_parser()[section]:
563
del self._get_parser()[section][policy_key]
565
def set_user_option(self, option, value, store=STORE_LOCATION):
566
"""Save option and its value in the configuration."""
567
assert store in [STORE_LOCATION,
568
STORE_LOCATION_NORECURSE,
569
STORE_LOCATION_APPENDPATH], 'bad storage policy'
570
# FIXME: RBC 20051029 This should refresh the parser and also take a
571
# file lock on locations.conf.
572
conf_dir = os.path.dirname(self._get_filename())
573
ensure_config_dir_exists(conf_dir)
574
location = self.location
575
if location.endswith('/'):
576
location = location[:-1]
577
if (not location in self._get_parser() and
578
not location + '/' in self._get_parser()):
579
self._get_parser()[location]={}
580
elif location + '/' in self._get_parser():
581
location = location + '/'
582
self._get_parser()[location][option]=value
583
# the allowed values of store match the config policies
584
self._set_option_policy(location, option, store)
585
self._get_parser().write(file(self._get_filename(), 'wb'))
588
class BranchConfig(Config):
589
"""A configuration object giving the policy for a branch."""
591
def _get_branch_data_config(self):
592
if self._branch_data_config is None:
593
self._branch_data_config = TreeConfig(self.branch)
594
return self._branch_data_config
596
def _get_location_config(self):
597
if self._location_config is None:
598
self._location_config = LocationConfig(self.branch.base)
599
return self._location_config
601
def _get_global_config(self):
602
if self._global_config is None:
603
self._global_config = GlobalConfig()
604
return self._global_config
606
def _get_best_value(self, option_name):
607
"""This returns a user option from local, tree or global config.
609
They are tried in that order. Use get_safe_value if trusted values
612
for source in self.option_sources:
613
value = getattr(source(), option_name)()
614
if value is not None:
618
def _get_safe_value(self, option_name):
619
"""This variant of get_best_value never returns untrusted values.
621
It does not return values from the branch data, because the branch may
622
not be controlled by the user.
624
We may wish to allow locations.conf to control whether branches are
625
trusted in the future.
627
for source in (self._get_location_config, self._get_global_config):
628
value = getattr(source(), option_name)()
629
if value is not None:
633
def _get_user_id(self):
634
"""Return the full user id for the branch.
636
e.g. "John Hacker <jhacker@foo.org>"
637
This is looked up in the email controlfile for the branch.
640
return (self.branch.control_files.get_utf8("email")
642
.decode(bzrlib.user_encoding)
644
except errors.NoSuchFile, e:
647
return self._get_best_value('_get_user_id')
649
def _get_signature_checking(self):
650
"""See Config._get_signature_checking."""
651
return self._get_best_value('_get_signature_checking')
653
def _get_signing_policy(self):
654
"""See Config._get_signing_policy."""
655
return self._get_best_value('_get_signing_policy')
657
def _get_user_option(self, option_name):
658
"""See Config._get_user_option."""
659
for source in self.option_sources:
660
value = source()._get_user_option(option_name)
661
if value is not None:
665
def set_user_option(self, name, value, store=STORE_BRANCH,
667
if store == STORE_BRANCH:
668
self._get_branch_data_config().set_option(value, name)
669
elif store == STORE_GLOBAL:
670
self._get_global_config().set_user_option(name, value)
672
self._get_location_config().set_user_option(name, value, store)
675
if store in (STORE_GLOBAL, STORE_BRANCH):
676
mask_value = self._get_location_config().get_user_option(name)
677
if mask_value is not None:
678
trace.warning('Value "%s" is masked by "%s" from'
679
' locations.conf', value, mask_value)
681
if store == STORE_GLOBAL:
682
branch_config = self._get_branch_data_config()
683
mask_value = branch_config.get_user_option(name)
684
if mask_value is not None:
685
trace.warning('Value "%s" is masked by "%s" from'
686
' branch.conf', value, mask_value)
689
def _gpg_signing_command(self):
690
"""See Config.gpg_signing_command."""
691
return self._get_safe_value('_gpg_signing_command')
693
def __init__(self, branch):
694
super(BranchConfig, self).__init__()
695
self._location_config = None
696
self._branch_data_config = None
697
self._global_config = None
699
self.option_sources = (self._get_location_config,
700
self._get_branch_data_config,
701
self._get_global_config)
703
def _post_commit(self):
704
"""See Config.post_commit."""
705
return self._get_safe_value('_post_commit')
707
def _get_nickname(self):
708
value = self._get_explicit_nickname()
709
if value is not None:
711
return urlutils.unescape(self.branch.base.split('/')[-2])
713
def has_explicit_nickname(self):
714
"""Return true if a nickname has been explicitly assigned."""
715
return self._get_explicit_nickname() is not None
717
def _get_explicit_nickname(self):
718
return self._get_best_value('_get_nickname')
720
def _log_format(self):
721
"""See Config.log_format."""
722
return self._get_best_value('_log_format')
725
def ensure_config_dir_exists(path=None):
726
"""Make sure a configuration directory exists.
727
This makes sure that the directory exists.
728
On windows, since configuration directories are 2 levels deep,
729
it makes sure both the directory and the parent directory exists.
733
if not os.path.isdir(path):
734
if sys.platform == 'win32':
735
parent_dir = os.path.dirname(path)
736
if not os.path.isdir(parent_dir):
737
mutter('creating config parent directory: %r', parent_dir)
739
mutter('creating config directory: %r', path)
744
"""Return per-user configuration directory.
746
By default this is ~/.bazaar/
748
TODO: Global option --config-dir to override this.
750
base = os.environ.get('BZR_HOME', None)
751
if sys.platform == 'win32':
753
base = win32utils.get_appdata_location_unicode()
755
base = os.environ.get('HOME', None)
757
raise errors.BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
758
return osutils.pathjoin(base, 'bazaar', '2.0')
760
# cygwin, linux, and darwin all have a $HOME directory
762
base = os.path.expanduser("~")
763
return osutils.pathjoin(base, ".bazaar")
766
def config_filename():
767
"""Return per-user configuration ini file filename."""
768
return osutils.pathjoin(config_dir(), 'bazaar.conf')
771
def branches_config_filename():
772
"""Return per-user configuration ini file filename."""
773
return osutils.pathjoin(config_dir(), 'branches.conf')
776
def locations_config_filename():
777
"""Return per-user configuration ini file filename."""
778
return osutils.pathjoin(config_dir(), 'locations.conf')
781
def user_ignore_config_filename():
782
"""Return the user default ignore filename"""
783
return osutils.pathjoin(config_dir(), 'ignore')
787
"""Calculate automatic user identification.
789
Returns (realname, email).
791
Only used when none is set in the environment or the id file.
793
This previously used the FQDN as the default domain, but that can
794
be very slow on machines where DNS is broken. So now we simply
799
if sys.platform == 'win32':
800
name = win32utils.get_user_name_unicode()
802
raise errors.BzrError("Cannot autodetect user name.\n"
803
"Please, set your name with command like:\n"
804
'bzr whoami "Your Name <name@domain.com>"')
805
host = win32utils.get_host_name_unicode()
807
host = socket.gethostname()
808
return name, (name + '@' + host)
813
w = pwd.getpwuid(uid)
815
# we try utf-8 first, because on many variants (like Linux),
816
# /etc/passwd "should" be in utf-8, and because it's unlikely to give
817
# false positives. (many users will have their user encoding set to
818
# latin-1, which cannot raise UnicodeError.)
820
gecos = w.pw_gecos.decode('utf-8')
824
gecos = w.pw_gecos.decode(bzrlib.user_encoding)
825
encoding = bzrlib.user_encoding
827
raise errors.BzrCommandError('Unable to determine your name. '
828
'Use "bzr whoami" to set it.')
830
username = w.pw_name.decode(encoding)
832
raise errors.BzrCommandError('Unable to determine your name. '
833
'Use "bzr whoami" to set it.')
835
comma = gecos.find(',')
839
realname = gecos[:comma]
846
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
847
except UnicodeDecodeError:
848
raise errors.BzrError("Can't decode username as %s." % \
849
bzrlib.user_encoding)
851
return realname, (username + '@' + socket.gethostname())
854
def extract_email_address(e):
855
"""Return just the address part of an email string.
857
That is just the user@domain part, nothing else.
858
This part is required to contain only ascii characters.
859
If it can't be extracted, raises an error.
861
>>> extract_email_address('Jane Tester <jane@test.com>')
864
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
866
raise errors.NoEmailInUsername(e)
870
class TreeConfig(IniBasedConfig):
871
"""Branch configuration data associated with its contents, not location"""
872
def __init__(self, branch):
875
def _get_parser(self, file=None):
877
return IniBasedConfig._get_parser(file)
878
return self._get_config()
880
def _get_config(self):
882
obj = ConfigObj(self.branch.control_files.get('branch.conf'),
884
except errors.NoSuchFile:
885
obj = ConfigObj(encoding='utf=8')
888
def get_option(self, name, section=None, default=None):
889
self.branch.lock_read()
891
obj = self._get_config()
893
if section is not None:
902
def set_option(self, value, name, section=None):
903
"""Set a per-branch configuration option"""
904
self.branch.lock_write()
906
cfg_obj = self._get_config()
911
obj = cfg_obj[section]
913
cfg_obj[section] = {}
914
obj = cfg_obj[section]
916
out_file = StringIO()
917
cfg_obj.write(out_file)
919
self.branch.control_files.put('branch.conf', out_file)