~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Jelmer Vernooij
  • Date: 2011-11-25 17:54:52 UTC
  • mfrom: (6303 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6321.
  • Revision ID: jelmer@samba.org-20111125175452-v0uwwxqcp97tzuzv
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
87
87
 
88
88
from bzrlib import (
89
89
    atomicfile,
90
 
    bzrdir,
 
90
    controldir,
91
91
    debug,
92
92
    errors,
93
93
    lazy_regex,
2632
2632
        # We re-use the dict-like object received
2633
2633
        self.options = options
2634
2634
 
2635
 
    def get(self, name, default=None):
 
2635
    def get(self, name, default=None, expand=True):
2636
2636
        return self.options.get(name, default)
2637
2637
 
 
2638
    def iter_option_names(self):
 
2639
        for k in self.options.iterkeys():
 
2640
            yield k
 
2641
 
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]
2666
2670
 
2667
2671
 
2668
 
class CommandLineSection(MutableSection):
2669
 
    """A section used to carry command line overrides for the config options."""
2670
 
 
2671
 
    def __init__(self, opts=None):
2672
 
        if opts is None:
2673
 
            opts = {}
2674
 
        super(CommandLineSection, self).__init__('cmdline-overrides', opts)
2675
 
 
2676
 
    def _reset(self):
2677
 
        # The dict should be cleared but not replaced so it can be shared.
2678
 
        self.options.clear()
2679
 
 
2680
 
    def _from_cmdline(self, overrides):
2681
 
        # Reset before accepting new definitions
2682
 
        self._reset()
2683
 
        for over in overrides:
2684
 
            try:
2685
 
                name, value = over.split('=', 1)
2686
 
            except ValueError:
2687
 
                raise errors.BzrCommandError(
2688
 
                    gettext("Invalid '%s', should be of the form 'name=value'")
2689
 
                    % (over,))
2690
 
            self.set(name, value)
2691
 
 
2692
 
 
2693
2672
class Store(object):
2694
2673
    """Abstract interface to persistent storage for configuration options."""
2695
2674
 
2734
2713
    def get_sections(self):
2735
2714
        """Returns an ordered iterable of existing sections.
2736
2715
 
2737
 
        :returns: An iterable of (name, dict).
 
2716
        :returns: An iterable of (store, section).
2738
2717
        """
2739
2718
        raise NotImplementedError(self.get_sections)
2740
2719
 
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.
2743
2722
 
2744
 
        :param section_name: The section identifier
 
2723
        :param section_id: The section identifier
2745
2724
        """
2746
2725
        raise NotImplementedError(self.get_mutable_section)
2747
2726
 
2751
2730
                                    self.external_url())
2752
2731
 
2753
2732
 
 
2733
class CommandLineStore(Store):
 
2734
    "A store to carry command line overrides for the config options."""
 
2735
 
 
2736
    def __init__(self, opts=None):
 
2737
        super(CommandLineStore, self).__init__()
 
2738
        if opts is None:
 
2739
            opts = {}
 
2740
        self.options = {}
 
2741
 
 
2742
    def _reset(self):
 
2743
        # The dict should be cleared but not replaced so it can be shared.
 
2744
        self.options.clear()
 
2745
 
 
2746
    def _from_cmdline(self, overrides):
 
2747
        # Reset before accepting new definitions
 
2748
        self._reset()
 
2749
        for over in overrides:
 
2750
            try:
 
2751
                name, value = over.split('=', 1)
 
2752
            except ValueError:
 
2753
                raise errors.BzrCommandError(
 
2754
                    gettext("Invalid '%s', should be of the form 'name=value'")
 
2755
                    % (over,))
 
2756
            self.options[name] = value
 
2757
 
 
2758
    def external_url(self):
 
2759
        # Not an url but it makes debugging easier and it never needed
 
2760
        # otherwise
 
2761
        return 'cmdline'
 
2762
 
 
2763
    def get_sections(self):
 
2764
        yield self,  self.readonly_section_class('cmdline_overrides',
 
2765
                                                 self.options)
 
2766
 
 
2767
 
2754
2768
class IniFileStore(Store):
2755
2769
    """A config Store using ConfigObj for storage.
2756
2770
 
2762
2776
        serialize/deserialize the config file.
2763
2777
    """
2764
2778
 
2765
 
    def __init__(self, transport, file_name):
 
2779
    def __init__(self):
2766
2780
        """A config Store using ConfigObj for storage.
2767
 
 
2768
 
        :param transport: The transport object where the config file is located.
2769
 
 
2770
 
        :param file_name: The config file basename in the transport directory.
2771
2781
        """
2772
2782
        super(IniFileStore, self).__init__()
2773
 
        self.transport = transport
2774
 
        self.file_name = file_name
2775
2783
        self._config_obj = None
2776
2784
 
2777
2785
    def is_loaded(self):
2780
2788
    def unload(self):
2781
2789
        self._config_obj = None
2782
2790
 
 
2791
    def _load_content(self):
 
2792
        """Load the config file bytes.
 
2793
 
 
2794
        This should be provided by subclasses
 
2795
 
 
2796
        :return: Byte string
 
2797
        """
 
2798
        raise NotImplementedError(self._load_content)
 
2799
 
 
2800
    def _save_content(self, content):
 
2801
        """Save the config file bytes.
 
2802
 
 
2803
        This should be provided by subclasses
 
2804
 
 
2805
        :param content: Config file bytes to write
 
2806
        """
 
2807
        raise NotImplementedError(self._save_content)
 
2808
 
2783
2809
    def load(self):
2784
2810
        """Load the store from the associated file."""
2785
2811
        if self.is_loaded():
2786
2812
            return
2787
 
        try:
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())
2792
 
            raise
 
