68
from bzrlib.lazy_import import lazy_import
69
lazy_import(globals(), """
71
69
from fnmatch import fnmatch
73
from cStringIO import StringIO
87
from bzrlib.util.configobj import configobj
73
import bzrlib.errors as errors
74
from bzrlib.osutils import pathjoin
75
from bzrlib.trace import mutter
76
import bzrlib.util.configobj.configobj as configobj
77
from StringIO import StringIO
91
79
CHECK_IF_POSSIBLE=0
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)
84
class ConfigObj(configobj.ConfigObj):
86
def get_bool(self, section, key):
87
return self[section].as_bool(key)
89
def get_value(self, section, name):
90
# Try [] for the old DEFAULT section.
91
if section == "DEFAULT":
96
return self[section][name]
145
99
class Config(object):
309
self._parser = ConfigObj(input, encoding='utf-8')
220
self._parser = ConfigObj(input)
310
221
except configobj.ConfigObjError, e:
311
222
raise errors.ParseConfigError(e.errors, e.config.filename)
312
223
return self._parser
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
225
def _get_section(self):
327
226
"""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
229
def _get_signature_checking(self):
335
230
"""See Config._get_signature_checking."""
336
231
policy = self._get_user_option('check_signatures')
338
233
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
235
def _get_user_id(self):
347
236
"""Get the user id from the 'email' key in the current section."""
348
237
return self._get_user_option('email')
350
239
def _get_user_option(self, option_name):
351
240
"""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)
242
return self._get_parser().get_value(self._get_section(),
375
247
def _gpg_signing_command(self):
376
248
"""See Config.gpg_signing_command."""
431
289
def __init__(self):
432
290
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
293
class LocationConfig(IniBasedConfig):
472
294
"""A configuration object that gives the policy for a location."""
474
296
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)
297
super(LocationConfig, self).__init__(branches_config_filename)
298
self._global_config = None
492
299
self.location = location
494
def _get_matching_sections(self):
495
"""Return an ordered list of section names matching this location."""
301
def _get_global_config(self):
302
if self._global_config is None:
303
self._global_config = GlobalConfig()
304
return self._global_config
306
def _get_section(self):
307
"""Get the section we should look in for config items.
309
Returns None if none exists.
310
TODO: perhaps return a NullSection that thunks through to the
496
313
sections = self._get_parser()
497
314
location_names = self.location.split('/')
498
315
if self.location.endswith('/'):
499
316
del location_names[-1]
501
318
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('/')
319
section_names = section.split('/')
511
320
if section.endswith('/'):
512
321
del section_names[-1]
513
322
names = zip(location_names, section_names)
522
331
# if section is longer, no match.
523
332
if len(section_names) > len(location_names):
525
matches.append((len(section_names), section,
526
'/'.join(location_names[len(section_names):])))
334
# if path is longer, and recurse is not true, no match
335
if len(section_names) < len(location_names):
337
if not self._get_parser().get_bool(section, 'recurse'):
341
matches.append((len(section_names), section))
527
344
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):
347
def _gpg_signing_command(self):
348
"""See Config.gpg_signing_command."""
349
command = super(LocationConfig, self)._gpg_signing_command()
350
if command is not None:
352
return self._get_global_config()._gpg_signing_command()
354
def _log_format(self):
355
"""See Config.log_format."""
356
command = super(LocationConfig, self)._log_format()
357
if command is not None:
359
return self._get_global_config()._log_format()
361
def _get_user_id(self):
362
user_id = super(LocationConfig, self)._get_user_id()
363
if user_id is not None:
365
return self._get_global_config()._get_user_id()
367
def _get_user_option(self, option_name):
368
"""See Config._get_user_option."""
369
option_value = super(LocationConfig,
370
self)._get_user_option(option_name)
371
if option_value is not None:
373
return self._get_global_config()._get_user_option(option_name)
375
def _get_signature_checking(self):
376
"""See Config._get_signature_checking."""
377
check = super(LocationConfig, self)._get_signature_checking()
378
if check is not None:
380
return self._get_global_config()._get_signature_checking()
382
def _post_commit(self):
383
"""See Config.post_commit."""
384
hook = self._get_user_option('post_commit')
387
return self._get_global_config()._post_commit()
389
def set_user_option(self, option, value):
588
390
"""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
391
# FIXME: RBC 20051029 This should refresh the parser and also take a
595
# file lock on locations.conf.
392
# file lock on branches.conf.
596
393
conf_dir = os.path.dirname(self._get_filename())
597
394
ensure_config_dir_exists(conf_dir)
598
395
location = self.location
604
401
elif location + '/' in self._get_parser():
605
402
location = location + '/'
606
403
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'))
404
self._get_parser().write()
612
407
class BranchConfig(Config):
613
408
"""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
410
def _get_location_config(self):
621
411
if self._location_config is None:
622
412
self._location_config = LocationConfig(self.branch.base)
623
413
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
415
def _get_user_id(self):
658
416
"""Return the full user id for the branch.
660
e.g. "John Hacker <jhacker@example.com>"
418
e.g. "John Hacker <jhacker@foo.org>"
661
419
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())
422
return (self.branch.control_files.get_utf8("email")
424
.decode(bzrlib.user_encoding)
667
426
except errors.NoSuchFile, e:
670
return self._get_best_value('_get_user_id')
429
return self._get_location_config()._get_user_id()
672
431
def _get_signature_checking(self):
673
432
"""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')
433
return self._get_location_config()._get_signature_checking()
680
435
def _get_user_option(self, option_name):
681
436
"""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)
437
return self._get_location_config()._get_user_option(option_name)
712
439
def _gpg_signing_command(self):
713
440
"""See Config.gpg_signing_command."""
714
return self._get_safe_value('_gpg_signing_command')
441
return self._get_location_config()._gpg_signing_command()
716
443
def __init__(self, branch):
717
444
super(BranchConfig, self).__init__()
718
445
self._location_config = None
719
self._branch_data_config = None
720
self._global_config = None
721
446
self.branch = branch
722
self.option_sources = (self._get_location_config,
723
self._get_branch_data_config,
724
self._get_global_config)
726
448
def _post_commit(self):
727
449
"""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')
450
return self._get_location_config()._post_commit()
743
452
def _log_format(self):
744
453
"""See Config.log_format."""
745
return self._get_best_value('_log_format')
454
return self._get_location_config()._log_format()
748
457
def ensure_config_dir_exists(path=None):
773
482
base = os.environ.get('BZR_HOME', None)
774
483
if sys.platform == 'win32':
776
base = win32utils.get_appdata_location_unicode()
485
base = os.environ.get('APPDATA', None)
778
487
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')
489
raise BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
490
return pathjoin(base, 'bazaar', '2.0')
784
492
# cygwin, linux, and darwin all have a $HOME directory
786
494
base = os.path.expanduser("~")
787
return osutils.pathjoin(base, ".bazaar")
495
return pathjoin(base, ".bazaar")
790
498
def config_filename():
791
499
"""Return per-user configuration ini file filename."""
792
return osutils.pathjoin(config_dir(), 'bazaar.conf')
500
return pathjoin(config_dir(), 'bazaar.conf')
795
503
def branches_config_filename():
796
504
"""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')
505
return pathjoin(config_dir(), 'branches.conf')
815
508
def _auto_user_id():
872
537
except ImportError:
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." % \
539
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
881
541
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
544
def extract_email_address(e):
894
545
"""Return just the address part of an email string.
896
547
That is just the user@domain part, nothing else.
897
548
This part is required to contain only ascii characters.
898
549
If it can't be extracted, raises an error.
900
551
>>> extract_email_address('Jane Tester <jane@test.com>')
903
name, email = parse_username(e)
905
raise errors.NoEmailInUsername(e)
909
class TreeConfig(IniBasedConfig):
554
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
556
raise errors.BzrError("%r doesn't seem to contain "
557
"a reasonable email address" % e)
560
class TreeConfig(object):
910
561
"""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
562
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')
919
563
self.branch = branch
921
def _get_parser(self, file=None):
923
return IniBasedConfig._get_parser(file)
924
return self._config._get_configobj()
565
def _get_config(self):
567
obj = ConfigObj(self.branch.control_files.get('branch.conf'),
569
except errors.NoSuchFile:
570
obj = ConfigObj(encoding='utf=8')
926
573
def get_option(self, name, section=None, default=None):
927
574
self.branch.lock_read()
929
return self._config.get_option(name, section, default)
576
obj = self._get_config()
578
if section is not None:
931
584
self.branch.unlock()
935
588
"""Set a per-branch configuration option"""
936
589
self.branch.lock_write()
938
self._config.set_option(value, name, section)
591
cfg_obj = self._get_config()
596
obj = cfg_obj[section]
598
cfg_obj[section] = {}
599
obj = cfg_obj[section]
601
out_file = StringIO()
602
cfg_obj.write(out_file)
604
self.branch.control_files.put('branch.conf', out_file)
940
606
self.branch.unlock()
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 get_user(self, scheme, host, port=None,
1068
realm=None, path=None, prompt=None):
1069
"""Get a user from authentication file.
1071
:param scheme: protocol
1073
:param host: the server address
1075
:param port: the associated port (optional)
1077
:param realm: the realm sent by the server (optional)
1079
:param path: the absolute path on the server (optional)
1081
:return: The found user.
1083
credentials = self.get_credentials(scheme, host, port, user=None,
1085
if credentials is not None:
1086
user = credentials['user']
1091
def get_password(self, scheme, host, user, port=None,
1092
realm=None, path=None, prompt=None):
1093
"""Get a password from authentication file or prompt the user for one.
1095
:param scheme: protocol
1097
:param host: the server address
1099
:param port: the associated port (optional)
1103
:param realm: the realm sent by the server (optional)
1105
:param path: the absolute path on the server (optional)
1107
:return: The found password or the one entered by the user.
1109
credentials = self.get_credentials(scheme, host, port, user, path)
1110
if credentials is not None:
1111
password = credentials['password']
1112
if password is not None and scheme is 'ssh':
1113
trace.warning('password ignored in section [%s],'
1114
' use an ssh agent instead'
1115
% credentials['name'])
1119
# Prompt user only if we could't find a password
1120
if password is None:
1122
# Create a default prompt suitable for most cases
1123
prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1124
# Special handling for optional fields in the prompt
1125
if port is not None:
1126
prompt_host = '%s:%d' % (host, port)
1129
password = ui.ui_factory.get_password(prompt,
1130
host=prompt_host, user=user)
1133
def decode_password(self, credentials, encoding):
1137
class BzrDirConfig(object):
1139
def __init__(self, transport):
1140
self._config = TransportConfig(transport, 'control.conf')
1142
def set_default_stack_on(self, value):
1143
"""Set the default stacking location.
1145
It may be set to a location, or None.
1147
This policy affects all branches contained by this bzrdir, except for
1148
those under repositories.
1151
self._config.set_option('', 'default_stack_on')
1153
self._config.set_option(value, 'default_stack_on')
1155
def get_default_stack_on(self):
1156
"""Return the default stacking location.
1158
This will either be a location, or None.
1160
This policy affects all branches contained by this bzrdir, except for
1161
those under repositories.
1163
value = self._config.get_option('default_stack_on')
1169
class TransportConfig(object):
1170
"""A Config that reads/writes a config file on a Transport.
1172
It is a low-level object that considers config data to be name/value pairs
1173
that may be associated with a section. Assigning meaning to the these
1174
values is done at higher levels like TreeConfig.
1177
def __init__(self, transport, filename):
1178
self._transport = transport
1179
self._filename = filename
1181
def get_option(self, name, section=None, default=None):
1182
"""Return the value associated with a named option.
1184
:param name: The name of the value
1185
:param section: The section the option is in (if any)
1186
:param default: The value to return if the value is not set
1187
:return: The value or default value
1189
configobj = self._get_configobj()
1191
section_obj = configobj
1194
section_obj = configobj[section]
1197
return section_obj.get(name, default)
1199
def set_option(self, value, name, section=None):
1200
"""Set the value associated with a named option.
1202
:param value: The value to set
1203
:param name: The name of the value to set
1204
:param section: The section the option is in (if any)
1206
configobj = self._get_configobj()
1208
configobj[name] = value
1210
configobj.setdefault(section, {})[name] = value
1211
self._set_configobj(configobj)
1213
def _get_configobj(self):
1215
return ConfigObj(self._transport.get(self._filename),
1217
except errors.NoSuchFile:
1218
return ConfigObj(encoding='utf-8')
1220
def _set_configobj(self, configobj):
1221
out_file = StringIO()
1222
configobj.write(out_file)
1224
self._transport.put_file(self._filename, out_file)