/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Vincent Ladeuil
  • Date: 2011-11-16 15:57:14 UTC
  • mto: This revision was merged to the branch mainline in revision 6273.
  • Revision ID: v.ladeuil+lp@free.fr-20111116155714-6a15q7tcjsfax0iu
Switch ``bzr config`` to the new config implementation

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
2833
2847
    def get_sections(self):
2834
2848
        """Get the configobj section in the file order.
2835
2849
 
2836
 
        :returns: An iterable of (name, dict).
 
2850
        :returns: An iterable of (store, section).
2837
2851
        """
2838
2852
        # We need a loaded store
2839
2853
        try:
2843
2857
            return
2844
2858
        cobj = self._config_obj
2845
2859
        if cobj.scalars:
2846
 
            yield self.readonly_section_class(None, cobj)
 
2860
            yield self, self.readonly_section_class(None, cobj)
2847
2861
        for section_name in cobj.sections:
2848
 
            yield self.readonly_section_class(section_name, cobj[section_name])
 
2862
            yield (self,
 
2863
                   self.readonly_section_class(section_name,
 
2864
                                               cobj[section_name]))
2849
2865
 
2850
 
    def get_mutable_section(self, section_name=None):
 
2866
    def get_mutable_section(self, section_id=None):
2851
2867
        # We need a loaded store
2852
2868
        try:
2853
2869
            self.load()
2854
2870
        except errors.NoSuchFile:
2855
2871
            # The file doesn't exist, let's pretend it was empty
2856
2872
            self._load_from_string('')
2857
 
        if section_name is None:
 
2873
        if section_id is None:
2858
2874
            section = self._config_obj
2859
2875
        else:
2860
 
            section = self._config_obj.setdefault(section_name, {})
2861
 
        return self.mutable_section_class(section_name, section)
 
2876
            section = self._config_obj.setdefault(section_id, {})
 
2877
        return self.mutable_section_class(section_id, section)
2862
2878
 
2863
2879
 
2864
2880
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
2923
2939
        t = transport.get_transport_from_path(
2924
2940
            config_dir(), possible_transports=possible_transports)
2925
2941
        super(GlobalStore, self).__init__(t, 'bazaar.conf')
 
2942
        self.id = 'bazaar'
2926
2943
 
2927
2944
 
2928
2945
class LocationStore(LockableIniFileStore):
2931
2948
        t = transport.get_transport_from_path(
2932
2949
            config_dir(), possible_transports=possible_transports)
2933
2950
        super(LocationStore, self).__init__(t, 'locations.conf')
 
2951
        self.id = 'locations'
2934
2952
 
2935
2953
 
2936
2954
class BranchStore(IniFileStore):
2939
2957
        super(BranchStore, self).__init__(branch.control_transport,
2940
2958
                                          'branch.conf')
2941
2959
        self.branch = branch
 
2960
        self.id = 'branch'
2942
2961
 
2943
2962
    def lock_write(self, token=None):
2944
2963
        return self.branch.lock_write(token)
2977
2996
        # This is where we require loading the store so we can see all defined
2978
2997
        # sections.
2979
2998
        sections = self.store.get_sections()
2980
 
        # Walk the revisions in the order provided
2981
 
        for s in sections:
 
2999
        # Walk the revisions in the provided order
 
3000
        for store, s in sections:
2982
3001
            if self.match(s):
2983
 
                yield s
 
3002
                yield store, s
2984
3003
 
2985
3004
    def match(self, section):
2986
3005
        """Does the proposed section match.
3010
3029
        self.extra_path = extra_path
3011
3030
        self.locals = {'relpath': extra_path}
3012
3031
 
3013
 
    def get(self, name, default=None):
 
3032
    def get(self, name, default=None, expand=True):
3014
3033
        value = super(LocationSection, self).get(name, default)
3015
 
        if value is not None:
 
3034
        if value is not None and expand:
3016
3035
            policy_name = self.get(name + ':policy', None)
3017
3036
            policy = _policy_value.get(policy_name, POLICY_NONE)
3018
3037
            if policy == POLICY_APPENDPATH:
3049
3068
        all_sections = []
3050
3069
        # Filter out the no_name_section so _iter_for_location_by_parts can be
3051
3070
        # used (it assumes all sections have a name).
3052
 
        for section in self.store.get_sections():
 
3071
        for _, section in self.store.get_sections():
3053
3072
            if section.id is None:
3054
3073
                no_name_section = section
3055
3074
            else:
3092
3111
            if ignore:
3093
3112
                break
3094
3113
            # Finally, we have a valid section
3095
 
            yield section
 
3114
            yield self.store, section
3096
3115
 
3097
3116
 
3098
3117
_option_ref_re = lazy_regex.lazy_compile('({[^{}]+})')
3115
3134
class Stack(object):
3116
3135
    """A stack of configurations where an option can be defined"""
3117
3136
 
3118
 
    def __init__(self, sections_def, store=None, mutable_section_name=None):
 
3137
    def __init__(self, sections_def, store=None, mutable_section_id=None):
3119
3138
        """Creates a stack of sections with an optional store for changes.
