1
# Copyright (C) 2005, 2007, 2008 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 cStringIO import StringIO
87
from bzrlib.util.configobj import configobj
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
def ConfigObj(*args, **kwargs):
127
if _ConfigObj is None:
128
class ConfigObj(configobj.ConfigObj):
130
def get_bool(self, section, key):
131
return self[section].as_bool(key)
133
def get_value(self, section, name):
134
# Try [] for the old DEFAULT section.
135
if section == "DEFAULT":
140
return self[section][name]
141
_ConfigObj = ConfigObj
142
return _ConfigObj(*args, **kwargs)
145
class Config(object):
146
"""A configuration policy - what username, editor, gpg needs etc."""
148
def get_editor(self):
149
"""Get the users pop up editor."""
150
raise NotImplementedError
152
def get_mail_client(self):
153
"""Get a mail client to use"""
154
selected_client = self.get_user_option('mail_client')
155
_registry = mail_client.mail_client_registry
157
mail_client_class = _registry.get(selected_client)
159
raise errors.UnknownMailClient(selected_client)
160
return mail_client_class(self)
162
def _get_signature_checking(self):
163
"""Template method to override signature checking policy."""
165
def _get_signing_policy(self):
166
"""Template method to override signature creation policy."""
168
def _get_user_option(self, option_name):
169
"""Template method to provide a user option."""
172
def get_user_option(self, option_name):
173
"""Get a generic option - no special process, no default."""
174
return self._get_user_option(option_name)
176
def gpg_signing_command(self):
177
"""What program should be used to sign signatures?"""
178
result = self._gpg_signing_command()
183
def _gpg_signing_command(self):
184
"""See gpg_signing_command()."""
187
def log_format(self):
188
"""What log format should be used"""
189
result = self._log_format()
194
def _log_format(self):
195
"""See log_format()."""
199
super(Config, self).__init__()
201
def post_commit(self):
202
"""An ordered list of python functions to call.
204
Each function takes branch, rev_id as parameters.
206
return self._post_commit()
208
def _post_commit(self):
209
"""See Config.post_commit."""
212
def user_email(self):
213
"""Return just the email component of a username."""
214
return extract_email_address(self.username())
217
"""Return email-style username.
219
Something similar to 'Martin Pool <mbp@sourcefrog.net>'
221
$BZR_EMAIL can be set to override this (as well as the
222
deprecated $BZREMAIL), then
223
the concrete policy type is checked, and finally
225
If none is found, a reasonable default is (hopefully)
228
TODO: Check it's reasonably well-formed.
230
v = os.environ.get('BZR_EMAIL')
232
return v.decode(osutils.get_user_encoding())
234
v = self._get_user_id()
238
v = os.environ.get('EMAIL')
240
return v.decode(osutils.get_user_encoding())
242
name, email = _auto_user_id()
244
return '%s <%s>' % (name, email)
248
def signature_checking(self):
249
"""What is the current policy for signature checking?."""
250
policy = self._get_signature_checking()
251
if policy is not None:
253
return CHECK_IF_POSSIBLE
255
def signing_policy(self):
256
"""What is the current policy for signature checking?."""
257
policy = self._get_signing_policy()
258
if policy is not None:
260
return SIGN_WHEN_REQUIRED
262
def signature_needed(self):
263
"""Is a signature needed when committing ?."""
264
policy = self._get_signing_policy()
266
policy = self._get_signature_checking()
267
if policy is not None:
268
trace.warning("Please use create_signatures,"
269
" not check_signatures to set signing policy.")
270
if policy == CHECK_ALWAYS:
272
elif policy == SIGN_ALWAYS:
276
def get_alias(self, value):
277
return self._get_alias(value)
279
def _get_alias(self, value):
282
def get_nickname(self):
283
return self._get_nickname()
285
def _get_nickname(self):
288
def get_bzr_remote_path(self):
290
return os.environ['BZR_REMOTE_PATH']
292
path = self.get_user_option("bzr_remote_path")
298
class IniBasedConfig(Config):
299
"""A configuration policy that draws from ini files."""
301
def _get_parser(self, file=None):
302
if self._parser is not None:
305
input = self._get_filename()
309
self._parser = ConfigObj(input, encoding='utf-8')
310
except configobj.ConfigObjError, e:
311
raise errors.ParseConfigError(e.errors, e.config.filename)
314
def _get_matching_sections(self):
315
"""Return an ordered list of (section_name, extra_path) pairs.
317
If the section contains inherited configuration, extra_path is
318
a string containing the additional path components.
320
section = self._get_section()
321
if section is not None:
322
return [(section, '')]
326
def _get_section(self):
327
"""Override this to define the section used by the config."""
330
def _get_option_policy(self, section, option_name):
331
"""Return the policy for the given (section, option_name) pair."""
334
def _get_signature_checking(self):
335
"""See Config._get_signature_checking."""
336
policy = self._get_user_option('check_signatures')
338
return self._string_to_signature_policy(policy)
340
def _get_signing_policy(self):
341
"""See Config._get_signing_policy"""
342
policy = self._get_user_option('create_signatures')
344
return self._string_to_signing_policy(policy)
346
def _get_user_id(self):
347
"""Get the user id from the 'email' key in the current section."""
348
return self._get_user_option('email')
350
def _get_user_option(self, option_name):
351
"""See Config._get_user_option."""
352
for (section, extra_path) in self._get_matching_sections():
354
value = self._get_parser().get_value(section, option_name)
357
policy = self._get_option_policy(section, option_name)
358
if policy == POLICY_NONE:
360
elif policy == POLICY_NORECURSE:
361
# norecurse items only apply to the exact path
366
elif policy == POLICY_APPENDPATH:
368
value = urlutils.join(value, extra_path)
371
raise AssertionError('Unexpected config policy %r' % policy)
375
def _gpg_signing_command(self):
376
"""See Config.gpg_signing_command."""
377
return self._get_user_option('gpg_signing_command')
379
def _log_format(self):
380
"""See Config.log_format."""
381
return self._get_user_option('log_format')
383
def __init__(self, get_filename):
384
super(IniBasedConfig, self).__init__()
385
self._get_filename = get_filename
388
def _post_commit(self):
389
"""See Config.post_commit."""
390
return self._get_user_option('post_commit')
392
def _string_to_signature_policy(self, signature_string):
393
"""Convert a string to a signing policy."""
394
if signature_string.lower() == 'check-available':
395
return CHECK_IF_POSSIBLE
396
if signature_string.lower() == 'ignore':
398
if signature_string.lower() == 'require':
400
raise errors.BzrError("Invalid signatures policy '%s'"
403
def _string_to_signing_policy(self, signature_string):
404
"""Convert a string to a signing policy."""
405
if signature_string.lower() == 'when-required':
406
return SIGN_WHEN_REQUIRED
407
if signature_string.lower() == 'never':
409
if signature_string.lower() == 'always':
411
raise errors.BzrError("Invalid signing policy '%s'"
414
def _get_alias(self, value):
416
return self._get_parser().get_value("ALIASES",
421
def _get_nickname(self):
422
return self.get_user_option('nickname')
425
class GlobalConfig(IniBasedConfig):
426
"""The configuration that should be used for a specific location."""
428
def get_editor(self):
429
return self._get_user_option('editor')
432
super(GlobalConfig, self).__init__(config_filename)
434
def set_user_option(self, option, value):
435
"""Save option and its value in the configuration."""
436
self._set_option(option, value, 'DEFAULT')
438
def get_aliases(self):
439
"""Return the aliases section."""
440
if 'ALIASES' in self._get_parser():
441
return self._get_parser()['ALIASES']
445
def set_alias(self, alias_name, alias_command):
446
"""Save the alias in the configuration."""
447
self._set_option(alias_name, alias_command, 'ALIASES')
449
def unset_alias(self, alias_name):
450
"""Unset an existing alias."""
451
aliases = self._get_parser().get('ALIASES')
452
if not aliases or alias_name not in aliases:
453
raise errors.NoSuchAlias(alias_name)
454
del aliases[alias_name]
455
self._write_config_file()
457
def _set_option(self, option, value, section):
458
# FIXME: RBC 20051029 This should refresh the parser and also take a
459
# file lock on bazaar.conf.
460
conf_dir = os.path.dirname(self._get_filename())
461
ensure_config_dir_exists(conf_dir)
462
self._get_parser().setdefault(section, {})[option] = value
463
self._write_config_file()
465
def _write_config_file(self):
466
f = open(self._get_filename(), 'wb')
467
self._get_parser().write(f)
471
class LocationConfig(IniBasedConfig):
472
"""A configuration object that gives the policy for a location."""
474
def __init__(self, location):
475
name_generator = locations_config_filename
476
if (not os.path.exists(name_generator()) and
477
os.path.exists(branches_config_filename())):
478
if sys.platform == 'win32':
479
trace.warning('Please rename %s to %s'
480
% (branches_config_filename(),
481
locations_config_filename()))
483
trace.warning('Please rename ~/.bazaar/branches.conf'
484
' to ~/.bazaar/locations.conf')
485
name_generator = branches_config_filename
486
super(LocationConfig, self).__init__(name_generator)
487
# local file locations are looked up by local path, rather than
488
# by file url. This is because the config file is a user
489
# file, and we would rather not expose the user to file urls.
490
if location.startswith('file://'):
491
location = urlutils.local_path_from_url(location)
492
self.location = location
494
def _get_matching_sections(self):
495
"""Return an ordered list of section names matching this location."""
496
sections = self._get_parser()
497
location_names = self.location.split('/')
498
if self.location.endswith('/'):
499
del location_names[-1]
501
for section in sections:
502
# location is a local path if possible, so we need
503
# to convert 'file://' urls to local paths if necessary.
504
# This also avoids having file:///path be a more exact
505
# match than '/path'.
506
if section.startswith('file://'):
507
section_path = urlutils.local_path_from_url(section)
509
section_path = section
510
section_names = section_path.split('/')
511
if section.endswith('/'):
512
del section_names[-1]
513
names = zip(location_names, section_names)
516
if not fnmatch(name[0], name[1]):
521
# so, for the common prefix they matched.
522
# if section is longer, no match.
523
if len(section_names) > len(location_names):
525
matches.append((len(section_names), section,
526
'/'.join(location_names[len(section_names):])))
527
matches.sort(reverse=True)
529
for (length, section, extra_path) in matches:
530
sections.append((section, extra_path))
531
# should we stop looking for parent configs here?
533
if self._get_parser()[section].as_bool('ignore_parents'):
539
def _get_option_policy(self, section, option_name):
540
"""Return the policy for the given (section, option_name) pair."""
541
# check for the old 'recurse=False' flag
543
recurse = self._get_parser()[section].as_bool('recurse')
547
return POLICY_NORECURSE
549
policy_key = option_name + ':policy'
551
policy_name = self._get_parser()[section][policy_key]
555
return _policy_value[policy_name]
557
def _set_option_policy(self, section, option_name, option_policy):
558
"""Set the policy for the given option name in the given section."""
559
# The old recurse=False option affects all options in the
560
# section. To handle multiple policies in the section, we
561
# need to convert it to a policy_norecurse key.
563
recurse = self._get_parser()[section].as_bool('recurse')
567
symbol_versioning.warn(
568
'The recurse option is deprecated as of 0.14. '
569
'The section "%s" has been converted to use policies.'
572
del self._get_parser()[section]['recurse']
574
for key in self._get_parser()[section].keys():
575
if not key.endswith(':policy'):
576
self._get_parser()[section][key +
577
':policy'] = 'norecurse'
579
policy_key = option_name + ':policy'
580
policy_name = _policy_name[option_policy]
581
if policy_name is not None:
582
self._get_parser()[section][policy_key] = policy_name
584
if policy_key in self._get_parser()[section]:
585
del self._get_parser()[section][policy_key]
587
def set_user_option(self, option, value, store=STORE_LOCATION):
588
"""Save option and its value in the configuration."""
589
if store not in [STORE_LOCATION,
590
STORE_LOCATION_NORECURSE,
591
STORE_LOCATION_APPENDPATH]:
592
raise ValueError('bad storage policy %r for %r' %
594
# FIXME: RBC 20051029 This should refresh the parser and also take a
595
# file lock on locations.conf.
596
conf_dir = os.path.dirname(self._get_filename())
597
ensure_config_dir_exists(conf_dir)
598
location = self.location
599
if location.endswith('/'):
600
location = location[:-1]
601
if (not location in self._get_parser() and
602
not location + '/' in self._get_parser()):
603
self._get_parser()[location]={}
604
elif location + '/' in self._get_parser():
605
location = location + '/'
606
self._get_parser()[location][option]=value
607
# the allowed values of store match the config policies
608
self._set_option_policy(location, option, store)
609
self._get_parser().write(file(self._get_filename(), 'wb'))
612
class BranchConfig(Config):
613
"""A configuration object giving the policy for a branch."""
615
def _get_branch_data_config(self):
616
if self._branch_data_config is None:
617
self._branch_data_config = TreeConfig(self.branch)
618
return self._branch_data_config
620
def _get_location_config(self):
621
if self._location_config is None:
622
self._location_config = LocationConfig(self.branch.base)
623
return self._location_config
625
def _get_global_config(self):
626
if self._global_config is None:
627
self._global_config = GlobalConfig()
628
return self._global_config
630
def _get_best_value(self, option_name):
631
"""This returns a user option from local, tree or global config.
633
They are tried in that order. Use get_safe_value if trusted values
636
for source in self.option_sources:
637
value = getattr(source(), option_name)()
638
if value is not None:
642
def _get_safe_value(self, option_name):
643
"""This variant of get_best_value never returns untrusted values.
645
It does not return values from the branch data, because the branch may
646
not be controlled by the user.
648
We may wish to allow locations.conf to control whether branches are
649
trusted in the future.
651
for source in (self._get_location_config, self._get_global_config):
652
value = getattr(source(), option_name)()
653
if value is not None:
657
def _get_user_id(self):
658
"""Return the full user id for the branch.
660
e.g. "John Hacker <jhacker@example.com>"
661
This is looked up in the email controlfile for the branch.
664
return (self.branch._transport.get_bytes("email")
665
.decode(osutils.get_user_encoding())
667
except errors.NoSuchFile, e:
670
return self._get_best_value('_get_user_id')
672
def _get_signature_checking(self):
673
"""See Config._get_signature_checking."""
674
return self._get_best_value('_get_signature_checking')
676
def _get_signing_policy(self):
677
"""See Config._get_signing_policy."""
678
return self._get_best_value('_get_signing_policy')
680
def _get_user_option(self, option_name):
681
"""See Config._get_user_option."""
682
for source in self.option_sources:
683
value = source()._get_user_option(option_name)
684
if value is not None:
688
def set_user_option(self, name, value, store=STORE_BRANCH,
690
if store == STORE_BRANCH:
691
self._get_branch_data_config().set_option(value, name)
692
elif store == STORE_GLOBAL:
693
self._get_global_config().set_user_option(name, value)
695
self._get_location_config().set_user_option(name, value, store)
698
if store in (STORE_GLOBAL, STORE_BRANCH):
699
mask_value = self._get_location_config().get_user_option(name)
700
if mask_value is not None:
701
trace.warning('Value "%s" is masked by "%s" from'
702
' locations.conf', value, mask_value)
704
if store == STORE_GLOBAL:
705
branch_config = self._get_branch_data_config()
706
mask_value = branch_config.get_user_option(name)
707
if mask_value is not None:
708
trace.warning('Value "%s" is masked by "%s" from'
709
' branch.conf', value, mask_value)
712
def _gpg_signing_command(self):
713
"""See Config.gpg_signing_command."""
714
return self._get_safe_value('_gpg_signing_command')
716
def __init__(self, branch):
717
super(BranchConfig, self).__init__()
718
self._location_config = None
719
self._branch_data_config = None
720
self._global_config = None
722
self.option_sources = (self._get_location_config,
723
self._get_branch_data_config,
724
self._get_global_config)
726
def _post_commit(self):
727
"""See Config.post_commit."""
728
return self._get_safe_value('_post_commit')
730
def _get_nickname(self):
731
value = self._get_explicit_nickname()
732
if value is not None:
734
return urlutils.unescape(self.branch.base.split('/')[-2])
736
def has_explicit_nickname(self):
737
"""Return true if a nickname has been explicitly assigned."""
738
return self._get_explicit_nickname() is not None
740
def _get_explicit_nickname(self):
741
return self._get_best_value('_get_nickname')
743
def _log_format(self):
744
"""See Config.log_format."""
745
return self._get_best_value('_log_format')
748
def ensure_config_dir_exists(path=None):
749
"""Make sure a configuration directory exists.
750
This makes sure that the directory exists.
751
On windows, since configuration directories are 2 levels deep,
752
it makes sure both the directory and the parent directory exists.
756
if not os.path.isdir(path):
757
if sys.platform == 'win32':
758
parent_dir = os.path.dirname(path)
759
if not os.path.isdir(parent_dir):
760
trace.mutter('creating config parent directory: %r', parent_dir)
762
trace.mutter('creating config directory: %r', path)
767
"""Return per-user configuration directory.
769
By default this is ~/.bazaar/
771
TODO: Global option --config-dir to override this.
773
base = os.environ.get('BZR_HOME', None)
774
if sys.platform == 'win32':
776
base = win32utils.get_appdata_location_unicode()
778
base = os.environ.get('HOME', None)
780
raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
782
return osutils.pathjoin(base, 'bazaar', '2.0')
784
# cygwin, linux, and darwin all have a $HOME directory
786
base = os.path.expanduser("~")
787
return osutils.pathjoin(base, ".bazaar")
790
def config_filename():
791
"""Return per-user configuration ini file filename."""
792
return osutils.pathjoin(config_dir(), 'bazaar.conf')
795
def branches_config_filename():
796
"""Return per-user configuration ini file filename."""
797
return osutils.pathjoin(config_dir(), 'branches.conf')
800
def locations_config_filename():
801
"""Return per-user configuration ini file filename."""
802
return osutils.pathjoin(config_dir(), 'locations.conf')
805
def authentication_config_filename():
806
"""Return per-user authentication ini file filename."""
807
return osutils.pathjoin(config_dir(), 'authentication.conf')
810
def user_ignore_config_filename():
811
"""Return the user default ignore filename"""
812
return osutils.pathjoin(config_dir(), 'ignore')
816
"""Calculate automatic user identification.
818
Returns (realname, email).
820
Only used when none is set in the environment or the id file.
822
This previously used the FQDN as the default domain, but that can
823
be very slow on machines where DNS is broken. So now we simply
828
if sys.platform == 'win32':
829
name = win32utils.get_user_name_unicode()
831
raise errors.BzrError("Cannot autodetect user name.\n"
832
"Please, set your name with command like:\n"
833
'bzr whoami "Your Name <name@domain.com>"')
834
host = win32utils.get_host_name_unicode()
836
host = socket.gethostname()
837
return name, (name + '@' + host)
842
w = pwd.getpwuid(uid)
844
# we try utf-8 first, because on many variants (like Linux),
845
# /etc/passwd "should" be in utf-8, and because it's unlikely to give
846
# false positives. (many users will have their user encoding set to
847
# latin-1, which cannot raise UnicodeError.)
849
gecos = w.pw_gecos.decode('utf-8')
853
encoding = osutils.get_user_encoding()
854
gecos = w.pw_gecos.decode(encoding)
856
raise errors.BzrCommandError('Unable to determine your name. '
857
'Use "bzr whoami" to set it.')
859
username = w.pw_name.decode(encoding)
861
raise errors.BzrCommandError('Unable to determine your name. '
862
'Use "bzr whoami" to set it.')
864
comma = gecos.find(',')
868
realname = gecos[:comma]
875
user_encoding = osutils.get_user_encoding()
876
realname = username = getpass.getuser().decode(user_encoding)
877
except UnicodeDecodeError:
878
raise errors.BzrError("Can't decode username as %s." % \
881
return realname, (username + '@' + socket.gethostname())
884
def parse_username(username):
885
"""Parse e-mail username and return a (name, address) tuple."""
886
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
888
return (username, '')
890
return (match.group(1), match.group(2))
893
def extract_email_address(e):
894
"""Return just the address part of an email string.
896
That is just the user@domain part, nothing else.
897
This part is required to contain only ascii characters.
898
If it can't be extracted, raises an error.
900
>>> extract_email_address('Jane Tester <jane@test.com>')
903
name, email = parse_username(e)
905
raise errors.NoEmailInUsername(e)
909
class TreeConfig(IniBasedConfig):
910
"""Branch configuration data associated with its contents, not location"""
912
# XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
914
def __init__(self, branch):
915
# XXX: Really this should be asking the branch for its configuration
916
# data, rather than relying on a Transport, so that it can work
917
# more cleanly with a RemoteBranch that has no transport.
918
self._config = TransportConfig(branch._transport, 'branch.conf')
921
def _get_parser(self, file=None):
923
return IniBasedConfig._get_parser(file)
924
return self._config._get_configobj()
926
def get_option(self, name, section=None, default=None):
927
self.branch.lock_read()
929
return self._config.get_option(name, section, default)
934
def set_option(self, value, name, section=None):
935
"""Set a per-branch configuration option"""
936
self.branch.lock_write()
938
self._config.set_option(value, name, section)
943
class AuthenticationConfig(object):
944
"""The authentication configuration file based on a ini file.
946
Implements the authentication.conf file described in
947
doc/developers/authentication-ring.txt.
950
def __init__(self, _file=None):
951
self._config = None # The ConfigObj
953
self._filename = authentication_config_filename()
954
self._input = self._filename = authentication_config_filename()
956
# Tests can provide a string as _file
957
self._filename = None
960
def _get_config(self):
961
if self._config is not None:
964
# FIXME: Should we validate something here ? Includes: empty
965
# sections are useless, at least one of
966
# user/password/password_encoding should be defined, etc.
968
# Note: the encoding below declares that the file itself is utf-8
969
# encoded, but the values in the ConfigObj are always Unicode.
970
self._config = ConfigObj(self._input, encoding='utf-8')
971
except configobj.ConfigObjError, e:
972
raise errors.ParseConfigError(e.errors, e.config.filename)
976
"""Save the config file, only tests should use it for now."""
977
conf_dir = os.path.dirname(self._filename)
978
ensure_config_dir_exists(conf_dir)
979
self._get_config().write(file(self._filename, 'wb'))
981
def _set_option(self, section_name, option_name, value):
982
"""Set an authentication configuration option"""
983
conf = self._get_config()
984
section = conf.get(section_name)
987
section = conf[section]
988
section[option_name] = value
991
def get_credentials(self, scheme, host, port=None, user=None, path=None):
992
"""Returns the matching credentials from authentication.conf file.
994
:param scheme: protocol
996
:param host: the server address
998
:param port: the associated port (optional)
1000
:param user: login (optional)
1002
:param path: the absolute path on the server (optional)
1004
:return: A dict containing the matching credentials or None.
1006
- name: the section name of the credentials in the
1007
authentication.conf file,
1008
- user: can't de different from the provided user if any,
1009
- password: the decoded password, could be None if the credential
1010
defines only the user
1011
- verify_certificates: https specific, True if the server
1012
certificate should be verified, False otherwise.
1015
for auth_def_name, auth_def in self._get_config().items():
1016
if type(auth_def) is not configobj.Section:
1017
raise ValueError("%s defined outside a section" % auth_def_name)
1019
a_scheme, a_host, a_user, a_path = map(
1020
auth_def.get, ['scheme', 'host', 'user', 'path'])
1023
a_port = auth_def.as_int('port')
1027
raise ValueError("'port' not numeric in %s" % auth_def_name)
1029
a_verify_certificates = auth_def.as_bool('verify_certificates')
1031
a_verify_certificates = True
1034
"'verify_certificates' not boolean in %s" % auth_def_name)
1037
if a_scheme is not None and scheme != a_scheme:
1039
if a_host is not None:
1040
if not (host == a_host
1041
or (a_host.startswith('.') and host.endswith(a_host))):
1043
if a_port is not None and port != a_port:
1045
if (a_path is not None and path is not None
1046
and not path.startswith(a_path)):
1048
if (a_user is not None and user is not None
1049
and a_user != user):
1050
# Never contradict the caller about the user to be used
1055
credentials = dict(name=auth_def_name,
1057
password=auth_def.get('password', None),
1058
verify_certificates=a_verify_certificates)
1059
self.decode_password(credentials,
1060
auth_def.get('password_encoding', None))
1061
if 'auth' in debug.debug_flags:
1062
trace.mutter("Using authentication section: %r", auth_def_name)
1067
def set_credentials(self, name, host, user, scheme=None, password=None,
1068
port=None, path=None, verify_certificates=None):
1069
"""Set authentication credentials for a host.
1071
Any existing credentials with matching scheme, host, port and path
1072
will be deleted, regardless of name.
1074
:param name: An arbitrary name to describe this set of credentials.
1075
:param host: Name of the host that accepts these credentials.
1076
:param user: The username portion of these credentials.
1077
:param scheme: The URL scheme (e.g. ssh, http) the credentials apply
1079
:param password: Password portion of these credentials.
1080
:param port: The IP port on the host that these credentials apply to.
1081
:param path: A filesystem path on the host that these credentials
1083
:param verify_certificates: On https, verify server certificates if
1086
values = {'host': host, 'user': user}
1087
if password is not None:
1088
values['password'] = password
1089
if scheme is not None:
1090
values['scheme'] = scheme
1091
if port is not None:
1092
values['port'] = '%d' % port
1093
if path is not None:
1094
values['path'] = path
1095
if verify_certificates is not None:
1096
values['verify_certificates'] = str(verify_certificates)
1097
config = self._get_config()
1099
for section, existing_values in config.items():
1100
for key in ('scheme', 'host', 'port', 'path'):
1101
if existing_values.get(key) != values.get(key):
1105
config.update({name: values})
1108
def get_user(self, scheme, host, port=None,
1109
realm=None, path=None, prompt=None):
1110
"""Get a user from authentication file.
1112
:param scheme: protocol
1114
:param host: the server address
1116
:param port: the associated port (optional)
1118
:param realm: the realm sent by the server (optional)
1120
:param path: the absolute path on the server (optional)
1122
:return: The found user.
1124
credentials = self.get_credentials(scheme, host, port, user=None,
1126
if credentials is not None:
1127
user = credentials['user']
1132
def get_password(self, scheme, host, user, port=None,
1133
realm=None, path=None, prompt=None):
1134
"""Get a password from authentication file or prompt the user for one.
1136
:param scheme: protocol
1138
:param host: the server address
1140
:param port: the associated port (optional)
1144
:param realm: the realm sent by the server (optional)
1146
:param path: the absolute path on the server (optional)
1148
:return: The found password or the one entered by the user.
1150
credentials = self.get_credentials(scheme, host, port, user, path)
1151
if credentials is not None:
1152
password = credentials['password']
1153
if password is not None and scheme is 'ssh':
1154
trace.warning('password ignored in section [%s],'
1155
' use an ssh agent instead'
1156
% credentials['name'])
1160
# Prompt user only if we could't find a password
1161
if password is None:
1163
# Create a default prompt suitable for most cases
1164
prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1165
# Special handling for optional fields in the prompt
1166
if port is not None:
1167
prompt_host = '%s:%d' % (host, port)
1170
password = ui.ui_factory.get_password(prompt,
1171
host=prompt_host, user=user)
1174
def decode_password(self, credentials, encoding):
1178
class BzrDirConfig(object):
1180
def __init__(self, transport):
1181
self._config = TransportConfig(transport, 'control.conf')
1183
def set_default_stack_on(self, value):
1184
"""Set the default stacking location.
1186
It may be set to a location, or None.
1188
This policy affects all branches contained by this bzrdir, except for
1189
those under repositories.
1192
self._config.set_option('', 'default_stack_on')
1194
self._config.set_option(value, 'default_stack_on')
1196
def get_default_stack_on(self):
1197
"""Return the default stacking location.
1199
This will either be a location, or None.
1201
This policy affects all branches contained by this bzrdir, except for
1202
those under repositories.
1204
value = self._config.get_option('default_stack_on')
1210
class TransportConfig(object):
1211
"""A Config that reads/writes a config file on a Transport.
1213
It is a low-level object that considers config data to be name/value pairs
1214
that may be associated with a section. Assigning meaning to the these
1215
values is done at higher levels like TreeConfig.
1218
def __init__(self, transport, filename):
1219
self._transport = transport
1220
self._filename = filename
1222
def get_option(self, name, section=None, default=None):
1223
"""Return the value associated with a named option.
1225
:param name: The name of the value
1226
:param section: The section the option is in (if any)
1227
:param default: The value to return if the value is not set
1228
:return: The value or default value
1230
configobj = self._get_configobj()
1232
section_obj = configobj
1235
section_obj = configobj[section]
1238
return section_obj.get(name, default)
1240
def set_option(self, value, name, section=None):
1241
"""Set the value associated with a named option.
1243
:param value: The value to set
1244
:param name: The name of the value to set
1245
:param section: The section the option is in (if any)
1247
configobj = self._get_configobj()
1249
configobj[name] = value
1251
configobj.setdefault(section, {})[name] = value
1252
self._set_configobj(configobj)
1254
def _get_configobj(self):
1256
return ConfigObj(self._transport.get(self._filename),
1258
except errors.NoSuchFile:
1259
return ConfigObj(encoding='utf-8')
1261
def _set_configobj(self, configobj):
1262
out_file = StringIO()
1263
configobj.write(out_file)
1265
self._transport.put_file(self._filename, out_file)