2813
        content = self._load_content()
2793
2814
        self._load_from_string(content)
2794
2815
        for hook in ConfigHooks['load']:
2795
2816
            hook(self)
2818
2839
            return
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']:
2823
2844
            hook(self)
2824
2845
 
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)
2832
 
 
2833
2846
    def get_sections(self):
2834
2847
        """Get the configobj section in the file order.
2835
2848
 
2836
 
        :returns: An iterable of (name, dict).
 
2849
        :returns: An iterable of (store, section).
2837
2850
        """
2838
2851
        # We need a loaded store
2839
2852
        try:
2843
2856
            return
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])
 
2861
            yield (self,
 
2862
                   self.readonly_section_class(section_name,
 
2863
                                               cobj[section_name]))
2849
2864
 
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
2852
2867
        try:
2853
2868
            self.load()
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
2859
2874
        else:
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)
 
2877
 
 
2878
 
 
2879
class TransportIniFileStore(IniFileStore):
 
2880
    """IniFileStore that loads files from a transport.
 
2881
    """
 
2882
 
 
2883
    def __init__(self, transport, file_name):
 
2884
        """A Store using a ini file on a Transport
 
2885
 
 
2886
        :param transport: The transport object where the config file is located.
 
2887
        :param file_name: The config file basename in the transport directory.
 
2888
        """
 
2889
        super(TransportIniFileStore, self).__init__()
 
2890
        self.transport = transport
 
2891
        self.file_name = file_name
 
2892
 
 
2893
    def _load_content(self):
 
2894
        try:
 
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())
 
2899
            raise
 
2900
 
 
2901
    def _save_content(self, content):
 
2902
        self.transport.put_bytes(self.file_name, content)
 
2903
 
 
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)
2862
2911
 
2863
2912
 
2864
2913
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
2867
2916
# they may face the same issue.
2868
2917
 
2869
2918
 
2870
 
class LockableIniFileStore(IniFileStore):
 
2919
class LockableIniFileStore(TransportIniFileStore):
2871
2920
    """A ConfigObjStore using locks on save to ensure store integrity."""
2872
2921
 
2873
2922
    def __init__(self, transport, file_name, lock_dir_name=None):
2923
2972
        t = transport.get_transport_from_path(
2924
2973
            config_dir(), possible_transports=possible_transports)
2925
2974
        super(GlobalStore, self).__init__(t, 'bazaar.conf')
 
2975
        self.id = 'bazaar'
2926
2976
 