3120
3139
 
3121
3140
        :param sections_def: A list of Section or callables that returns an
3125
3144
        :param store: The optional Store where modifications will be
3126
3145
            recorded. If none is specified, no modifications can be done.
3127
3146
 
3128
 
        :param mutable_section_name: The name of the MutableSection where
3129
 
            changes are recorded. This requires the ``store`` parameter to be
 
3147
        :param mutable_section_id: The id of the MutableSection where changes
 
3148
            are recorded. This requires the ``store`` parameter to be
3130
3149
            specified.
3131
3150
        """
3132
3151
        self.sections_def = sections_def
3133
3152
        self.store = store
3134
 
        self.mutable_section_name = mutable_section_name
 
3153
        self.mutable_section_id = mutable_section_id
3135
3154
 
3136
3155
    def get(self, name, expand=None):
3137
3156
        """Return the *first* option value found in the sections.
3156
3175
        # implies querying the persistent storage) until it can't be avoided
3157
3176
        # anymore by using callables to describe (possibly empty) section
3158
3177
        # lists.
3159
 
        for section_or_callable in self.sections_def:
3160
 
            # Each section can expand to multiple ones when a callable is used
3161
 
            if callable(section_or_callable):
3162
 
                sections = section_or_callable()
3163
 
            else:
3164
 
                sections = [section_or_callable]
3165
 
            for section in sections:
 
3178
        for sections in self.sections_def:
 
3179
            for store, section in sections():
3166
3180
                value = section.get(name)
3167
3181
                if value is not None:
3168
3182
                    break
3269
3283
        This is where we guarantee that the mutable section is lazily loaded:
3270
3284
        this means we won't load the corresponding store before setting a value
3271
3285
        or deleting an option. In practice the store will often be loaded but
3272
 
        this allows helps catching some programming errors.
 
3286
        this helps catching some programming errors.
3273
3287
        """
3274
 
        section = self.store.get_mutable_section(self.mutable_section_name)
 
3288
        section = self.store.get_mutable_section(self.mutable_section_id)
3275
3289
        return section
3276
3290
 
3277
3291
    def set(self, name, value):
3295
3309
    def _get_overrides(self):
3296
3310
        # Hack around library_state.initialize never called
3297
3311
        if bzrlib.global_state is not None:
3298
 
            return [bzrlib.global_state.cmdline_overrides]
 
3312
            return bzrlib.global_state.cmdline_overrides.get_sections()
3299
3313
        return []
3300
3314
 
3301
3315
 
3308
3322
    One assumption made here is that the daughter classes will all use Stores
3309
3323
    derived from LockableIniFileStore).
3310
3324
 
3311
 
    It implements set() by re-loading the store before applying the
3312
 
    modification and saving it.
 
3325
    It implements set() and remove () by re-loading the store before applying
 
3326
    the modification and saving it.
3313
3327
 
3314
3328
    The long term plan being to implement a single write by store to save
3315
3329
    all modifications, this class should not be used in the interim.
3322
3336
        # Force a write to persistent storage
3323
3337
        self.store.save()
3324
3338
 
 
3339
    def remove(self, name):
 
3340
        # Force a reload
 
3341
        self.store.unload()
 
3342
        super(_CompatibleStack, self).remove(name)
 
3343
        # Force a write to persistent storage
 
3344
        self.store.save()
 
3345
 
3325
3346
 
3326
3347
class GlobalStack(_CompatibleStack):
3327
3348
    """Global options only stack."""
3331
3352
        gstore = GlobalStore()
3332
3353
        super(GlobalStack, self).__init__(
3333
3354
            [self._get_overrides, gstore.get_sections],
3334
 
            gstore)
 
3355
            gstore, mutable_section_id='DEFAULT')
3335
3356
 
3336
3357
 
3337
3358
class LocationStack(_CompatibleStack):
3342
3363
        
3343
3364
        :param location: A URL prefix to """
