2632
2632
# We re-use the dict-like object received
2633
2633
self.options = options
2635
def get(self, name, default=None):
2635
def get(self, name, default=None, expand=True):
2636
2636
return self.options.get(name, default)
2638
def iter_option_names(self):
2639
for k in self.options.iterkeys():
2638
2642
def __repr__(self):
2639
2643
# Mostly for debugging use
2640
2644
return "<config.%s id=%s>" % (self.__class__.__name__, self.id)
2665
2669
del self.options[name]
2668
class CommandLineSection(MutableSection):
2669
"""A section used to carry command line overrides for the config options."""
2671
def __init__(self, opts=None):
2674
super(CommandLineSection, self).__init__('cmdline-overrides', opts)
2677
# The dict should be cleared but not replaced so it can be shared.
2678
self.options.clear()
2680
def _from_cmdline(self, overrides):
2681
# Reset before accepting new definitions
2683
for over in overrides:
2685
name, value = over.split('=', 1)
2687
raise errors.BzrCommandError(
2688
gettext("Invalid '%s', should be of the form 'name=value'")
2690
self.set(name, value)
2693
2672
class Store(object):
2694
2673
"""Abstract interface to persistent storage for configuration options."""
2734
2713
def get_sections(self):
2735
2714
"""Returns an ordered iterable of existing sections.
2737
:returns: An iterable of (name, dict).
2716
:returns: An iterable of (store, section).
2739
2718
raise NotImplementedError(self.get_sections)
2741
def get_mutable_section(self, section_name=None):
2720
def get_mutable_section(self, section_id=None):
2742
2721
"""Returns the specified mutable section.
2744
:param section_name: The section identifier
2723
:param section_id: The section identifier
2746
2725
raise NotImplementedError(self.get_mutable_section)
2751
2730
self.external_url())
2733
class CommandLineStore(Store):
2734
"A store to carry command line overrides for the config options."""
2736
def __init__(self, opts=None):
2737
super(CommandLineStore, self).__init__()
2743
# The dict should be cleared but not replaced so it can be shared.
2744
self.options.clear()
2746
def _from_cmdline(self, overrides):
2747
# Reset before accepting new definitions
2749
for over in overrides:
2751
name, value = over.split('=', 1)
2753
raise errors.BzrCommandError(
2754
gettext("Invalid '%s', should be of the form 'name=value'")
2756
self.options[name] = value
2758
def external_url(self):
2759
# Not an url but it makes debugging easier and it never needed
2763
def get_sections(self):
2764
yield self, self.readonly_section_class('cmdline_overrides',
2754
2768
class IniFileStore(Store):
2755
2769
"""A config Store using ConfigObj for storage.
2762
2776
serialize/deserialize the config file.
2765
def __init__(self, transport, file_name):
2766
2780
"""A config Store using ConfigObj for storage.
2768
:param transport: The transport object where the config file is located.
2770
:param file_name: The config file basename in the transport directory.
2772
2782
super(IniFileStore, self).__init__()
2773
self.transport = transport
2774
self.file_name = file_name
2775
2783
self._config_obj = None
2777
2785
def is_loaded(self):
2780
2788
def unload(self):
2781
2789
self._config_obj = None
2791
def _load_content(self):
2792
"""Load the config file bytes.
2794
This should be provided by subclasses
2796
:return: Byte string
2798
raise NotImplementedError(self._load_content)
2800
def _save_content(self, content):
2801
"""Save the config file bytes.
2803
This should be provided by subclasses
2805
:param content: Config file bytes to write
2807
raise NotImplementedError(self._save_content)
2783
2809
def load(self):
2784
2810
"""Load the store from the associated file."""
2785
2811
if self.is_loaded():
2788
content = self.transport.get_bytes(self.file_name)
2789
except errors.PermissionDenied:
2790
trace.warning("Permission denied while trying to load "
2791
"configuration store %s.", self.external_url())
2813
content = self._load_content()
2793
2814
self._load_from_string(content)
2794
2815
for hook in ConfigHooks['load']:
2819
2840
out = StringIO()
2820
2841
self._config_obj.write(out)
2821
self.transport.put_bytes(self.file_name, out.getvalue())
2842
self._save_content(out.getvalue())
2822
2843
for hook in ConfigHooks['save']:
2825
def external_url(self):
2826
# FIXME: external_url should really accepts an optional relpath
2827
# parameter (bug #750169) :-/ -- vila 2011-04-04
2828
# The following will do in the interim but maybe we don't want to
2829
# expose a path here but rather a config ID and its associated
2830
# object </hand wawe>.
2831
return urlutils.join(self.transport.external_url(), self.file_name)
2833
2846
def get_sections(self):
2834
2847
"""Get the configobj section in the file order.
2836
:returns: An iterable of (name, dict).
2849
:returns: An iterable of (store, section).
2838
2851
# We need a loaded store
2844
2857
cobj = self._config_obj
2845
2858
if cobj.scalars:
2846
yield self.readonly_section_class(None, cobj)
2859
yield self, self.readonly_section_class(None, cobj)
2847
2860
for section_name in cobj.sections:
2848
yield self.readonly_section_class(section_name, cobj[section_name])
2862
self.readonly_section_class(section_name,
2863
cobj[section_name]))
2850
def get_mutable_section(self, section_name=None):
2865
def get_mutable_section(self, section_id=None):
2851
2866
# We need a loaded store
2854
2869
except errors.NoSuchFile:
2855
2870
# The file doesn't exist, let's pretend it was empty
2856
2871
self._load_from_string('')
2857
if section_name is None:
2872
if section_id is None:
2858
2873
section = self._config_obj
2860
section = self._config_obj.setdefault(section_name, {})
2861
return self.mutable_section_class(section_name, section)
2875
section = self._config_obj.setdefault(section_id, {})
2876
return self.mutable_section_class(section_id, section)
2879
class TransportIniFileStore(IniFileStore):
2880
"""IniFileStore that loads files from a transport.
2883
def __init__(self, transport, file_name):
2884
"""A Store using a ini file on a Transport
2886
:param transport: The transport object where the config file is located.
2887
:param file_name: The config file basename in the transport directory.
2889
super(TransportIniFileStore, self).__init__()
2890
self.transport = transport
2891
self.file_name = file_name
2893
def _load_content(self):
2895
return self.transport.get_bytes(self.file_name)
2896
except errors.PermissionDenied:
2897
trace.warning("Permission denied while trying to load "
2898
"configuration store %s.", self.external_url())
2901
def _save_content(self, content):
2902
self.transport.put_bytes(self.file_name, content)
2904
def external_url(self):
2905
# FIXME: external_url should really accepts an optional relpath
2906
# parameter (bug #750169) :-/ -- vila 2011-04-04
2907
# The following will do in the interim but maybe we don't want to
2908
# expose a path here but rather a config ID and its associated
2909
# object </hand wawe>.
2910
return urlutils.join(self.transport.external_url(), self.file_name)
2864
2913
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
2931
2981
t = transport.get_transport_from_path(
2932
2982
config_dir(), possible_transports=possible_transports)
2933
2983
super(LocationStore, self).__init__(t, 'locations.conf')
2936
class BranchStore(IniFileStore):
2984
self.id = 'locations'
2987
class BranchStore(TransportIniFileStore):
2938
2989
def __init__(self, branch):
2939
2990
super(BranchStore, self).__init__(branch.control_transport,
2941
2992
self.branch = branch
2943
2995
def lock_write(self, token=None):
2944
2996
return self.branch.lock_write(token)
3008
3060
super(LocationSection, self).__init__(section.id, section.options)
3009
3061
self.length = length
3010
3062
self.extra_path = extra_path
3063
self.locals = {'relpath': extra_path,
3064
'basename': urlutils.basename(extra_path)}
3012
def get(self, name, default=None):
3066
def get(self, name, default=None, expand=True):
3013
3067
value = super(LocationSection, self).get(name, default)
3014
if value is not None:
3068
if value is not None and expand:
3015
3069
policy_name = self.get(name + ':policy', None)
3016
3070
policy = _policy_value.get(policy_name, POLICY_NONE)
3017
3071
if policy == POLICY_APPENDPATH:
3018
3072
value = urlutils.join(value, self.extra_path)
3073
# expand section local options right now (since POLICY_APPENDPATH
3074
# will never add options references, it's ok to expand after it).
3076
for is_ref, chunk in iter_option_refs(value):
3078
chunks.append(chunk)
3081
if ref in self.locals:
3082
chunks.append(self.locals[ref])
3084
chunks.append(chunk)
3085
value = ''.join(chunks)
3080
3147
# Finally, we have a valid section
3148
yield self.store, section
3151
_option_ref_re = lazy_regex.lazy_compile('({[^{}]+})')
3152
"""Describes an expandable option reference.
3154
We want to match the most embedded reference first.
3156
I.e. for '{{foo}}' we will get '{foo}',
3157
for '{bar{baz}}' we will get '{baz}'
3160
def iter_option_refs(string):
3161
# Split isolate refs so every other chunk is a ref
3163
for chunk in _option_ref_re.split(string):
3084
3168
class Stack(object):
3085
3169
"""A stack of configurations where an option can be defined"""
3087
_option_ref_re = lazy_regex.lazy_compile('({[^{}]+})')
3088
"""Describes an exandable option reference.
3090
We want to match the most embedded reference first.
3092
I.e. for '{{foo}}' we will get '{foo}',
3093
for '{bar{baz}}' we will get '{baz}'
3096
def __init__(self, sections_def, store=None, mutable_section_name=None):
3171
def __init__(self, sections_def, store=None, mutable_section_id=None):
3097
3172
"""Creates a stack of sections with an optional store for changes.
3099
3174
:param sections_def: A list of Section or callables that returns an
3103
3178
:param store: The optional Store where modifications will be
3104
3179
recorded. If none is specified, no modifications can be done.
3106
:param mutable_section_name: The name of the MutableSection where
3107
changes are recorded. This requires the ``store`` parameter to be
3181
:param mutable_section_id: The id of the MutableSection where changes
3182
are recorded. This requires the ``store`` parameter to be
3110
3185
self.sections_def = sections_def
3111
3186
self.store = store
3112
self.mutable_section_name = mutable_section_name
3187
self.mutable_section_id = mutable_section_id
3114
3189
def get(self, name, expand=None):
3115
3190
"""Return the *first* option value found in the sections.
3134
3209
# implies querying the persistent storage) until it can't be avoided
3135
3210
# anymore by using callables to describe (possibly empty) section
3137
for section_or_callable in self.sections_def:
3138
# Each section can expand to multiple ones when a callable is used
3139
if callable(section_or_callable):
3140
sections = section_or_callable()
3142
sections = [section_or_callable]
3143
for section in sections:
3212
for sections in self.sections_def:
3213
for store, section in sections():
3144
3214
value = section.get(name)
3145
3215
if value is not None:
3242
3307
# anything else
3243
3308
value = env[name]
3245
# FIXME: This is a limited implementation, what we really need is a
3246
# way to query the bzr config for the value of an option,
3247
# respecting the scope rules (That is, once we implement fallback
3248
# configs, getting the option value should restart from the top
3249
# config, not the current one) -- vila 20101222
3250
3310
value = self.get(name, expand=False)
3251
3311
value = self._expand_options_in_string(value, env, _refs)
3257
3317
This is where we guarantee that the mutable section is lazily loaded:
3258
3318
this means we won't load the corresponding store before setting a value
3259
3319
or deleting an option. In practice the store will often be loaded but
3260
this allows helps catching some programming errors.
3320
this helps catching some programming errors.
3262
section = self.store.get_mutable_section(self.mutable_section_name)
3322
section = self.store.get_mutable_section(self.mutable_section_id)
3265
3325
def set(self, name, value):
3331
3398
:param location: A URL prefix to """
3332
3399
lstore = LocationStore()
3400
if location.startswith('file://'):
3401
location = urlutils.local_path_from_url(location)
3333
3402
matcher = LocationMatcher(lstore, location)
3334
3403
gstore = GlobalStore()
3335
3404
super(LocationStack, self).__init__(
3336
3405
[self._get_overrides,
3337
matcher.get_sections, gstore.get_sections],
3406
matcher.get_sections, NameMatcher(gstore, 'DEFAULT').get_sections],
3407
lstore, mutable_section_id=location)
3341
3410
class BranchStack(_CompatibleStack):
3342
3411
"""Per-location options falling back to branch then global options stack."""
3344
3413
def __init__(self, branch):
3345
bstore = BranchStore(branch)
3414
bstore = branch._get_config_store()
3346
3415
lstore = LocationStore()
3347
3416
matcher = LocationMatcher(lstore, branch.base)
3348
3417
gstore = GlobalStore()
3349
3418
super(BranchStack, self).__init__(
3350
3419
[self._get_overrides,
3351
matcher.get_sections, bstore.get_sections, gstore.get_sections],
3420
matcher.get_sections, bstore.get_sections,
3421
NameMatcher(gstore, 'DEFAULT').get_sections],
3353
3423
self.branch = branch
3356
3426
class RemoteControlStack(_CompatibleStack):
3357
3427
"""Remote control-only options stack."""
3429
# FIXME 2011-11-22 JRV This should probably be renamed to avoid confusion
3430
# with the stack used for remote bzr dirs. RemoteControlStack only uses
3431
# control.conf and is used only for stack options.
3359
3433
def __init__(self, bzrdir):
3360
cstore = ControlStore(bzrdir)
3434
cstore = bzrdir._get_config_store()
3361
3435
super(RemoteControlStack, self).__init__(
3362
3436
[cstore.get_sections],
3367
3441
class RemoteBranchStack(_CompatibleStack):
3368
3442
"""Remote branch-only options stack."""
3444
# FIXME 2011-11-22 JRV This should probably be renamed to avoid confusion
3445
# with the stack used for remote branches. RemoteBranchStack only uses
3446
# branch.conf and is used only for the stack options.
3370
3448
def __init__(self, branch):
3371
bstore = BranchStore(branch)
3449
bstore = branch._get_config_store()
3372
3450
super(RemoteBranchStack, self).__init__(
3373
3451
[bstore.get_sections],
3375
3453
self.branch = branch
3455
# Use a an empty dict to initialize an empty configobj avoiding all
3456
# parsing and encoding checks
3457
_quoting_config = configobj.ConfigObj(
3458
{}, encoding='utf-8', interpolation=False)
3378
3460
class cmd_config(commands.Command):
3379
3461
__doc__ = """Display, set or remove a configuration option.
3396
3478
takes_options = [
3398
3480
# FIXME: This should be a registry option so that plugins can register
3399
# their own config files (or not) -- vila 20101002
3481
# their own config files (or not) and will also address
3482
# http://pad.lv/788991 -- vila 20101115
3400
3483
commands.Option('scope', help='Reduce the scope to the specified'
3401
' configuration file',
3484
' configuration file.',
3403
3486
commands.Option('all',
3404
3487
help='Display all the defined values for the matching options.',
3406
3489
commands.Option('remove', help='Remove the option from'
3407
' the configuration file'),
3490
' the configuration file.'),
3410
3493
_see_also = ['configuration']
3440
3523
# Set the option value
3441
3524
self._set_config_option(name, value, directory, scope)
3443
def _get_configs(self, directory, scope=None):
3444
"""Iterate the configurations specified by ``directory`` and ``scope``.
3526
def _get_stack(self, directory, scope=None):
3527
"""Get the configuration stack specified by ``directory`` and ``scope``.
3446
3529
:param directory: Where the configurations are derived from.
3448
3531
:param scope: A specific config to start from.
3533
# FIXME: scope should allow access to plugin-specific stacks (even
3534
# reduced to the plugin-specific store), related to
3535
# http://pad.lv/788991 -- vila 2011-11-15
3450
3536
if scope is not None:
3451
3537
if scope == 'bazaar':
3452
yield GlobalConfig()
3538
return GlobalStack()
3453
3539
elif scope == 'locations':
3454
yield LocationConfig(directory)
3540
return LocationStack(directory)
3455
3541
elif scope == 'branch':
3456
(_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
3458
yield br.get_config()
3543
controldir.ControlDir.open_containing_tree_or_branch(
3545
return br.get_config_stack()
3546
raise errors.NoSuchConfig(scope)
3461
(_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
3463
yield br.get_config()
3550
controldir.ControlDir.open_containing_tree_or_branch(
3552
return br.get_config_stack()
3464
3553
except errors.NotBranchError:
3465
yield LocationConfig(directory)
3466
yield GlobalConfig()
3554
return LocationStack(directory)
3468
3556
def _show_value(self, name, directory, scope):
3470
for c in self._get_configs(directory, scope):
3473
for (oname, value, section, conf_id, parser) in c._get_options():
3475
# Display only the first value and exit
3477
# FIXME: We need to use get_user_option to take policies
3478
# into account and we need to make sure the option exists
3479
# too (hence the two for loops), this needs a better API
3481
value = c.get_user_option(name)
3482
# Quote the value appropriately
3483
value = parser._quote(value)
3484
self.outf.write('%s\n' % (value,))
3557
conf = self._get_stack(directory, scope)
3558
value = conf.get(name, expand=True)
3559
if value is not None:
3560
# Quote the value appropriately
3561
value = _quoting_config._quote(value)
3562
self.outf.write('%s\n' % (value,))
3488
3564
raise errors.NoSuchConfigOption(name)
3490
3566
def _show_matching_options(self, name, directory, scope):
3493
3569
# avoid the delay introduced by the lazy regexp. But, we still do
3494
3570
# want the nicer errors raised by lazy_regex.
3495
3571
name._compile_and_collapse()
3497
3573
cur_section = None
3498
for c in self._get_configs(directory, scope):
3499
for (oname, value, section, conf_id, parser) in c._get_options():
3500
if name.search(oname):
3501
if cur_conf_id != conf_id:
3502
# Explain where the options are defined
3503
self.outf.write('%s:\n' % (conf_id,))
3504
cur_conf_id = conf_id
3506
if (section not in (None, 'DEFAULT')
3507
and cur_section != section):
3508
# Display the section if it's not the default (or only)
3510
self.outf.write(' [%s]\n' % (section,))
3511
cur_section = section
3512
self.outf.write(' %s = %s\n' % (oname, value))
3574
conf = self._get_stack(directory, scope)
3575
for sections in conf.sections_def:
3576
for store, section in sections():
3577
for oname in section.iter_option_names():
3578
if name.search(oname):
3579
if cur_store_id != store.id:
3580
# Explain where the options are defined
3581
self.outf.write('%s:\n' % (store.id,))
3582
cur_store_id = store.id
3584
if (section.id not in (None, 'DEFAULT')
3585
and cur_section != section.id):
3586
# Display the section if it's not the default (or
3588
self.outf.write(' [%s]\n' % (section.id,))
3589
cur_section = section.id
3590
value = section.get(oname, expand=False)
3591
value = _quoting_config._quote(value)
3592
self.outf.write(' %s = %s\n' % (oname, value))
3514
3594
def _set_config_option(self, name, value, directory, scope):
3515
for conf in self._get_configs(directory, scope):
3516
conf.set_user_option(name, value)
3519
raise errors.NoSuchConfig(scope)
3595
conf = self._get_stack(directory, scope)
3596
conf.set(name, value)
3521
3598
def _remove_config_option(self, name, directory, scope):
3522
3599
if name is None:
3523
3600
raise errors.BzrCommandError(
3524
3601
'--remove expects an option to remove.')
3526
for conf in self._get_configs(directory, scope):
3527
for (section_name, section, conf_id) in conf._get_sections():
3528
if scope is not None and conf_id != scope:
3529
# Not the right configuration file
3532
if conf_id != conf.config_id():
3533
conf = self._get_configs(directory, conf_id).next()
3534
# We use the first section in the first config where the
3535
# option is defined to remove it
3536
conf.remove_user_option(name, section_name)
3541
raise errors.NoSuchConfig(scope)
3602
conf = self._get_stack(directory, scope)
3543
3606
raise errors.NoSuchConfigOption(name)
3545
3609
# Test registries
3547
3611
# We need adapters that can build a Store or a Stack in a test context. Test