2927
2977
 
2928
2978
class LocationStore(LockableIniFileStore):
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')
2934
 
 
2935
 
 
2936
 
class BranchStore(IniFileStore):
 
2984
        self.id = 'locations'
 
2985
 
 
2986
 
 
2987
class BranchStore(TransportIniFileStore):
2937
2988
 
2938
2989
    def __init__(self, branch):
2939
2990
        super(BranchStore, self).__init__(branch.control_transport,
2940
2991
                                          'branch.conf')
2941
2992
        self.branch = branch
 
2993
        self.id = 'branch'
2942
2994
 
2943
2995
    def lock_write(self, token=None):
2944
2996
        return self.branch.lock_write(token)
2978
3030
        # sections.
2979
3031
        sections = self.store.get_sections()
2980
3032
        # Walk the revisions in the order provided
2981
 
        for s in sections:
 
3033
        for store, s in sections:
2982
3034
            if self.match(s):
2983
 
                yield s
 
3035
                yield store, s
2984
3036
 
2985
3037
    def match(self, section):
2986
3038
        """Does the proposed section match.
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)}
3011
3065
 
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).
 
3075
            chunks = []
 
3076
            for is_ref, chunk in iter_option_refs(value):
 
3077
                if not is_ref:
 
3078
                    chunks.append(chunk)
 
3079
                else:
 
3080
                    ref = chunk[1:-1]
 
3081
                    if ref in self.locals:
 
3082
                        chunks.append(self.locals[ref])
 
3083
                    else:
 
3084
                        chunks.append(chunk)
 
3085
            value = ''.join(chunks)
3019
3086
        return value
3020
3087
 
3021
3088
 
3035
3102
        all_sections = []
3036
3103
        # Filter out the no_name_section so _iter_for_location_by_parts can be
3037
3104
        # used (it assumes all sections have a name).
3038
 
        for section in self.store.get_sections():
 
3105
        for _, section in self.store.get_sections():
3039
3106
            if section.id is None:
3040
3107
                no_name_section = section
3041
3108
            else:
3078
3145
            if ignore:
3079
3146
                break
3080
3147
            # Finally, we have a valid section
3081
 
            yield section
 
3148
            yield self.store, section
 
3149
 
 
3150
 
 
3151
_option_ref_re = lazy_regex.lazy_compile('({[^{}]+})')
 
3152
"""Describes an expandable option reference.
 
3153
 
 
3154
We want to match the most embedded reference first.
 
3155
 
 
3156
I.e. for '{{foo}}' we will get '{foo}',
 
3157
for '{bar{baz}}' we will get '{baz}'
 
3158
"""
 
3159
 
 
3160
def iter_option_refs(string):
 
3161
    # Split isolate refs so every other chunk is a ref
 
3162
    is_ref = False
 
3163
    for chunk  in _option_ref_re.split(string):
 
3164
        yield is_ref, chunk
 
3165
        is_ref = not is_ref
3082
3166
 
3083
3167
 
3084
3168
class Stack(object):
3085
3169
    """A stack of configurations where an option can be defined"""
3086
3170
 
3087
 
    _option_ref_re = lazy_regex.lazy_compile('({[^{}]+})')
3088
 
    """Describes an exandable option reference.
3089
 
 
3090
 
    We want to match the most embedded reference first.
3091
 
 
3092
 
    I.e. for '{{foo}}' we will get '{foo}',
3093
 
    for '{bar{baz}}' we will get '{baz}'
3094
 
    """
3095
 
 
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.
3098
3173
 
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.
3105
3180
 
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
3108
3183
            specified.
3109
3184
        """
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
3113
3188
 
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
3136
3211
        # lists.
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()
3141
 
            else:
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:
3146
3216
                    break
3210
3280
        result = string
3211
3281
        # We need to iterate until no more refs appear ({{foo}} will need two
3212
3282
        # iterations for example).
3213
 
        while True:
3214
 
            raw_chunks = Stack._option_ref_re.split(result)
3215
 
            if len(raw_chunks) == 1:
3216
 
                # Shorcut the trivial case: no refs
3217
 
                return result
 