3344
3365
        lstore = LocationStore()
 
3366
        if location is not None:
 
3367
            location = urlutils.normalize_url(location)
 
3368
            if location.startswith('file://'):
 
3369
                location = urlutils.local_path_from_url(location)
3345
3370
        matcher = LocationMatcher(lstore, location)
3346
3371
        gstore = GlobalStore()
3347
3372
        super(LocationStack, self).__init__(
3348
3373
            [self._get_overrides,
3349
3374
             matcher.get_sections, gstore.get_sections],
3350
 
            lstore)
 
3375
            lstore, mutable_section_id=location)
3351
3376
 
3352
3377
 
3353
3378
class BranchStack(_CompatibleStack):
3386
3411
            bstore)
3387
3412
        self.branch = branch
3388
3413
 
 
3414
# Use a an empty dict to initialize an empty configobj avoiding all
 
3415
# parsing and encoding checks
 
3416
_quoting_config = configobj.ConfigObj(
 
3417
    {}, encoding='utf-8', interpolation=False)
3389
3418
 
3390
3419
class cmd_config(commands.Command):
3391
3420
    __doc__ = """Display, set or remove a configuration option.
3408
3437
    takes_options = [
3409
3438
        'directory',
3410
3439
        # FIXME: This should be a registry option so that plugins can register
3411
 
        # their own config files (or not) -- vila 20101002
 
3440
        # their own config files (or not) and will also address
 
3441
        # http://pad.lv/788991 -- vila 20101115
3412
3442
        commands.Option('scope', help='Reduce the scope to the specified'
3413
3443
                        ' configuration file',
3414
3444
                        type=unicode),
3452
3482
                # Set the option value
3453
3483
                self._set_config_option(name, value, directory, scope)
3454
3484
 
3455
 
    def _get_configs(self, directory, scope=None):
3456
 
        """Iterate the configurations specified by ``directory`` and ``scope``.
 
3485
    def _get_stack(self, directory, scope=None):
 
3486
        """Get the configuration stack specified by ``directory`` and ``scope``.
3457
3487
 
3458
3488
        :param directory: Where the configurations are derived from.
3459
3489
 
3460
3490
        :param scope: A specific config to start from.
3461
3491
        """
 
3492
        # FIXME: scope should allow access to plugin-specific stacks (even
 
3493
        # reduced to the plugin-specific store), related to
 
3494
        # http://pad.lv/788991 -- vila 2011-11-15
3462
3495
        if scope is not None:
3463
3496
            if scope == 'bazaar':
3464
 
                yield GlobalConfig()
 
3497
                return GlobalStack()
3465
3498
            elif scope == 'locations':
3466
 
                yield LocationConfig(directory)
 
3499
                return LocationStack(directory)
3467
3500
            elif scope == 'branch':
3468
3501
                (_, br, _) = (
3469
3502
                    controldir.ControlDir.open_containing_tree_or_branch(
3470
3503
                        directory))
3471
 
                yield br.get_config()
 
3504
                return br.get_config_stack()
 
3505
            raise errors.NoSuchConfig(scope)
3472
3506
        else:
3473
3507
            try:
3474
3508
                (_, br, _) = (
3475
3509
                    controldir.ControlDir.open_containing_tree_or_branch(
3476
3510
                        directory))
3477
 
                yield br.get_config()
 
3511
                return br.get_config_stack()
3478
3512
            except errors.NotBranchError:
3479
 
                yield LocationConfig(directory)
3480
 
                yield GlobalConfig()
 
3513
                return LocationStack(directory)
3481
3514
 
3482
3515
    def _show_value(self, name, directory, scope):
3483
 
        displayed = False
3484
 
        for c in self._get_configs(directory, scope):
3485
 
            if displayed:
3486
 
                break
3487
 
            for (oname, value, section, conf_id, parser) in c._get_options():
3488
 
                if name == oname:
3489
 
                    # Display only the first value and exit
3490
 
 
3491
 
                    # FIXME: We need to use get_user_option to take policies
3492
 
                    # into account and we need to make sure the option exists
3493
 
                    # too (hence the two for loops), this needs a better API
3494
 
                    # -- vila 20101117
3495
 
                    value = c.get_user_option(name)
3496
 
                    # Quote the value appropriately
3497
 
                    value = parser._quote(value)
3498
 
                    self.outf.write('%s\n' % (value,))