3283
        expanded = True
 
3284
        while expanded:
 
3285
            expanded = False
3218
3286
            chunks = []
3219
 
            # Split will isolate refs so that every other chunk is a ref
3220
 
            chunk_is_ref = False
3221
 
            for chunk in raw_chunks:
3222
 
                if not chunk_is_ref:
 
3287
            for is_ref, chunk in iter_option_refs(result):
 
3288
                if not is_ref:
3223
3289
                    chunks.append(chunk)
3224
 
                    chunk_is_ref = True
3225
3290
                else:
 
3291
                    expanded = True
3226
3292
                    name = chunk[1:-1]
3227
3293
                    if name in _refs:
3228
3294
                        raise errors.OptionExpansionLoop(string, _refs)
3232
3298
                        raise errors.ExpandingUnknownOption(name, string)
3233
3299
                    chunks.append(value)
3234
3300
                    _refs.pop()
3235
 
                    chunk_is_ref = False
3236
3301
            result = ''.join(chunks)
3237
3302
        return result
3238
3303
 
3242
3307
            # anything else
3243
3308
            value = env[name]
3244
3309
        else:
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)
3252
3312
        return value
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.
3261
3321
        """
3262
 
        section = self.store.get_mutable_section(self.mutable_section_name)
 
3322
        section = self.store.get_mutable_section(self.mutable_section_id)
3263
3323
        return section
3264
3324
 
3265
3325
    def set(self, name, value):
3283
3343
    def _get_overrides(self):
3284
3344
        # Hack around library_state.initialize never called
3285
3345
        if bzrlib.global_state is not None:
3286
 
            return [bzrlib.global_state.cmdline_overrides]
 
3346
            return bzrlib.global_state.cmdline_overrides.get_sections()
3287
3347
        return []
3288
3348
 
3289
3349
 
3296
3356
    One assumption made here is that the daughter classes will all use Stores
3297
3357
    derived from LockableIniFileStore).
3298
3358
 
3299
 
    It implements set() by re-loading the store before applying the
3300
 
    modification and saving it.
 
3359
    It implements set() and remove () by re-loading the store before applying
 
3360
    the modification and saving it.
3301
3361
 
3302
3362
    The long term plan being to implement a single write by store to save
3303
3363
    all modifications, this class should not be used in the interim.
3310
3370
        # Force a write to persistent storage
3311
3371
        self.store.save()
3312
3372
 
 
3373
    def remove(self, name):
 
3374
        # Force a reload
 
3375
        self.store.unload()
 
3376
        super(_CompatibleStack, self).remove(name)
 
3377
        # Force a write to persistent storage
 
3378
        self.store.save()
 
3379
 
3313
3380
 
3314
3381
class GlobalStack(_CompatibleStack):
3315
3382
    """Global options only stack."""
3318
3385
        # Get a GlobalStore
3319
3386
        gstore = GlobalStore()
3320
3387
        super(GlobalStack, self).__init__(
3321
 
            [self._get_overrides, gstore.get_sections],
3322
 
            gstore)
 
3388
            [self._get_overrides, NameMatcher(gstore, 'DEFAULT').get_sections],
 
3389
            gstore, mutable_section_id='DEFAULT')
3323
3390
 
3324
3391
 
3325
3392
class LocationStack(_CompatibleStack):
3330
3397
        
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],
3338
 
            lstore)
 
3406
             matcher.get_sections, NameMatcher(gstore, 'DEFAULT').get_sections],
 
3407
            lstore, mutable_section_id=location)
3339
3408
 
3340
3409
 
3341
3410
class BranchStack(_CompatibleStack):
3342
3411
    """Per-location options falling back to branch then global options stack."""
3343
3412
 
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],
3352
3422
            bstore)
3353
3423
        self.branch = branch
3354
3424
 
3356
3426
class RemoteControlStack(_CompatibleStack):
3357
3427
    """Remote control-only options stack."""
3358
3428
 
 
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.
 
3432
 
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],
3363
3437
            cstore)
3367
3441
class RemoteBranchStack(_CompatibleStack):
3368
3442
    """Remote branch-only options stack."""
3369
3443
 
 
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.
 
3447
 
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],
3374
3452
            bstore)
3375
3453
        self.branch = branch
3376
3454
 
 
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)
3377
3459
 
3378
3460
class cmd_config(commands.Command):
3379
3461
    __doc__ = """Display, set or remove a configuration option.