3499
 
                    displayed = True
3500
 
                    break
3501
 
        if not displayed:
 
3516
        conf = self._get_stack(directory, scope)
 
3517
        value = conf.get(name, expand=True)
 
3518
        if value is not None:
 
3519
            # Quote the value appropriately
 
3520
            value = _quoting_config._quote(value)
 
3521
            self.outf.write('%s\n' % (value,))
 
3522
        else:
3502
3523
            raise errors.NoSuchConfigOption(name)
3503
3524
 
3504
3525
    def _show_matching_options(self, name, directory, scope):
3507
3528
        # avoid the delay introduced by the lazy regexp.  But, we still do
3508
3529
        # want the nicer errors raised by lazy_regex.
3509
3530
        name._compile_and_collapse()
3510
 
        cur_conf_id = None
 
3531
        cur_store_id = None
3511
3532
        cur_section = None
3512
 
        for c in self._get_configs(directory, scope):
3513
 
            for (oname, value, section, conf_id, parser) in c._get_options():
3514
 
                if name.search(oname):
3515
 
                    if cur_conf_id != conf_id:
3516
 
                        # Explain where the options are defined
3517
 
                        self.outf.write('%s:\n' % (conf_id,))
3518
 
                        cur_conf_id = conf_id
3519
 
                        cur_section = None
3520
 
                    if (section not in (None, 'DEFAULT')
3521
 
                        and cur_section != section):
3522
 
                        # Display the section if it's not the default (or only)
3523
 
                        # one.
3524
 
                        self.outf.write('  [%s]\n' % (section,))
3525
 
                        cur_section = section
3526
 
                    self.outf.write('  %s = %s\n' % (oname, value))
 
3533
        conf = self._get_stack(directory, scope)
 
3534
        for sections in conf.sections_def:
 
3535
            for store, section in sections():
 
3536
                for oname in section.iter_option_names():
 
3537
                    if name.search(oname):
 
3538
                        if cur_store_id != store.id:
 
3539
                            # Explain where the options are defined
 
3540
                            self.outf.write('%s:\n' % (store.id,))
 
3541
                            cur_store_id = store.id
 
3542
                            cur_section = None
 
3543
                        if (section.id not in (None, 'DEFAULT')
 
3544
                            and cur_section != section.id):
 
3545
                            # Display the section if it's not the default (or
 
3546
                            # only) one.
 
3547
                            self.outf.write('  [%s]\n' % (section.id,))
 
3548
                            cur_section = section.id
 
3549
                        value = section.get(oname, expand=False)
 
3550
                        value = _quoting_config._quote(value)
 
3551
                        self.outf.write('  %s = %s\n' % (oname, value))
3527
3552
 
3528
3553
    def _set_config_option(self, name, value, directory, scope):
3529
 
        for conf in self._get_configs(directory, scope):
3530
 
            conf.set_user_option(name, value)
3531
 
            break
3532
 
        else:
3533
 
            raise errors.NoSuchConfig(scope)
 
3554
        conf = self._get_stack(directory, scope)
 
3555
        conf.set(name, value)
3534
3556
 
3535
3557
    def _remove_config_option(self, name, directory, scope):
3536
3558
        if name is None:
3537
3559
            raise errors.BzrCommandError(
3538
3560
                '--remove expects an option to remove.')
3539
 
        removed = False
3540
 
        for conf in self._get_configs(directory, scope):
3541
 
            for (section_name, section, conf_id) in conf._get_sections():
3542
 
                if scope is not None and conf_id != scope:
3543
 
                    # Not the right configuration file
3544
 
                    continue
3545
 
                if name in section:
3546
 
                    if conf_id != conf.config_id():
3547
 
                        conf = self._get_configs(directory, conf_id).next()
3548
 
                    # We use the first section in the first config where the
3549
 
                    # option is defined to remove it
3550
 
                    conf.remove_user_option(name, section_name)
3551
 
                    removed = True
3552
 
                    break
3553
 
            break
3554
 
        else:
3555
 
            raise errors.NoSuchConfig(scope)
3556
 
        if not removed:
 
3561
        conf = self._get_stack(directory, scope)
 
3562
        try:
 
3563
            conf.remove(name)
 
3564
        except KeyError:
3557
3565
            raise errors.NoSuchConfigOption(name)
3558
3566
 
 
3567
 
3559
3568
# Test registries
3560
3569
#
3561
3570
# We need adapters that can build a Store or a Stack in a test context. Test