3396
3478
    takes_options = [
3397
3479
        'directory',
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.',
3402
3485
                        type=unicode),
3403
3486
        commands.Option('all',
3404
3487
            help='Display all the defined values for the matching options.',
3405
3488
            ),
3406
3489
        commands.Option('remove', help='Remove the option from'
3407
 
                        ' the configuration file'),
 
3490
                        ' the configuration file.'),
3408
3491
        ]
3409
3492
 
3410
3493
    _see_also = ['configuration']
3440
3523
                # Set the option value
3441
3524
                self._set_config_option(name, value, directory, scope)
3442
3525
 
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``.
3445
3528
 
3446
3529
        :param directory: Where the configurations are derived from.
3447
3530
 
3448
3531
        :param scope: A specific config to start from.
3449
3532
        """
 
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(
3457
 
                    directory)
3458
 
                yield br.get_config()
 
3542
                (_, br, _) = (
 
3543
                    controldir.ControlDir.open_containing_tree_or_branch(
 
3544
                        directory))
 
3545
                return br.get_config_stack()
 
3546
            raise errors.NoSuchConfig(scope)
3459
3547
        else:
3460
3548
            try:
3461
 
                (_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
3462
 
                    directory)
3463
 
                yield br.get_config()
 
3549
                (_, br, _) = (
 
3550
                    controldir.ControlDir.open_containing_tree_or_branch(
 
3551
                        directory))
 
3552
                return br.get_config_stack()
3464
3553
            except errors.NotBranchError:
3465
 
                yield LocationConfig(directory)
3466
 
                yield GlobalConfig()
 
3554
                return LocationStack(directory)
3467
3555
 
3468
3556
    def _show_value(self, name, directory, scope):
3469
 
        displayed = False
3470
 
        for c in self._get_configs(directory, scope):
3471
 
            if displayed:
3472
 
                break
3473
 
            for (oname, value, section, conf_id, parser) in c._get_options():
3474
 
                if name == oname:
3475
 
                    # Display only the first value and exit
3476
 
 
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
3480
 
                    # -- vila 20101117
3481
 
                    value = c.get_user_option(name)
3482
 
                    # Quote the value appropriately
3483
 
                    value = parser._quote(value)
3484
 
                    self.outf.write('%s\n' % (value,))
3485
 
                    displayed = True
3486
 
                    break
3487
 
        if not displayed:
 
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,))
 
3563
        else:
3488
3564
            raise errors.NoSuchConfigOption(name)
3489
3565
 
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()
3496
 
        cur_conf_id = None
 
3572
        cur_store_id = None
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
3505
 
                        cur_section = None
3506
 
                    if (section not in (None, 'DEFAULT')
3507
 
                        and cur_section != section):
3508
 
                        # Display the section if it's not the default (or only)
3509
 
                        # one.
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
 
3583
                            cur_section = None
 
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
 
3587
                            # only) one.
 
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))
3513
3593
 
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)
3517
 
            break
3518
 
        else:
3519
 
            raise errors.NoSuchConfig(scope)
 
3595
        conf = self._get_stack(directory, scope)
 
3596
        conf.set(name, value)
3520
3597
 
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.')
3525
 
        removed = False
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
3530
 
                    continue
3531
 
                if name in section:
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)
3537
 
                    removed = True
3538
 
                    break
3539
 
            break
3540
 
        else:
3541
 
            raise errors.NoSuchConfig(scope)
3542
 
        if not removed:
 
3602
        conf = self._get_stack(directory, scope)
 
3603
        try:
 
3604
            conf.remove(name)
 
3605
        except KeyError:
3543
3606
            raise errors.NoSuchConfigOption(name)
3544
3607
 
 
3608
 
3545
3609
# Test registries
3546
3610
#
3547
3611
# We need adapters that can build a Store or a Stack in a test context. Test