~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-05-28 00:25:32 UTC
  • mfrom: (5264.1.2 command-help-bug-177500)
  • Revision ID: pqm@pqm.ubuntu.com-20100528002532-9bzj1fajyxckd1rg
(lifeless) Stop raising at runtime when a command has no help,
 instead have a test in the test suite that checks all known command objects.
 (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#            and others
4
4
#
29
29
create_signatures=always|never|when-required(default)
30
30
gpg_signing_command=name-of-program
31
31
log_format=name-of-format
32
 
validate_signatures_in_log=true|false(default)
33
 
acceptable_keys=pattern1,pattern2
34
32
 
35
33
in locations.conf, you specify the url of a branch and options for it.
36
34
Wildcards may be used - * and ? as normal in shell completion. Options
41
39
email= as above
42
40
check_signatures= as above
43
41
create_signatures= as above.
44
 
validate_signatures_in_log=as above
45
 
acceptable_keys=as above
46
42
 
47
43
explanation of options
48
44
----------------------
49
45
editor - this option sets the pop up editor to use during commits.
50
46
email - this option sets the user id bzr will use when committing.
51
 
check_signatures - this option will control whether bzr will require good gpg
 
47
check_signatures - this option controls whether bzr will require good gpg
52
48
                   signatures, ignore them, or check them if they are
53
 
                   present.  Currently it is unused except that check_signatures
54
 
                   turns on create_signatures.
 
49
                   present.
55
50
create_signatures - this option controls whether bzr will always create
56
 
                    gpg signatures or not on commits.  There is an unused
57
 
                    option which in future is expected to work if               
58
 
                    branch settings require signatures.
 
51
                    gpg signatures, never create them, or create them if the
 
52
                    branch is configured to require them.
59
53
log_format - this option sets the default log format.  Possible values are
60
54
             long, short, line, or a plugin can register new formats.
61
 
validate_signatures_in_log - show GPG signature validity in log output
62
 
acceptable_keys - comma separated list of key patterns acceptable for
63
 
                  verify-signatures command
64
55
 
65
56
In bazaar.conf you can also define aliases in the ALIASES sections, example
66
57
 
72
63
"""
73
64
 
74
65
import os
75
 
import string
76
66
import sys
77
67
 
78
 
 
79
 
from bzrlib.decorators import needs_write_lock
80
68
from bzrlib.lazy_import import lazy_import
81
69
lazy_import(globals(), """
82
 
import fnmatch
 
70
import errno
 
71
from fnmatch import fnmatch
83
72
import re
84
73
from cStringIO import StringIO
85
74
 
 
75
import bzrlib
86
76
from bzrlib import (
87
 
    atomicfile,
88
 
    bzrdir,
89
77
    debug,
90
78
    errors,
91
 
    lazy_regex,
92
 
    lockdir,
93
79
    mail_client,
94
 
    mergetools,
95
80
    osutils,
 
81
    registry,
96
82
    symbol_versioning,
97
83
    trace,
98
 
    transport,
99
84
    ui,
100
85
    urlutils,
101
86
    win32utils,
102
87
    )
103
88
from bzrlib.util.configobj import configobj
104
89
""")
105
 
from bzrlib import (
106
 
    commands,
107
 
    hooks,
108
 
    registry,
109
 
    )
110
 
from bzrlib.symbol_versioning import (
111
 
    deprecated_in,
112
 
    deprecated_method,
113
 
    )
114
90
 
115
91
 
116
92
CHECK_IF_POSSIBLE=0
146
122
STORE_BRANCH = 3
147
123
STORE_GLOBAL = 4
148
124
 
149
 
 
150
 
class ConfigObj(configobj.ConfigObj):
151
 
 
152
 
    def __init__(self, infile=None, **kwargs):
153
 
        # We define our own interpolation mechanism calling it option expansion
154
 
        super(ConfigObj, self).__init__(infile=infile,
155
 
                                        interpolation=False,
156
 
                                        **kwargs)
157
 
 
158
 
    def get_bool(self, section, key):
159
 
        return self[section].as_bool(key)
160
 
 
161
 
    def get_value(self, section, name):
162
 
        # Try [] for the old DEFAULT section.
163
 
        if section == "DEFAULT":
164
 
            try:
165
 
                return self[name]
166
 
            except KeyError:
167
 
                pass
168
 
        return self[section][name]
169
 
 
170
 
 
171
 
# FIXME: Until we can guarantee that each config file is loaded once and
172
 
# only once for a given bzrlib session, we don't want to re-read the file every
173
 
# time we query for an option so we cache the value (bad ! watch out for tests
174
 
# needing to restore the proper value).This shouldn't be part of 2.4.0 final,
175
 
# yell at mgz^W vila and the RM if this is still present at that time
176
 
# -- vila 20110219
177
 
_expand_default_value = None
178
 
def _get_expand_default_value():
179
 
    global _expand_default_value
180
 
    if _expand_default_value is not None:
181
 
        return _expand_default_value
182
 
    conf = GlobalConfig()
183
 
    # Note that we must not use None for the expand value below or we'll run
184
 
    # into infinite recursion. Using False really would be quite silly ;)
185
 
    expand = conf.get_user_option_as_bool('bzr.config.expand', expand=True)
186
 
    if expand is None:
187
 
        # This is an opt-in feature, you *really* need to clearly say you want
188
 
        # to activate it !
189
 
        expand = False
190
 
    _expand_default_value = expand
191
 
    return expand
 
125
_ConfigObj = None
 
126
def ConfigObj(*args, **kwargs):
 
127
    global _ConfigObj
 
128
    if _ConfigObj is None:
 
129
        class ConfigObj(configobj.ConfigObj):
 
130
 
 
131
            def get_bool(self, section, key):
 
132
                return self[section].as_bool(key)
 
133
 
 
134
            def get_value(self, section, name):
 
135
                # Try [] for the old DEFAULT section.
 
136
                if section == "DEFAULT":
 
137
                    try:
 
138
                        return self[name]
 
139
                    except KeyError:
 
140
                        pass
 
141
                return self[section][name]
 
142
        _ConfigObj = ConfigObj
 
143
    return _ConfigObj(*args, **kwargs)
192
144
 
193
145
 
194
146
class Config(object):
197
149
    def __init__(self):
198
150
        super(Config, self).__init__()
199
151
 
200
 
    def config_id(self):
201
 
        """Returns a unique ID for the config."""
202
 
        raise NotImplementedError(self.config_id)
203
 
 
204
 
    @deprecated_method(deprecated_in((2, 4, 0)))
205
152
    def get_editor(self):
206
153
        """Get the users pop up editor."""
207
154
        raise NotImplementedError
214
161
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
215
162
                                             sys.stdout)
216
163
 
 
164
 
217
165
    def get_mail_client(self):
218
166
        """Get a mail client to use"""
219
167
        selected_client = self.get_user_option('mail_client')
230
178
    def _get_signing_policy(self):
231
179
        """Template method to override signature creation policy."""
232
180
 
233
 
    option_ref_re = None
234
 
 
235
 
    def expand_options(self, string, env=None):
236
 
        """Expand option references in the string in the configuration context.
237
 
 
238
 
        :param string: The string containing option to expand.
239
 
 
240
 
        :param env: An option dict defining additional configuration options or
241
 
            overriding existing ones.
242
 
 
243
 
        :returns: The expanded string.
244
 
        """
245
 
        return self._expand_options_in_string(string, env)
246
 
 
247
 
    def _expand_options_in_list(self, slist, env=None, _ref_stack=None):
248
 
        """Expand options in  a list of strings in the configuration context.
249
 
 
250
 
        :param slist: A list of strings.
251
 
 
252
 
        :param env: An option dict defining additional configuration options or
253
 
            overriding existing ones.
254
 
 
255
 
        :param _ref_stack: Private list containing the options being
256
 
            expanded to detect loops.
257
 
 
258
 
        :returns: The flatten list of expanded strings.
259
 
        """
260
 
        # expand options in each value separately flattening lists
261
 
        result = []
262
 
        for s in slist:
263
 
            value = self._expand_options_in_string(s, env, _ref_stack)
264
 
            if isinstance(value, list):
265
 
                result.extend(value)
266
 
            else:
267
 
                result.append(value)
268
 
        return result
269
 
 
270
 
    def _expand_options_in_string(self, string, env=None, _ref_stack=None):
271
 
        """Expand options in the string in the configuration context.
272
 
 
273
 
        :param string: The string to be expanded.
274
 
 
275
 
        :param env: An option dict defining additional configuration options or
276
 
            overriding existing ones.
277
 
 
278
 
        :param _ref_stack: Private list containing the options being
279
 
            expanded to detect loops.
280
 
 
281
 
        :returns: The expanded string.
282
 
        """
283
 
        if string is None:
284
 
            # Not much to expand there
285
 
            return None
286
 
        if _ref_stack is None:
287
 
            # What references are currently resolved (to detect loops)
288
 
            _ref_stack = []
289
 
        if self.option_ref_re is None:
290
 
            # We want to match the most embedded reference first (i.e. for
291
 
            # '{{foo}}' we will get '{foo}',
292
 
            # for '{bar{baz}}' we will get '{baz}'
293
 
            self.option_ref_re = re.compile('({[^{}]+})')
294
 
        result = string
295
 
        # We need to iterate until no more refs appear ({{foo}} will need two
296
 
        # iterations for example).
297
 
        while True:
298
 
            raw_chunks = self.option_ref_re.split(result)
299
 
            if len(raw_chunks) == 1:
300
 
                # Shorcut the trivial case: no refs
301
 
                return result
302
 
            chunks = []
303
 
            list_value = False
304
 
            # Split will isolate refs so that every other chunk is a ref
305
 
            chunk_is_ref = False
306
 
            for chunk in raw_chunks:
307
 
                if not chunk_is_ref:
308
 
                    if chunk:
309
 
                        # Keep only non-empty strings (or we get bogus empty
310
 
                        # slots when a list value is involved).
311
 
                        chunks.append(chunk)
312
 
                    chunk_is_ref = True
313
 
                else:
314
 
                    name = chunk[1:-1]
315
 
                    if name in _ref_stack:
316
 
                        raise errors.OptionExpansionLoop(string, _ref_stack)
317
 
                    _ref_stack.append(name)
318
 
                    value = self._expand_option(name, env, _ref_stack)
319
 
                    if value is None:
320
 
                        raise errors.ExpandingUnknownOption(name, string)
321
 
                    if isinstance(value, list):
322
 
                        list_value = True
323
 
                        chunks.extend(value)
324
 
                    else:
325
 
                        chunks.append(value)
326
 
                    _ref_stack.pop()
327
 
                    chunk_is_ref = False
328
 
            if list_value:
329
 
                # Once a list appears as the result of an expansion, all
330
 
                # callers will get a list result. This allows a consistent
331
 
                # behavior even when some options in the expansion chain
332
 
                # defined as strings (no comma in their value) but their
333
 
                # expanded value is a list.
334
 
                return self._expand_options_in_list(chunks, env, _ref_stack)
335
 
            else:
336
 
                result = ''.join(chunks)
337
 
        return result
338
 
 
339
 
    def _expand_option(self, name, env, _ref_stack):
340
 
        if env is not None and name in env:
341
 
            # Special case, values provided in env takes precedence over
342
 
            # anything else
343
 
            value = env[name]
344
 
        else:
345
 
            # FIXME: This is a limited implementation, what we really need is a
346
 
            # way to query the bzr config for the value of an option,
347
 
            # respecting the scope rules (That is, once we implement fallback
348
 
            # configs, getting the option value should restart from the top
349
 
            # config, not the current one) -- vila 20101222
350
 
            value = self.get_user_option(name, expand=False)
351
 
            if isinstance(value, list):
352
 
                value = self._expand_options_in_list(value, env, _ref_stack)
353
 
            else:
354
 
                value = self._expand_options_in_string(value, env, _ref_stack)
355
 
        return value
356
 
 
357
181
    def _get_user_option(self, option_name):
358
182
        """Template method to provide a user option."""
359
183
        return None
360
184
 
361
 
    def get_user_option(self, option_name, expand=None):
362
 
        """Get a generic option - no special process, no default.
363
 
 
364
 
        :param option_name: The queried option.
365
 
 
366
 
        :param expand: Whether options references should be expanded.
367
 
 
368
 
        :returns: The value of the option.
369
 
        """
370
 
        if expand is None:
371
 
            expand = _get_expand_default_value()
372
 
        value = self._get_user_option(option_name)
373
 
        if expand:
374
 
            if isinstance(value, list):
375
 
                value = self._expand_options_in_list(value)
376
 
            elif isinstance(value, dict):
377
 
                trace.warning('Cannot expand "%s":'
378
 
                              ' Dicts do not support option expansion'
379
 
                              % (option_name,))
380
 
            else:
381
 
                value = self._expand_options_in_string(value)
382
 
        for hook in OldConfigHooks['get']:
383
 
            hook(self, option_name, value)
384
 
        return value
385
 
 
386
 
    def get_user_option_as_bool(self, option_name, expand=None, default=None):
387
 
        """Get a generic option as a boolean.
388
 
 
389
 
        :param expand: Allow expanding references to other config values.
390
 
        :param default: Default value if nothing is configured
 
185
    def get_user_option(self, option_name):
 
186
        """Get a generic option - no special process, no default."""
 
187
        return self._get_user_option(option_name)
 
188
 
 
189
    def get_user_option_as_bool(self, option_name):
 
190
        """Get a generic option as a boolean - no special process, no default.
 
191
 
391
192
        :return None if the option doesn't exist or its value can't be
392
193
            interpreted as a boolean. Returns True or False otherwise.
393
194
        """
394
 
        s = self.get_user_option(option_name, expand=expand)
 
195
        s = self._get_user_option(option_name)
395
196
        if s is None:
396
197
            # The option doesn't exist
397
 
            return default
 
198
            return None
398
199
        val = ui.bool_from_string(s)
399
200
        if val is None:
400
201
            # The value can't be interpreted as a boolean
402
203
                          s, option_name)
403
204
        return val
404
205
 
405
 
    def get_user_option_as_list(self, option_name, expand=None):
 
206
    def get_user_option_as_list(self, option_name):
406
207
        """Get a generic option as a list - no special process, no default.
407
208
 
408
209
        :return None if the option doesn't exist. Returns the value as a list
409
210
            otherwise.
410
211
        """
411
 
        l = self.get_user_option(option_name, expand=expand)
 
212
        l = self._get_user_option(option_name)
412
213
        if isinstance(l, (str, unicode)):
413
 
            # A single value, most probably the user forgot (or didn't care to
414
 
            # add) the final ','
 
214
            # A single value, most probably the user forgot the final ','
415
215
            l = [l]
416
216
        return l
417
217
 
437
237
        """See log_format()."""
438
238
        return None
439
239
 
440
 
    def validate_signatures_in_log(self):
441
 
        """Show GPG signature validity in log"""
442
 
        result = self._validate_signatures_in_log()
443
 
        if result == "true":
444
 
            result = True
445
 
        else:
446
 
            result = False
447
 
        return result
448
 
 
449
 
    def _validate_signatures_in_log(self):
450
 
        """See validate_signatures_in_log()."""
451
 
        return None
452
 
 
453
 
    def acceptable_keys(self):
454
 
        """Comma separated list of key patterns acceptable to 
455
 
        verify-signatures command"""
456
 
        result = self._acceptable_keys()
457
 
        return result
458
 
 
459
 
    def _acceptable_keys(self):
460
 
        """See acceptable_keys()."""
461
 
        return None
462
 
 
463
240
    def post_commit(self):
464
241
        """An ordered list of python functions to call.
465
242
 
484
261
        the concrete policy type is checked, and finally
485
262
        $EMAIL is examined.
486
263
        If no username can be found, errors.NoWhoami exception is raised.
 
264
 
 
265
        TODO: Check it's reasonably well-formed.
487
266
        """
488
267
        v = os.environ.get('BZR_EMAIL')
489
268
        if v:
490
269
            return v.decode(osutils.get_user_encoding())
 
270
 
491
271
        v = self._get_user_id()
492
272
        if v:
493
273
            return v
 
274
 
494
275
        v = os.environ.get('EMAIL')
495
276
        if v:
496
277
            return v.decode(osutils.get_user_encoding())
497
 
        name, email = _auto_user_id()
498
 
        if name and email:
499
 
            return '%s <%s>' % (name, email)
500
 
        elif email:
501
 
            return email
 
278
 
502
279
        raise errors.NoWhoami()
503
280
 
504
281
    def ensure_username(self):
528
305
        if policy is None:
529
306
            policy = self._get_signature_checking()
530
307
            if policy is not None:
531
 
                #this warning should go away once check_signatures is
532
 
                #implemented (if not before)
533
308
                trace.warning("Please use create_signatures,"
534
309
                              " not check_signatures to set signing policy.")
 
310
            if policy == CHECK_ALWAYS:
 
311
                return True
535
312
        elif policy == SIGN_ALWAYS:
536
313
            return True
537
314
        return False
570
347
        else:
571
348
            return True
572
349
 
573
 
    def get_merge_tools(self):
574
 
        tools = {}
575
 
        for (oname, value, section, conf_id, parser) in self._get_options():
576
 
            if oname.startswith('bzr.mergetool.'):
577
 
                tool_name = oname[len('bzr.mergetool.'):]
578
 
                tools[tool_name] = value
579
 
        trace.mutter('loaded merge tools: %r' % tools)
580
 
        return tools
581
 
 
582
 
    def find_merge_tool(self, name):
583
 
        # We fake a defaults mechanism here by checking if the given name can
584
 
        # be found in the known_merge_tools if it's not found in the config.
585
 
        # This should be done through the proposed config defaults mechanism
586
 
        # when it becomes available in the future.
587
 
        command_line = (self.get_user_option('bzr.mergetool.%s' % name,
588
 
                                             expand=False)
589
 
                        or mergetools.known_merge_tools.get(name, None))
590
 
        return command_line
591
 
 
592
 
 
593
 
class _ConfigHooks(hooks.Hooks):
594
 
    """A dict mapping hook names and a list of callables for configs.
595
 
    """
596
 
 
597
 
    def __init__(self):
598
 
        """Create the default hooks.
599
 
 
600
 
        These are all empty initially, because by default nothing should get
601
 
        notified.
602
 
        """
603
 
        super(_ConfigHooks, self).__init__('bzrlib.config', 'ConfigHooks')
604
 
        self.add_hook('load',
605
 
                      'Invoked when a config store is loaded.'
606
 
                      ' The signature is (store).',
607
 
                      (2, 4))
608
 
        self.add_hook('save',
609
 
                      'Invoked when a config store is saved.'
610
 
                      ' The signature is (store).',
611
 
                      (2, 4))
612
 
        # The hooks for config options
613
 
        self.add_hook('get',
614
 
                      'Invoked when a config option is read.'
615
 
                      ' The signature is (stack, name, value).',
616
 
                      (2, 4))
617
 
        self.add_hook('set',
618
 
                      'Invoked when a config option is set.'
619
 
                      ' The signature is (stack, name, value).',
620
 
                      (2, 4))
621
 
        self.add_hook('remove',
622
 
                      'Invoked when a config option is removed.'
623
 
                      ' The signature is (stack, name).',
624
 
                      (2, 4))
625
 
ConfigHooks = _ConfigHooks()
626
 
 
627
 
 
628
 
class _OldConfigHooks(hooks.Hooks):
629
 
    """A dict mapping hook names and a list of callables for configs.
630
 
    """
631
 
 
632
 
    def __init__(self):
633
 
        """Create the default hooks.
634
 
 
635
 
        These are all empty initially, because by default nothing should get
636
 
        notified.
637
 
        """
638
 
        super(_OldConfigHooks, self).__init__('bzrlib.config', 'OldConfigHooks')
639
 
        self.add_hook('load',
640
 
                      'Invoked when a config store is loaded.'
641
 
                      ' The signature is (config).',
642
 
                      (2, 4))
643
 
        self.add_hook('save',
644
 
                      'Invoked when a config store is saved.'
645
 
                      ' The signature is (config).',
646
 
                      (2, 4))
647
 
        # The hooks for config options
648
 
        self.add_hook('get',
649
 
                      'Invoked when a config option is read.'
650
 
                      ' The signature is (config, name, value).',
651
 
                      (2, 4))
652
 
        self.add_hook('set',
653
 
                      'Invoked when a config option is set.'
654
 
                      ' The signature is (config, name, value).',
655
 
                      (2, 4))
656
 
        self.add_hook('remove',
657
 
                      'Invoked when a config option is removed.'
658
 
                      ' The signature is (config, name).',
659
 
                      (2, 4))
660
 
OldConfigHooks = _OldConfigHooks()
661
 
 
662
350
 
663
351
class IniBasedConfig(Config):
664
352
    """A configuration policy that draws from ini files."""
665
353
 
666
 
    def __init__(self, get_filename=symbol_versioning.DEPRECATED_PARAMETER,
667
 
                 file_name=None):
668
 
        """Base class for configuration files using an ini-like syntax.
669
 
 
670
 
        :param file_name: The configuration file path.
671
 
        """
 
354
    def __init__(self, get_filename):
672
355
        super(IniBasedConfig, self).__init__()
673
 
        self.file_name = file_name
674
 
        if symbol_versioning.deprecated_passed(get_filename):
675
 
            symbol_versioning.warn(
676
 
                'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
677
 
                ' Use file_name instead.',
678
 
                DeprecationWarning,
679
 
                stacklevel=2)
680
 
            if get_filename is not None:
681
 
                self.file_name = get_filename()
682
 
        else:
683
 
            self.file_name = file_name
684
 
        self._content = None
 
356
        self._get_filename = get_filename
685
357
        self._parser = None
686
358
 
687
 
    @classmethod
688
 
    def from_string(cls, str_or_unicode, file_name=None, save=False):
689
 
        """Create a config object from a string.
690
 
 
691
 
        :param str_or_unicode: A string representing the file content. This will
692
 
            be utf-8 encoded.
693
 
 
694
 
        :param file_name: The configuration file path.
695
 
 
696
 
        :param _save: Whether the file should be saved upon creation.
697
 
        """
698
 
        conf = cls(file_name=file_name)
699
 
        conf._create_from_string(str_or_unicode, save)
700
 
        return conf
701
 
 
702
 
    def _create_from_string(self, str_or_unicode, save):
703
 
        self._content = StringIO(str_or_unicode.encode('utf-8'))
704
 
        # Some tests use in-memory configs, some other always need the config
705
 
        # file to exist on disk.
706
 
        if save:
707
 
            self._write_config_file()
708
 
 
709
 
    def _get_parser(self, file=symbol_versioning.DEPRECATED_PARAMETER):
 
359
    def _get_parser(self, file=None):
710
360
        if self._parser is not None:
711
361
            return self._parser
712
 
        if symbol_versioning.deprecated_passed(file):
713
 
            symbol_versioning.warn(
714
 
                'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
715
 
                ' Use IniBasedConfig(_content=xxx) instead.',
716
 
                DeprecationWarning,
717
 
                stacklevel=2)
718
 
        if self._content is not None:
719
 
            co_input = self._content
720
 
        elif self.file_name is None:
721
 
            raise AssertionError('We have no content to create the config')
 
362
        if file is None:
 
363
            input = self._get_filename()
722
364
        else:
723
 
            co_input = self.file_name
 
365
            input = file
724
366
        try:
725
 
            self._parser = ConfigObj(co_input, encoding='utf-8')
 
367
            self._parser = ConfigObj(input, encoding='utf-8')
726
368
        except configobj.ConfigObjError, e:
727
369
            raise errors.ParseConfigError(e.errors, e.config.filename)
728
 
        except UnicodeDecodeError:
729
 
            raise errors.ConfigContentError(self.file_name)
730
 
        # Make sure self.reload() will use the right file name
731
 
        self._parser.filename = self.file_name
732
 
        for hook in OldConfigHooks['load']:
733
 
            hook(self)
734
370
        return self._parser
735
371
 
736
 
    def reload(self):
737
 
        """Reload the config file from disk."""
738
 
        if self.file_name is None:
739
 
            raise AssertionError('We need a file name to reload the config')
740
 
        if self._parser is not None:
741
 
            self._parser.reload()
742
 
        for hook in ConfigHooks['load']:
743
 
            hook(self)
744
 
 
745
372
    def _get_matching_sections(self):
746
373
        """Return an ordered list of (section_name, extra_path) pairs.
747
374
 
758
385
        """Override this to define the section used by the config."""
759
386
        return "DEFAULT"
760
387
 
761
 
    def _get_sections(self, name=None):
762
 
        """Returns an iterator of the sections specified by ``name``.
763
 
 
764
 
        :param name: The section name. If None is supplied, the default
765
 
            configurations are yielded.
766
 
 
767
 
        :return: A tuple (name, section, config_id) for all sections that will
768
 
            be walked by user_get_option() in the 'right' order. The first one
769
 
            is where set_user_option() will update the value.
770
 
        """
771
 
        parser = self._get_parser()
772
 
        if name is not None:
773
 
            yield (name, parser[name], self.config_id())
774
 
        else:
775
 
            # No section name has been given so we fallback to the configobj
776
 
            # itself which holds the variables defined outside of any section.
777
 
            yield (None, parser, self.config_id())
778
 
 
779
 
    def _get_options(self, sections=None):
780
 
        """Return an ordered list of (name, value, section, config_id) tuples.
781
 
 
782
 
        All options are returned with their associated value and the section
783
 
        they appeared in. ``config_id`` is a unique identifier for the
784
 
        configuration file the option is defined in.
785
 
 
786
 
        :param sections: Default to ``_get_matching_sections`` if not
787
 
            specified. This gives a better control to daughter classes about
788
 
            which sections should be searched. This is a list of (name,
789
 
            configobj) tuples.
790
 
        """
791
 
        opts = []
792
 
        if sections is None:
793
 
            parser = self._get_parser()
794
 
            sections = []
795
 
            for (section_name, _) in self._get_matching_sections():
796
 
                try:
797
 
                    section = parser[section_name]
798
 
                except KeyError:
799
 
                    # This could happen for an empty file for which we define a
800
 
                    # DEFAULT section. FIXME: Force callers to provide sections
801
 
                    # instead ? -- vila 20100930
802
 
                    continue
803
 
                sections.append((section_name, section))
804
 
        config_id = self.config_id()
805
 
        for (section_name, section) in sections:
806
 
            for (name, value) in section.iteritems():
807
 
                yield (name, parser._quote(value), section_name,
808
 
                       config_id, parser)
809
 
 
810
388
    def _get_option_policy(self, section, option_name):
811
389
        """Return the policy for the given (section, option_name) pair."""
812
390
        return POLICY_NONE
863
441
        """See Config.log_format."""
864
442
        return self._get_user_option('log_format')
865
443
 
866
 
    def _validate_signatures_in_log(self):
867
 
        """See Config.validate_signatures_in_log."""
868
 
        return self._get_user_option('validate_signatures_in_log')
869
 
 
870
 
    def _acceptable_keys(self):
871
 
        """See Config.acceptable_keys."""
872
 
        return self._get_user_option('acceptable_keys')
873
 
 
874
444
    def _post_commit(self):
875
445
        """See Config.post_commit."""
876
446
        return self._get_user_option('post_commit')
907
477
    def _get_nickname(self):
908
478
        return self.get_user_option('nickname')
909
479
 
910
 
    def remove_user_option(self, option_name, section_name=None):
911
 
        """Remove a user option and save the configuration file.
912
 
 
913
 
        :param option_name: The option to be removed.
914
 
 
915
 
        :param section_name: The section the option is defined in, default to
916
 
            the default section.
917
 
        """
918
 
        self.reload()
919
 
        parser = self._get_parser()
920
 
        if section_name is None:
921
 
            section = parser
922
 
        else:
923
 
            section = parser[section_name]
 
480
    def _write_config_file(self):
 
481
        f = file(self._get_filename(), "wb")
924
482
        try:
925
 
            del section[option_name]
926
 
        except KeyError:
927
 
            raise errors.NoSuchConfigOption(option_name)
928
 
        self._write_config_file()
929
 
        for hook in OldConfigHooks['remove']:
930
 
            hook(self, option_name)
931
 
 
932
 
    def _write_config_file(self):
933
 
        if self.file_name is None:
934
 
            raise AssertionError('We cannot save, self.file_name is None')
935
 
        conf_dir = os.path.dirname(self.file_name)
936
 
        ensure_config_dir_exists(conf_dir)
937
 
        atomic_file = atomicfile.AtomicFile(self.file_name)
938
 
        self._get_parser().write(atomic_file)
939
 
        atomic_file.commit()
940
 
        atomic_file.close()
941
 
        osutils.copy_ownership_from_path(self.file_name)
942
 
        for hook in OldConfigHooks['save']:
943
 
            hook(self)
944
 
 
945
 
 
946
 
class LockableConfig(IniBasedConfig):
947
 
    """A configuration needing explicit locking for access.
948
 
 
949
 
    If several processes try to write the config file, the accesses need to be
950
 
    serialized.
951
 
 
952
 
    Daughter classes should decorate all methods that update a config with the
953
 
    ``@needs_write_lock`` decorator (they call, directly or indirectly, the
954
 
    ``_write_config_file()`` method. These methods (typically ``set_option()``
955
 
    and variants must reload the config file from disk before calling
956
 
    ``_write_config_file()``), this can be achieved by calling the
957
 
    ``self.reload()`` method. Note that the lock scope should cover both the
958
 
    reading and the writing of the config file which is why the decorator can't
959
 
    be applied to ``_write_config_file()`` only.
960
 
 
961
 
    This should be enough to implement the following logic:
962
 
    - lock for exclusive write access,
963
 
    - reload the config file from disk,
964
 
    - set the new value
965
 
    - unlock
966
 
 
967
 
    This logic guarantees that a writer can update a value without erasing an
968
 
    update made by another writer.
969
 
    """
970
 
 
971
 
    lock_name = 'lock'
972
 
 
973
 
    def __init__(self, file_name):
974
 
        super(LockableConfig, self).__init__(file_name=file_name)
975
 
        self.dir = osutils.dirname(osutils.safe_unicode(self.file_name))
976
 
        # FIXME: It doesn't matter that we don't provide possible_transports
977
 
        # below since this is currently used only for local config files ;
978
 
        # local transports are not shared. But if/when we start using
979
 
        # LockableConfig for other kind of transports, we will need to reuse
980
 
        # whatever connection is already established -- vila 20100929
981
 
        self.transport = transport.get_transport(self.dir)
982
 
        self._lock = lockdir.LockDir(self.transport, self.lock_name)
983
 
 
984
 
    def _create_from_string(self, unicode_bytes, save):
985
 
        super(LockableConfig, self)._create_from_string(unicode_bytes, False)
986
 
        if save:
987
 
            # We need to handle the saving here (as opposed to IniBasedConfig)
988
 
            # to be able to lock
989
 
            self.lock_write()
990
 
            self._write_config_file()
991
 
            self.unlock()
992
 
 
993
 
    def lock_write(self, token=None):
994
 
        """Takes a write lock in the directory containing the config file.
995
 
 
996
 
        If the directory doesn't exist it is created.
997
 
        """
998
 
        ensure_config_dir_exists(self.dir)
999
 
        return self._lock.lock_write(token)
1000
 
 
1001
 
    def unlock(self):
1002
 
        self._lock.unlock()
1003
 
 
1004
 
    def break_lock(self):
1005
 
        self._lock.break_lock()
1006
 
 
1007
 
    @needs_write_lock
1008
 
    def remove_user_option(self, option_name, section_name=None):
1009
 
        super(LockableConfig, self).remove_user_option(option_name,
1010
 
                                                       section_name)
1011
 
 
1012
 
    def _write_config_file(self):
1013
 
        if self._lock is None or not self._lock.is_held:
1014
 
            # NB: if the following exception is raised it probably means a
1015
 
            # missing @needs_write_lock decorator on one of the callers.
1016
 
            raise errors.ObjectNotLocked(self)
1017
 
        super(LockableConfig, self)._write_config_file()
1018
 
 
1019
 
 
1020
 
class GlobalConfig(LockableConfig):
 
483
            osutils.copy_ownership_from_path(f.name)
 
484
            self._get_parser().write(f)
 
485
        finally:
 
486
            f.close()
 
487
 
 
488
 
 
489
class GlobalConfig(IniBasedConfig):
1021
490
    """The configuration that should be used for a specific location."""
1022
491
 
1023
 
    def __init__(self):
1024
 
        super(GlobalConfig, self).__init__(file_name=config_filename())
1025
 
 
1026
 
    def config_id(self):
1027
 
        return 'bazaar'
1028
 
 
1029
 
    @classmethod
1030
 
    def from_string(cls, str_or_unicode, save=False):
1031
 
        """Create a config object from a string.
1032
 
 
1033
 
        :param str_or_unicode: A string representing the file content. This
1034
 
            will be utf-8 encoded.
1035
 
 
1036
 
        :param save: Whether the file should be saved upon creation.
1037
 
        """
1038
 
        conf = cls()
1039
 
        conf._create_from_string(str_or_unicode, save)
1040
 
        return conf
1041
 
 
1042
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1043
492
    def get_editor(self):
1044
493
        return self._get_user_option('editor')
1045
494
 
1046
 
    @needs_write_lock
 
495
    def __init__(self):
 
496
        super(GlobalConfig, self).__init__(config_filename)
 
497
 
1047
498
    def set_user_option(self, option, value):
1048
499
        """Save option and its value in the configuration."""
1049
500
        self._set_option(option, value, 'DEFAULT')
1055
506
        else:
1056
507
            return {}
1057
508
 
1058
 
    @needs_write_lock
1059
509
    def set_alias(self, alias_name, alias_command):
1060
510
        """Save the alias in the configuration."""
1061
511
        self._set_option(alias_name, alias_command, 'ALIASES')
1062
512
 
1063
 
    @needs_write_lock
1064
513
    def unset_alias(self, alias_name):
1065
514
        """Unset an existing alias."""
1066
 
        self.reload()
1067
515
        aliases = self._get_parser().get('ALIASES')
1068
516
        if not aliases or alias_name not in aliases:
1069
517
            raise errors.NoSuchAlias(alias_name)
1071
519
        self._write_config_file()
1072
520
 
1073
521
    def _set_option(self, option, value, section):
1074
 
        self.reload()
 
522
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
523
        # file lock on bazaar.conf.
 
524
        conf_dir = os.path.dirname(self._get_filename())
 
525
        ensure_config_dir_exists(conf_dir)
1075
526
        self._get_parser().setdefault(section, {})[option] = value
1076
527
        self._write_config_file()
1077
 
        for hook in OldConfigHooks['set']:
1078
 
            hook(self, option, value)
1079
 
 
1080
 
    def _get_sections(self, name=None):
1081
 
        """See IniBasedConfig._get_sections()."""
1082
 
        parser = self._get_parser()
1083
 
        # We don't give access to options defined outside of any section, we
1084
 
        # used the DEFAULT section by... default.
1085
 
        if name in (None, 'DEFAULT'):
1086
 
            # This could happen for an empty file where the DEFAULT section
1087
 
            # doesn't exist yet. So we force DEFAULT when yielding
1088
 
            name = 'DEFAULT'
1089
 
            if 'DEFAULT' not in parser:
1090
 
               parser['DEFAULT']= {}
1091
 
        yield (name, parser[name], self.config_id())
1092
 
 
1093
 
    @needs_write_lock
1094
 
    def remove_user_option(self, option_name, section_name=None):
1095
 
        if section_name is None:
1096
 
            # We need to force the default section.
1097
 
            section_name = 'DEFAULT'
1098
 
        # We need to avoid the LockableConfig implementation or we'll lock
1099
 
        # twice
1100
 
        super(LockableConfig, self).remove_user_option(option_name,
1101
 
                                                       section_name)
1102
 
 
1103
 
def _iter_for_location_by_parts(sections, location):
1104
 
    """Keep only the sessions matching the specified location.
1105
 
 
1106
 
    :param sections: An iterable of section names.
1107
 
 
1108
 
    :param location: An url or a local path to match against.
1109
 
 
1110
 
    :returns: An iterator of (section, extra_path, nb_parts) where nb is the
1111
 
        number of path components in the section name, section is the section
1112
 
        name and extra_path is the difference between location and the section
1113
 
        name.
1114
 
 
1115
 
    ``location`` will always be a local path and never a 'file://' url but the
1116
 
    section names themselves can be in either form.
1117
 
    """
1118
 
    location_parts = location.rstrip('/').split('/')
1119
 
 
1120
 
    for section in sections:
1121
 
        # location is a local path if possible, so we need to convert 'file://'
1122
 
        # urls in section names to local paths if necessary.
1123
 
 
1124
 
        # This also avoids having file:///path be a more exact
1125
 
        # match than '/path'.
1126
 
 
1127
 
        # FIXME: This still raises an issue if a user defines both file:///path
1128
 
        # *and* /path. Should we raise an error in this case -- vila 20110505
1129
 
 
1130
 
        if section.startswith('file://'):
1131
 
            section_path = urlutils.local_path_from_url(section)
1132
 
        else:
1133
 
            section_path = section
1134
 
        section_parts = section_path.rstrip('/').split('/')
1135
 
 
1136
 
        matched = True
1137
 
        if len(section_parts) > len(location_parts):
1138
 
            # More path components in the section, they can't match
1139
 
            matched = False
1140
 
        else:
1141
 
            # Rely on zip truncating in length to the length of the shortest
1142
 
            # argument sequence.
1143
 
            names = zip(location_parts, section_parts)
1144
 
            for name in names:
1145
 
                if not fnmatch.fnmatch(name[0], name[1]):
1146
 
                    matched = False
1147
 
                    break
1148
 
        if not matched:
1149
 
            continue
1150
 
        # build the path difference between the section and the location
1151
 
        extra_path = '/'.join(location_parts[len(section_parts):])
1152
 
        yield section, extra_path, len(section_parts)
1153
 
 
1154
 
 
1155
 
class LocationConfig(LockableConfig):
 
528
 
 
529
 
 
530
class LocationConfig(IniBasedConfig):
1156
531
    """A configuration object that gives the policy for a location."""
1157
532
 
1158
533
    def __init__(self, location):
1159
 
        super(LocationConfig, self).__init__(
1160
 
            file_name=locations_config_filename())
 
534
        name_generator = locations_config_filename
 
535
        if (not os.path.exists(name_generator()) and
 
536
                os.path.exists(branches_config_filename())):
 
537
            if sys.platform == 'win32':
 
538
                trace.warning('Please rename %s to %s'
 
539
                              % (branches_config_filename(),
 
540
                                 locations_config_filename()))
 
541
            else:
 
542
                trace.warning('Please rename ~/.bazaar/branches.conf'
 
543
                              ' to ~/.bazaar/locations.conf')
 
544
            name_generator = branches_config_filename
 
545
        super(LocationConfig, self).__init__(name_generator)
1161
546
        # local file locations are looked up by local path, rather than
1162
547
        # by file url. This is because the config file is a user
1163
548
        # file, and we would rather not expose the user to file urls.
1165
550
            location = urlutils.local_path_from_url(location)
1166
551
        self.location = location
1167
552
 
1168
 
    def config_id(self):
1169
 
        return 'locations'
1170
 
 
1171
 
    @classmethod
1172
 
    def from_string(cls, str_or_unicode, location, save=False):
1173
 
        """Create a config object from a string.
1174
 
 
1175
 
        :param str_or_unicode: A string representing the file content. This will
1176
 
            be utf-8 encoded.
1177
 
 
1178
 
        :param location: The location url to filter the configuration.
1179
 
 
1180
 
        :param save: Whether the file should be saved upon creation.
1181
 
        """
1182
 
        conf = cls(location)
1183
 
        conf._create_from_string(str_or_unicode, save)
1184
 
        return conf
1185
 
 
1186
553
    def _get_matching_sections(self):
1187
554
        """Return an ordered list of section names matching this location."""
1188
 
        matches = list(_iter_for_location_by_parts(self._get_parser(),
1189
 
                                                   self.location))
1190
 
        # put the longest (aka more specific) locations first
1191
 
        matches.sort(
1192
 
            key=lambda (section, extra_path, length): (length, section),
1193
 
            reverse=True)
1194
 
        for (section, extra_path, length) in matches:
1195
 
            yield section, extra_path
 
555
        sections = self._get_parser()
 
556
        location_names = self.location.split('/')
 
557
        if self.location.endswith('/'):
 
558
            del location_names[-1]
 
559
        matches=[]
 
560
        for section in sections:
 
561
            # location is a local path if possible, so we need
 
562
            # to convert 'file://' urls to local paths if necessary.
 
563
            # This also avoids having file:///path be a more exact
 
564
            # match than '/path'.
 
565
            if section.startswith('file://'):
 
566
                section_path = urlutils.local_path_from_url(section)
 
567
            else:
 
568
                section_path = section
 
569
            section_names = section_path.split('/')
 
570
            if section.endswith('/'):
 
571
                del section_names[-1]
 
572
            names = zip(location_names, section_names)
 
573
            matched = True
 
574
            for name in names:
 
575
                if not fnmatch(name[0], name[1]):
 
576
                    matched = False
 
577
                    break
 
578
            if not matched:
 
579
                continue
 
580
            # so, for the common prefix they matched.
 
581
            # if section is longer, no match.
 
582
            if len(section_names) > len(location_names):
 
583
                continue
 
584
            matches.append((len(section_names), section,
 
585
                            '/'.join(location_names[len(section_names):])))
 
586
        matches.sort(reverse=True)
 
587
        sections = []
 
588
        for (length, section, extra_path) in matches:
 
589
            sections.append((section, extra_path))
1196
590
            # should we stop looking for parent configs here?
1197
591
            try:
1198
592
                if self._get_parser()[section].as_bool('ignore_parents'):
1199
593
                    break
1200
594
            except KeyError:
1201
595
                pass
1202
 
 
1203
 
    def _get_sections(self, name=None):
1204
 
        """See IniBasedConfig._get_sections()."""
1205
 
        # We ignore the name here as the only sections handled are named with
1206
 
        # the location path and we don't expose embedded sections either.
1207
 
        parser = self._get_parser()
1208
 
        for name, extra_path in self._get_matching_sections():
1209
 
            yield (name, parser[name], self.config_id())
 
596
        return sections
1210
597
 
1211
598
    def _get_option_policy(self, section, option_name):
1212
599
        """Return the policy for the given (section, option_name) pair."""
1256
643
            if policy_key in self._get_parser()[section]:
1257
644
                del self._get_parser()[section][policy_key]
1258
645
 
1259
 
    @needs_write_lock
1260
646
    def set_user_option(self, option, value, store=STORE_LOCATION):
1261
647
        """Save option and its value in the configuration."""
1262
648
        if store not in [STORE_LOCATION,
1264
650
                         STORE_LOCATION_APPENDPATH]:
1265
651
            raise ValueError('bad storage policy %r for %r' %
1266
652
                (store, option))
1267
 
        self.reload()
 
653
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
654
        # file lock on locations.conf.
 
655
        conf_dir = os.path.dirname(self._get_filename())
 
656
        ensure_config_dir_exists(conf_dir)
1268
657
        location = self.location
1269
658
        if location.endswith('/'):
1270
659
            location = location[:-1]
1271
 
        parser = self._get_parser()
1272
 
        if not location in parser and not location + '/' in parser:
1273
 
            parser[location] = {}
1274
 
        elif location + '/' in parser:
 
660
        if (not location in self._get_parser() and
 
661
            not location + '/' in self._get_parser()):
 
662
            self._get_parser()[location]={}
 
663
        elif location + '/' in self._get_parser():
1275
664
            location = location + '/'
1276
 
        parser[location][option]=value
 
665
        self._get_parser()[location][option]=value
1277
666
        # the allowed values of store match the config policies
1278
667
        self._set_option_policy(location, option, store)
1279
668
        self._write_config_file()
1280
 
        for hook in OldConfigHooks['set']:
1281
 
            hook(self, option, value)
1282
669
 
1283
670
 
1284
671
class BranchConfig(Config):
1285
672
    """A configuration object giving the policy for a branch."""
1286
673
 
1287
 
    def __init__(self, branch):
1288
 
        super(BranchConfig, self).__init__()
1289
 
        self._location_config = None
1290
 
        self._branch_data_config = None
1291
 
        self._global_config = None
1292
 
        self.branch = branch
1293
 
        self.option_sources = (self._get_location_config,
1294
 
                               self._get_branch_data_config,
1295
 
                               self._get_global_config)
1296
 
 
1297
 
    def config_id(self):
1298
 
        return 'branch'
1299
 
 
1300
674
    def _get_branch_data_config(self):
1301
675
        if self._branch_data_config is None:
1302
676
            self._branch_data_config = TreeConfig(self.branch)
1303
 
            self._branch_data_config.config_id = self.config_id
1304
677
        return self._branch_data_config
1305
678
 
1306
679
    def _get_location_config(self):
1374
747
                return value
1375
748
        return None
1376
749
 
1377
 
    def _get_sections(self, name=None):
1378
 
        """See IniBasedConfig.get_sections()."""
1379
 
        for source in self.option_sources:
1380
 
            for section in source()._get_sections(name):
1381
 
                yield section
1382
 
 
1383
 
    def _get_options(self, sections=None):
1384
 
        opts = []
1385
 
        # First the locations options
1386
 
        for option in self._get_location_config()._get_options():
1387
 
            yield option
1388
 
        # Then the branch options
1389
 
        branch_config = self._get_branch_data_config()
1390
 
        if sections is None:
1391
 
            sections = [('DEFAULT', branch_config._get_parser())]
1392
 
        # FIXME: We shouldn't have to duplicate the code in IniBasedConfig but
1393
 
        # Config itself has no notion of sections :( -- vila 20101001
1394
 
        config_id = self.config_id()
1395
 
        for (section_name, section) in sections:
1396
 
            for (name, value) in section.iteritems():
1397
 
                yield (name, value, section_name,
1398
 
                       config_id, branch_config._get_parser())
1399
 
        # Then the global options
1400
 
        for option in self._get_global_config()._get_options():
1401
 
            yield option
1402
 
 
1403
750
    def set_user_option(self, name, value, store=STORE_BRANCH,
1404
751
        warn_masked=False):
1405
752
        if store == STORE_BRANCH:
1423
770
                        trace.warning('Value "%s" is masked by "%s" from'
1424
771
                                      ' branch.conf', value, mask_value)
1425
772
 
1426
 
    def remove_user_option(self, option_name, section_name=None):
1427
 
        self._get_branch_data_config().remove_option(option_name, section_name)
1428
 
 
1429
773
    def _gpg_signing_command(self):
1430
774
        """See Config.gpg_signing_command."""
1431
775
        return self._get_safe_value('_gpg_signing_command')
1432
776
 
 
777
    def __init__(self, branch):
 
778
        super(BranchConfig, self).__init__()
 
779
        self._location_config = None
 
780
        self._branch_data_config = None
 
781
        self._global_config = None
 
782
        self.branch = branch
 
783
        self.option_sources = (self._get_location_config,
 
784
                               self._get_branch_data_config,
 
785
                               self._get_global_config)
 
786
 
1433
787
    def _post_commit(self):
1434
788
        """See Config.post_commit."""
1435
789
        return self._get_safe_value('_post_commit')
1451
805
        """See Config.log_format."""
1452
806
        return self._get_best_value('_log_format')
1453
807
 
1454
 
    def _validate_signatures_in_log(self):
1455
 
        """See Config.validate_signatures_in_log."""
1456
 
        return self._get_best_value('_validate_signatures_in_log')
1457
 
 
1458
 
    def _acceptable_keys(self):
1459
 
        """See Config.acceptable_keys."""
1460
 
        return self._get_best_value('_acceptable_keys')
1461
 
 
1462
808
 
1463
809
def ensure_config_dir_exists(path=None):
1464
810
    """Make sure a configuration directory exists.
1473
819
            parent_dir = os.path.dirname(path)
1474
820
            if not os.path.isdir(parent_dir):
1475
821
                trace.mutter('creating config parent directory: %r', parent_dir)
1476
 
                os.mkdir(parent_dir)
 
822
            os.mkdir(parent_dir)
1477
823
        trace.mutter('creating config directory: %r', path)
1478
824
        os.mkdir(path)
1479
825
        osutils.copy_ownership_from_path(path)
1482
828
def config_dir():
1483
829
    """Return per-user configuration directory.
1484
830
 
1485
 
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
1486
 
    and Linux.  On Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
1487
 
    that will be used instead.
 
831
    By default this is ~/.bazaar/
1488
832
 
1489
833
    TODO: Global option --config-dir to override this.
1490
834
    """
1491
835
    base = os.environ.get('BZR_HOME', None)
1492
836
    if sys.platform == 'win32':
1493
 
        # environ variables on Windows are in user encoding/mbcs. So decode
1494
 
        # before using one
1495
 
        if base is not None:
1496
 
            base = base.decode('mbcs')
1497
837
        if base is None:
1498
838
            base = win32utils.get_appdata_location_unicode()
1499
839
        if base is None:
1500
840
            base = os.environ.get('HOME', None)
1501
 
            if base is not None:
1502
 
                base = base.decode('mbcs')
1503
841
        if base is None:
1504
842
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
1505
843
                                  ' or HOME set')
1506
844
        return osutils.pathjoin(base, 'bazaar', '2.0')
1507
 
    elif sys.platform == 'darwin':
1508
 
        if base is None:
1509
 
            # this takes into account $HOME
1510
 
            base = os.path.expanduser("~")
1511
 
        return osutils.pathjoin(base, '.bazaar')
1512
845
    else:
 
846
        # cygwin, linux, and darwin all have a $HOME directory
1513
847
        if base is None:
1514
 
 
1515
 
            xdg_dir = os.environ.get('XDG_CONFIG_HOME', None)
1516
 
            if xdg_dir is None:
1517
 
                xdg_dir = osutils.pathjoin(os.path.expanduser("~"), ".config")
1518
 
            xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
1519
 
            if osutils.isdir(xdg_dir):
1520
 
                trace.mutter(
1521
 
                    "Using configuration in XDG directory %s." % xdg_dir)
1522
 
                return xdg_dir
1523
 
 
1524
848
            base = os.path.expanduser("~")
1525
849
        return osutils.pathjoin(base, ".bazaar")
1526
850
 
1530
854
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
1531
855
 
1532
856
 
 
857
def branches_config_filename():
 
858
    """Return per-user configuration ini file filename."""
 
859
    return osutils.pathjoin(config_dir(), 'branches.conf')
 
860
 
 
861
 
1533
862
def locations_config_filename():
1534
863
    """Return per-user configuration ini file filename."""
1535
864
    return osutils.pathjoin(config_dir(), 'locations.conf')
1572
901
        return os.path.expanduser('~/.cache')
1573
902
 
1574
903
 
1575
 
def _get_default_mail_domain():
1576
 
    """If possible, return the assumed default email domain.
1577
 
 
1578
 
    :returns: string mail domain, or None.
1579
 
    """
1580
 
    if sys.platform == 'win32':
1581
 
        # No implementation yet; patches welcome
1582
 
        return None
1583
 
    try:
1584
 
        f = open('/etc/mailname')
1585
 
    except (IOError, OSError), e:
1586
 
        return None
1587
 
    try:
1588
 
        domain = f.read().strip()
1589
 
        return domain
1590
 
    finally:
1591
 
        f.close()
1592
 
 
1593
 
 
1594
 
def _auto_user_id():
1595
 
    """Calculate automatic user identification.
1596
 
 
1597
 
    :returns: (realname, email), either of which may be None if they can't be
1598
 
    determined.
1599
 
 
1600
 
    Only used when none is set in the environment or the id file.
1601
 
 
1602
 
    This only returns an email address if we can be fairly sure the 
1603
 
    address is reasonable, ie if /etc/mailname is set on unix.
1604
 
 
1605
 
    This doesn't use the FQDN as the default domain because that may be 
1606
 
    slow, and it doesn't use the hostname alone because that's not normally 
1607
 
    a reasonable address.
1608
 
    """
1609
 
    if sys.platform == 'win32':
1610
 
        # No implementation to reliably determine Windows default mail
1611
 
        # address; please add one.
1612
 
        return None, None
1613
 
 
1614
 
    default_mail_domain = _get_default_mail_domain()
1615
 
    if not default_mail_domain:
1616
 
        return None, None
1617
 
 
1618
 
    import pwd
1619
 
    uid = os.getuid()
1620
 
    try:
1621
 
        w = pwd.getpwuid(uid)
1622
 
    except KeyError:
1623
 
        trace.mutter('no passwd entry for uid %d?' % uid)
1624
 
        return None, None
1625
 
 
1626
 
    # we try utf-8 first, because on many variants (like Linux),
1627
 
    # /etc/passwd "should" be in utf-8, and because it's unlikely to give
1628
 
    # false positives.  (many users will have their user encoding set to
1629
 
    # latin-1, which cannot raise UnicodeError.)
1630
 
    try:
1631
 
        gecos = w.pw_gecos.decode('utf-8')
1632
 
        encoding = 'utf-8'
1633
 
    except UnicodeError:
1634
 
        try:
1635
 
            encoding = osutils.get_user_encoding()
1636
 
            gecos = w.pw_gecos.decode(encoding)
1637
 
        except UnicodeError, e:
1638
 
            trace.mutter("cannot decode passwd entry %s" % w)
1639
 
            return None, None
1640
 
    try:
1641
 
        username = w.pw_name.decode(encoding)
1642
 
    except UnicodeError, e:
1643
 
        trace.mutter("cannot decode passwd entry %s" % w)
1644
 
        return None, None
1645
 
 
1646
 
    comma = gecos.find(',')
1647
 
    if comma == -1:
1648
 
        realname = gecos
1649
 
    else:
1650
 
        realname = gecos[:comma]
1651
 
 
1652
 
    return realname, (username + '@' + default_mail_domain)
1653
 
 
1654
 
 
1655
904
def parse_username(username):
1656
905
    """Parse e-mail username and return a (name, address) tuple."""
1657
906
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1700
949
 
1701
950
    def set_option(self, value, name, section=None):
1702
951
        """Set a per-branch configuration option"""
1703
 
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
1704
 
        # higher levels providing the right lock -- vila 20101004
1705
952
        self.branch.lock_write()
1706
953
        try:
1707
954
            self._config.set_option(value, name, section)
1708
955
        finally:
1709
956
            self.branch.unlock()
1710
957
 
1711
 
    def remove_option(self, option_name, section_name=None):
1712
 
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
1713
 
        # higher levels providing the right lock -- vila 20101004
1714
 
        self.branch.lock_write()
1715
 
        try:
1716
 
            self._config.remove_option(option_name, section_name)
1717
 
        finally:
1718
 
            self.branch.unlock()
1719
 
 
1720
958
 
1721
959
class AuthenticationConfig(object):
1722
960
    """The authentication configuration file based on a ini file.
1748
986
            self._config = ConfigObj(self._input, encoding='utf-8')
1749
987
        except configobj.ConfigObjError, e:
1750
988
            raise errors.ParseConfigError(e.errors, e.config.filename)
1751
 
        except UnicodeError:
1752
 
            raise errors.ConfigContentError(self._filename)
1753
989
        return self._config
1754
990
 
1755
991
    def _save(self):
1772
1008
        section[option_name] = value
1773
1009
        self._save()
1774
1010
 
1775
 
    def get_credentials(self, scheme, host, port=None, user=None, path=None,
 
1011
    def get_credentials(self, scheme, host, port=None, user=None, path=None, 
1776
1012
                        realm=None):
1777
1013
        """Returns the matching credentials from authentication.conf file.
1778
1014
 
1946
1182
            if ask:
1947
1183
                if prompt is None:
1948
1184
                    # Create a default prompt suitable for most cases
1949
 
                    prompt = u'%s' % (scheme.upper(),) + u' %(host)s username'
 
1185
                    prompt = scheme.upper() + ' %(host)s username'
1950
1186
                # Special handling for optional fields in the prompt
1951
1187
                if port is not None:
1952
1188
                    prompt_host = '%s:%d' % (host, port)
1990
1226
        if password is None:
1991
1227
            if prompt is None:
1992
1228
                # Create a default prompt suitable for most cases
1993
 
                prompt = u'%s' % scheme.upper() + u' %(user)s@%(host)s password'
 
1229
                prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1994
1230
            # Special handling for optional fields in the prompt
1995
1231
            if port is not None:
1996
1232
                prompt_host = '%s:%d' % (host, port)
2167
1403
    """A Config that reads/writes a config file on a Transport.
2168
1404
 
2169
1405
    It is a low-level object that considers config data to be name/value pairs
2170
 
    that may be associated with a section.  Assigning meaning to these values
2171
 
    is done at higher levels like TreeConfig.
 
1406
    that may be associated with a section.  Assigning meaning to the these
 
1407
    values is done at higher levels like TreeConfig.
2172
1408
    """
2173
1409
 
2174
1410
    def __init__(self, transport, filename):
2191
1427
                section_obj = configobj[section]
2192
1428
            except KeyError:
2193
1429
                return default
2194
 
        value = section_obj.get(name, default)
2195
 
        for hook in OldConfigHooks['get']:
2196
 
            hook(self, name, value)
2197
 
        return value
 
1430
        return section_obj.get(name, default)
2198
1431
 
2199
1432
    def set_option(self, value, name, section=None):
2200
1433
        """Set the value associated with a named option.
2208
1441
            configobj[name] = value
2209
1442
        else:
2210
1443
            configobj.setdefault(section, {})[name] = value
2211
 
        for hook in OldConfigHooks['set']:
2212
 
            hook(self, name, value)
2213
 
        self._set_configobj(configobj)
2214
 
 
2215
 
    def remove_option(self, option_name, section_name=None):
2216
 
        configobj = self._get_configobj()
2217
 
        if section_name is None:
2218
 
            del configobj[option_name]
2219
 
        else:
2220
 
            del configobj[section_name][option_name]
2221
 
        for hook in OldConfigHooks['remove']:
2222
 
            hook(self, option_name)
2223
1444
        self._set_configobj(configobj)
2224
1445
 
2225
1446
    def _get_config_file(self):
2226
1447
        try:
2227
 
            f = StringIO(self._transport.get_bytes(self._filename))
2228
 
            for hook in OldConfigHooks['load']:
2229
 
                hook(self)
2230
 
            return f
 
1448
            return StringIO(self._transport.get_bytes(self._filename))
2231
1449
        except errors.NoSuchFile:
2232
1450
            return StringIO()
2233
1451
 
2234
 
    def _external_url(self):
2235
 
        return urlutils.join(self._transport.external_url(), self._filename)
2236
 
 
2237
1452
    def _get_configobj(self):
2238
1453
        f = self._get_config_file()
2239
1454
        try:
2240
 
            try:
2241
 
                conf = ConfigObj(f, encoding='utf-8')
2242
 
            except configobj.ConfigObjError, e:
2243
 
                raise errors.ParseConfigError(e.errors, self._external_url())
2244
 
            except UnicodeDecodeError:
2245
 
                raise errors.ConfigContentError(self._external_url())
 
1455
            return ConfigObj(f, encoding='utf-8')
2246
1456
        finally:
2247
1457
            f.close()
2248
 
        return conf
2249
1458
 
2250
1459
    def _set_configobj(self, configobj):
2251
1460
        out_file = StringIO()
2252
1461
        configobj.write(out_file)
2253
1462
        out_file.seek(0)
2254
1463
        self._transport.put_file(self._filename, out_file)
2255
 
        for hook in OldConfigHooks['save']:
2256
 
            hook(self)
2257
 
 
2258
 
 
2259
 
class Option(object):
2260
 
    """An option definition.
2261
 
 
2262
 
    The option *values* are stored in config files and found in sections.
2263
 
 
2264
 
    Here we define various properties about the option itself, its default
2265
 
    value, in which config files it can be stored, etc (TBC).
2266
 
    """
2267
 
 
2268
 
    def __init__(self, name, default=None):
2269
 
        self.name = name
2270
 
        self.default = default
2271
 
 
2272
 
    def get_default(self):
2273
 
        return self.default
2274
 
 
2275
 
 
2276
 
# Options registry
2277
 
 
2278
 
option_registry = registry.Registry()
2279
 
 
2280
 
 
2281
 
option_registry.register(
2282
 
    'editor', Option('editor'),
2283
 
    help='The command called to launch an editor to enter a message.')
2284
 
 
2285
 
 
2286
 
class Section(object):
2287
 
    """A section defines a dict of option name => value.
2288
 
 
2289
 
    This is merely a read-only dict which can add some knowledge about the
2290
 
    options. It is *not* a python dict object though and doesn't try to mimic
2291
 
    its API.
2292
 
    """
2293
 
 
2294
 
    def __init__(self, section_id, options):
2295
 
        self.id = section_id
2296
 
        # We re-use the dict-like object received
2297
 
        self.options = options
2298
 
 
2299
 
    def get(self, name, default=None):
2300
 
        return self.options.get(name, default)
2301
 
 
2302
 
    def __repr__(self):
2303
 
        # Mostly for debugging use
2304
 
        return "<config.%s id=%s>" % (self.__class__.__name__, self.id)
2305
 
 
2306
 
 
2307
 
_NewlyCreatedOption = object()
2308
 
"""Was the option created during the MutableSection lifetime"""
2309
 
 
2310
 
 
2311
 
class MutableSection(Section):
2312
 
    """A section allowing changes and keeping track of the original values."""
2313
 
 
2314
 
    def __init__(self, section_id, options):
2315
 
        super(MutableSection, self).__init__(section_id, options)
2316
 
        self.orig = {}
2317
 
 
2318
 
    def set(self, name, value):
2319
 
        if name not in self.options:
2320
 
            # This is a new option
2321
 
            self.orig[name] = _NewlyCreatedOption
2322
 
        elif name not in self.orig:
2323
 
            self.orig[name] = self.get(name, None)
2324
 
        self.options[name] = value
2325
 
 
2326
 
    def remove(self, name):
2327
 
        if name not in self.orig:
2328
 
            self.orig[name] = self.get(name, None)
2329
 
        del self.options[name]
2330
 
 
2331
 
 
2332
 
class Store(object):
2333
 
    """Abstract interface to persistent storage for configuration options."""
2334
 
 
2335
 
    readonly_section_class = Section
2336
 
    mutable_section_class = MutableSection
2337
 
 
2338
 
    def is_loaded(self):
2339
 
        """Returns True if the Store has been loaded.
2340
 
 
2341
 
        This is used to implement lazy loading and ensure the persistent
2342
 
        storage is queried only when needed.
2343
 
        """
2344
 
        raise NotImplementedError(self.is_loaded)
2345
 
 
2346
 
    def load(self):
2347
 
        """Loads the Store from persistent storage."""
2348
 
        raise NotImplementedError(self.load)
2349
 
 
2350
 
    def _load_from_string(self, bytes):
2351
 
        """Create a store from a string in configobj syntax.
2352
 
 
2353
 
        :param bytes: A string representing the file content.
2354
 
        """
2355
 
        raise NotImplementedError(self._load_from_string)
2356
 
 
2357
 
    def unload(self):
2358
 
        """Unloads the Store.
2359
 
 
2360
 
        This should make is_loaded() return False. This is used when the caller
2361
 
        knows that the persistent storage has changed or may have change since
2362
 
        the last load.
2363
 
        """
2364
 
        raise NotImplementedError(self.unload)
2365
 
 
2366
 
    def save(self):
2367
 
        """Saves the Store to persistent storage."""
2368
 
        raise NotImplementedError(self.save)
2369
 
 
2370
 
    def external_url(self):
2371
 
        raise NotImplementedError(self.external_url)
2372
 
 
2373
 
    def get_sections(self):
2374
 
        """Returns an ordered iterable of existing sections.
2375
 
 
2376
 
        :returns: An iterable of (name, dict).
2377
 
        """
2378
 
        raise NotImplementedError(self.get_sections)
2379
 
 
2380
 
    def get_mutable_section(self, section_name=None):
2381
 
        """Returns the specified mutable section.
2382
 
 
2383
 
        :param section_name: The section identifier
2384
 
        """
2385
 
        raise NotImplementedError(self.get_mutable_section)
2386
 
 
2387
 
    def __repr__(self):
2388
 
        # Mostly for debugging use
2389
 
        return "<config.%s(%s)>" % (self.__class__.__name__,
2390
 
                                    self.external_url())
2391
 
 
2392
 
 
2393
 
class IniFileStore(Store):
2394
 
    """A config Store using ConfigObj for storage.
2395
 
 
2396
 
    :ivar transport: The transport object where the config file is located.
2397
 
 
2398
 
    :ivar file_name: The config file basename in the transport directory.
2399
 
 
2400
 
    :ivar _config_obj: Private member to hold the ConfigObj instance used to
2401
 
        serialize/deserialize the config file.
2402
 
    """
2403
 
 
2404
 
    def __init__(self, transport, file_name):
2405
 
        """A config Store using ConfigObj for storage.
2406
 
 
2407
 
        :param transport: The transport object where the config file is located.
2408
 
 
2409
 
        :param file_name: The config file basename in the transport directory.
2410
 
        """
2411
 
        super(IniFileStore, self).__init__()
2412
 
        self.transport = transport
2413
 
        self.file_name = file_name
2414
 
        self._config_obj = None
2415
 
 
2416
 
    def is_loaded(self):
2417
 
        return self._config_obj != None
2418
 
 
2419
 
    def unload(self):
2420
 
        self._config_obj = None
2421
 
 
2422
 
    def load(self):
2423
 
        """Load the store from the associated file."""
2424
 
        if self.is_loaded():
2425
 
            return
2426
 
        content = self.transport.get_bytes(self.file_name)
2427
 
        self._load_from_string(content)
2428
 
        for hook in ConfigHooks['load']:
2429
 
            hook(self)
2430
 
 
2431
 
    def _load_from_string(self, bytes):
2432
 
        """Create a config store from a string.
2433
 
 
2434
 
        :param bytes: A string representing the file content.
2435
 
        """
2436
 
        if self.is_loaded():
2437
 
            raise AssertionError('Already loaded: %r' % (self._config_obj,))
2438
 
        co_input = StringIO(bytes)
2439
 
        try:
2440
 
            # The config files are always stored utf8-encoded
2441
 
            self._config_obj = ConfigObj(co_input, encoding='utf-8')
2442
 
        except configobj.ConfigObjError, e:
2443
 
            self._config_obj = None
2444
 
            raise errors.ParseConfigError(e.errors, self.external_url())
2445
 
        except UnicodeDecodeError:
2446
 
            raise errors.ConfigContentError(self.external_url())
2447
 
 
2448
 
    def save(self):
2449
 
        if not self.is_loaded():
2450
 
            # Nothing to save
2451
 
            return
2452
 
        out = StringIO()
2453
 
        self._config_obj.write(out)
2454
 
        self.transport.put_bytes(self.file_name, out.getvalue())
2455
 
        for hook in ConfigHooks['save']:
2456
 
            hook(self)
2457
 
 
2458
 
    def external_url(self):
2459
 
        # FIXME: external_url should really accepts an optional relpath
2460
 
        # parameter (bug #750169) :-/ -- vila 2011-04-04
2461
 
        # The following will do in the interim but maybe we don't want to
2462
 
        # expose a path here but rather a config ID and its associated
2463
 
        # object </hand wawe>.
2464
 
        return urlutils.join(self.transport.external_url(), self.file_name)
2465
 
 
2466
 
    def get_sections(self):
2467
 
        """Get the configobj section in the file order.
2468
 
 
2469
 
        :returns: An iterable of (name, dict).
2470
 
        """
2471
 
        # We need a loaded store
2472
 
        try:
2473
 
            self.load()
2474
 
        except errors.NoSuchFile:
2475
 
            # If the file doesn't exist, there is no sections
2476
 
            return
2477
 
        cobj = self._config_obj
2478
 
        if cobj.scalars:
2479
 
            yield self.readonly_section_class(None, cobj)
2480
 
        for section_name in cobj.sections:
2481
 
            yield self.readonly_section_class(section_name, cobj[section_name])
2482
 
 
2483
 
    def get_mutable_section(self, section_name=None):
2484
 
        # We need a loaded store
2485
 
        try:
2486
 
            self.load()
2487
 
        except errors.NoSuchFile:
2488
 
            # The file doesn't exist, let's pretend it was empty
2489
 
            self._load_from_string('')
2490
 
        if section_name is None:
2491
 
            section = self._config_obj
2492
 
        else:
2493
 
            section = self._config_obj.setdefault(section_name, {})
2494
 
        return self.mutable_section_class(section_name, section)
2495
 
 
2496
 
 
2497
 
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
2498
 
# unlockable stores for use with objects that can already ensure the locking
2499
 
# (think branches). If different stores (not based on ConfigObj) are created,
2500
 
# they may face the same issue.
2501
 
 
2502
 
 
2503
 
class LockableIniFileStore(IniFileStore):
2504
 
    """A ConfigObjStore using locks on save to ensure store integrity."""
2505
 
 
2506
 
    def __init__(self, transport, file_name, lock_dir_name=None):
2507
 
        """A config Store using ConfigObj for storage.
2508
 
 
2509
 
        :param transport: The transport object where the config file is located.
2510
 
 
2511
 
        :param file_name: The config file basename in the transport directory.
2512
 
        """
2513
 
        if lock_dir_name is None:
2514
 
            lock_dir_name = 'lock'
2515
 
        self.lock_dir_name = lock_dir_name
2516
 
        super(LockableIniFileStore, self).__init__(transport, file_name)
2517
 
        self._lock = lockdir.LockDir(self.transport, self.lock_dir_name)
2518
 
 
2519
 
    def lock_write(self, token=None):
2520
 
        """Takes a write lock in the directory containing the config file.
2521
 
 
2522
 
        If the directory doesn't exist it is created.
2523
 
        """
2524
 
        # FIXME: This doesn't check the ownership of the created directories as
2525
 
        # ensure_config_dir_exists does. It should if the transport is local
2526
 
        # -- vila 2011-04-06
2527
 
        self.transport.create_prefix()
2528
 
        return self._lock.lock_write(token)
2529
 
 
2530
 
    def unlock(self):
2531
 
        self._lock.unlock()
2532
 
 
2533
 
    def break_lock(self):
2534
 
        self._lock.break_lock()
2535
 
 
2536
 
    @needs_write_lock
2537
 
    def save(self):
2538
 
        # We need to be able to override the undecorated implementation
2539
 
        self.save_without_locking()
2540
 
 
2541
 
    def save_without_locking(self):
2542
 
        super(LockableIniFileStore, self).save()
2543
 
 
2544
 
 
2545
 
# FIXME: global, bazaar, shouldn't that be 'user' instead or even
2546
 
# 'user_defaults' as opposed to 'user_overrides', 'system_defaults'
2547
 
# (/etc/bzr/bazaar.conf) and 'system_overrides' ? -- vila 2011-04-05
2548
 
 
2549
 
# FIXME: Moreover, we shouldn't need classes for these stores either, factory
2550
 
# functions or a registry will make it easier and clearer for tests, focusing
2551
 
# on the relevant parts of the API that needs testing -- vila 20110503 (based
2552
 
# on a poolie's remark)
2553
 
class GlobalStore(LockableIniFileStore):
2554
 
 
2555
 
    def __init__(self, possible_transports=None):
2556
 
        t = transport.get_transport(config_dir(),
2557
 
                                    possible_transports=possible_transports)
2558
 
        super(GlobalStore, self).__init__(t, 'bazaar.conf')
2559
 
 
2560
 
 
2561
 
class LocationStore(LockableIniFileStore):
2562
 
 
2563
 
    def __init__(self, possible_transports=None):
2564
 
        t = transport.get_transport(config_dir(),
2565
 
                                    possible_transports=possible_transports)
2566
 
        super(LocationStore, self).__init__(t, 'locations.conf')
2567
 
 
2568
 
 
2569
 
class BranchStore(IniFileStore):
2570
 
 
2571
 
    def __init__(self, branch):
2572
 
        super(BranchStore, self).__init__(branch.control_transport,
2573
 
                                          'branch.conf')
2574
 
        self.branch = branch
2575
 
 
2576
 
    def lock_write(self, token=None):
2577
 
        return self.branch.lock_write(token)
2578
 
 
2579
 
    def unlock(self):
2580
 
        return self.branch.unlock()
2581
 
 
2582
 
    @needs_write_lock
2583
 
    def save(self):
2584
 
        # We need to be able to override the undecorated implementation
2585
 
        self.save_without_locking()
2586
 
 
2587
 
    def save_without_locking(self):
2588
 
        super(BranchStore, self).save()
2589
 
 
2590
 
 
2591
 
class SectionMatcher(object):
2592
 
    """Select sections into a given Store.
2593
 
 
2594
 
    This intended to be used to postpone getting an iterable of sections from a
2595
 
    store.
2596
 
    """
2597
 
 
2598
 
    def __init__(self, store):
2599
 
        self.store = store
2600
 
 
2601
 
    def get_sections(self):
2602
 
        # This is where we require loading the store so we can see all defined
2603
 
        # sections.
2604
 
        sections = self.store.get_sections()
2605
 
        # Walk the revisions in the order provided
2606
 
        for s in sections:
2607
 
            if self.match(s):
2608
 
                yield s
2609
 
 
2610
 
    def match(self, secion):
2611
 
        raise NotImplementedError(self.match)
2612
 
 
2613
 
 
2614
 
class LocationSection(Section):
2615
 
 
2616
 
    def __init__(self, section, length, extra_path):
2617
 
        super(LocationSection, self).__init__(section.id, section.options)
2618
 
        self.length = length
2619
 
        self.extra_path = extra_path
2620
 
 
2621
 
    def get(self, name, default=None):
2622
 
        value = super(LocationSection, self).get(name, default)
2623
 
        if value is not None:
2624
 
            policy_name = self.get(name + ':policy', None)
2625
 
            policy = _policy_value.get(policy_name, POLICY_NONE)
2626
 
            if policy == POLICY_APPENDPATH:
2627
 
                value = urlutils.join(value, self.extra_path)
2628
 
        return value
2629
 
 
2630
 
 
2631
 
class LocationMatcher(SectionMatcher):
2632
 
 
2633
 
    def __init__(self, store, location):
2634
 
        super(LocationMatcher, self).__init__(store)
2635
 
        if location.startswith('file://'):
2636
 
            location = urlutils.local_path_from_url(location)
2637
 
        self.location = location
2638
 
 
2639
 
    def _get_matching_sections(self):
2640
 
        """Get all sections matching ``location``."""
2641
 
        # We slightly diverge from LocalConfig here by allowing the no-name
2642
 
        # section as the most generic one and the lower priority.
2643
 
        no_name_section = None
2644
 
        sections = []
2645
 
        # Filter out the no_name_section so _iter_for_location_by_parts can be
2646
 
        # used (it assumes all sections have a name).
2647
 
        for section in self.store.get_sections():
2648
 
            if section.id is None:
2649
 
                no_name_section = section
2650
 
            else:
2651
 
                sections.append(section)
2652
 
        # Unfortunately _iter_for_location_by_parts deals with section names so
2653
 
        # we have to resync.
2654
 
        filtered_sections = _iter_for_location_by_parts(
2655
 
            [s.id for s in sections], self.location)
2656
 
        iter_sections = iter(sections)
2657
 
        matching_sections = []
2658
 
        if no_name_section is not None:
2659
 
            matching_sections.append(
2660
 
                LocationSection(no_name_section, 0, self.location))
2661
 
        for section_id, extra_path, length in filtered_sections:
2662
 
            # a section id is unique for a given store so it's safe to iterate
2663
 
            # again
2664
 
            section = iter_sections.next()
2665
 
            if section_id == section.id:
2666
 
                matching_sections.append(
2667
 
                    LocationSection(section, length, extra_path))
2668
 
        return matching_sections
2669
 
 
2670
 
    def get_sections(self):
2671
 
        # Override the default implementation as we want to change the order
2672
 
        matching_sections = self._get_matching_sections()
2673
 
        # We want the longest (aka more specific) locations first
2674
 
        sections = sorted(matching_sections,
2675
 
                          key=lambda section: (section.length, section.id),
2676
 
                          reverse=True)
2677
 
        # Sections mentioning 'ignore_parents' restrict the selection
2678
 
        for section in sections:
2679
 
            # FIXME: We really want to use as_bool below -- vila 2011-04-07
2680
 
            ignore = section.get('ignore_parents', None)
2681
 
            if ignore is not None:
2682
 
                ignore = ui.bool_from_string(ignore)
2683
 
            if ignore:
2684
 
                break
2685
 
            # Finally, we have a valid section
2686
 
            yield section
2687
 
 
2688
 
 
2689
 
class Stack(object):
2690
 
    """A stack of configurations where an option can be defined"""
2691
 
 
2692
 
    def __init__(self, sections_def, store=None, mutable_section_name=None):
2693
 
        """Creates a stack of sections with an optional store for changes.
2694
 
 
2695
 
        :param sections_def: A list of Section or callables that returns an
2696
 
            iterable of Section. This defines the Sections for the Stack and
2697
 
            can be called repeatedly if needed.
2698
 
 
2699
 
        :param store: The optional Store where modifications will be
2700
 
            recorded. If none is specified, no modifications can be done.
2701
 
 
2702
 
        :param mutable_section_name: The name of the MutableSection where
2703
 
            changes are recorded. This requires the ``store`` parameter to be
2704
 
            specified.
2705
 
        """
2706
 
        self.sections_def = sections_def
2707
 
        self.store = store
2708
 
        self.mutable_section_name = mutable_section_name
2709
 
 
2710
 
    def get(self, name):
2711
 
        """Return the *first* option value found in the sections.
2712
 
 
2713
 
        This is where we guarantee that sections coming from Store are loaded
2714
 
        lazily: the loading is delayed until we need to either check that an
2715
 
        option exists or get its value, which in turn may require to discover
2716
 
        in which sections it can be defined. Both of these (section and option
2717
 
        existence) require loading the store (even partially).
2718
 
        """
2719
 
        # FIXME: No caching of options nor sections yet -- vila 20110503
2720
 
        value = None
2721
 
        # Ensuring lazy loading is achieved by delaying section matching (which
2722
 
        # implies querying the persistent storage) until it can't be avoided
2723
 
        # anymore by using callables to describe (possibly empty) section
2724
 
        # lists.
2725
 
        for section_or_callable in self.sections_def:
2726
 
            # Each section can expand to multiple ones when a callable is used
2727
 
            if callable(section_or_callable):
2728
 
                sections = section_or_callable()
2729
 
            else:
2730
 
                sections = [section_or_callable]
2731
 
            for section in sections:
2732
 
                value = section.get(name)
2733
 
                if value is not None:
2734
 
                    break
2735
 
            if value is not None:
2736
 
                break
2737
 
        if value is None:
2738
 
            # If the option is registered, it may provide a default value
2739
 
            try:
2740
 
                opt = option_registry.get(name)
2741
 
            except KeyError:
2742
 
                # Not registered
2743
 
                opt = None
2744
 
            if opt is not None:
2745
 
                value = opt.get_default()
2746
 
        for hook in ConfigHooks['get']:
2747
 
            hook(self, name, value)
2748
 
        return value
2749
 
 
2750
 
    def _get_mutable_section(self):
2751
 
        """Get the MutableSection for the Stack.
2752
 
 
2753
 
        This is where we guarantee that the mutable section is lazily loaded:
2754
 
        this means we won't load the corresponding store before setting a value
2755
 
        or deleting an option. In practice the store will often be loaded but
2756
 
        this allows helps catching some programming errors.
2757
 
        """
2758
 
        section = self.store.get_mutable_section(self.mutable_section_name)
2759
 
        return section
2760
 
 
2761
 
    def set(self, name, value):
2762
 
        """Set a new value for the option."""
2763
 
        section = self._get_mutable_section()
2764
 
        section.set(name, value)
2765
 
        for hook in ConfigHooks['set']:
2766
 
            hook(self, name, value)
2767
 
 
2768
 
    def remove(self, name):
2769
 
        """Remove an existing option."""
2770
 
        section = self._get_mutable_section()
2771
 
        section.remove(name)
2772
 
        for hook in ConfigHooks['remove']:
2773
 
            hook(self, name)
2774
 
 
2775
 
    def __repr__(self):
2776
 
        # Mostly for debugging use
2777
 
        return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
2778
 
 
2779
 
 
2780
 
class _CompatibleStack(Stack):
2781
 
    """Place holder for compatibility with previous design.
2782
 
 
2783
 
    This is intended to ease the transition from the Config-based design to the
2784
 
    Stack-based design and should not be used nor relied upon by plugins.
2785
 
 
2786
 
    One assumption made here is that the daughter classes will all use Stores
2787
 
    derived from LockableIniFileStore).
2788
 
 
2789
 
    It implements set() by re-loading the store before applying the
2790
 
    modification and saving it.
2791
 
 
2792
 
    The long term plan being to implement a single write by store to save
2793
 
    all modifications, this class should not be used in the interim.
2794
 
    """
2795
 
 
2796
 
    def set(self, name, value):
2797
 
        # Force a reload
2798
 
        self.store.unload()
2799
 
        super(_CompatibleStack, self).set(name, value)
2800
 
        # Force a write to persistent storage
2801
 
        self.store.save()
2802
 
 
2803
 
 
2804
 
class GlobalStack(_CompatibleStack):
2805
 
 
2806
 
    def __init__(self):
2807
 
        # Get a GlobalStore
2808
 
        gstore = GlobalStore()
2809
 
        super(GlobalStack, self).__init__([gstore.get_sections], gstore)
2810
 
 
2811
 
 
2812
 
class LocationStack(_CompatibleStack):
2813
 
 
2814
 
    def __init__(self, location):
2815
 
        lstore = LocationStore()
2816
 
        matcher = LocationMatcher(lstore, location)
2817
 
        gstore = GlobalStore()
2818
 
        super(LocationStack, self).__init__(
2819
 
            [matcher.get_sections, gstore.get_sections], lstore)
2820
 
 
2821
 
class BranchStack(_CompatibleStack):
2822
 
 
2823
 
    def __init__(self, branch):
2824
 
        bstore = BranchStore(branch)
2825
 
        lstore = LocationStore()
2826
 
        matcher = LocationMatcher(lstore, branch.base)
2827
 
        gstore = GlobalStore()
2828
 
        super(BranchStack, self).__init__(
2829
 
            [matcher.get_sections, bstore.get_sections, gstore.get_sections],
2830
 
            bstore)
2831
 
        self.branch = branch
2832
 
 
2833
 
 
2834
 
class cmd_config(commands.Command):
2835
 
    __doc__ = """Display, set or remove a configuration option.
2836
 
 
2837
 
    Display the active value for a given option.
2838
 
 
2839
 
    If --all is specified, NAME is interpreted as a regular expression and all
2840
 
    matching options are displayed mentioning their scope. The active value
2841
 
    that bzr will take into account is the first one displayed for each option.
2842
 
 
2843
 
    If no NAME is given, --all .* is implied.
2844
 
 
2845
 
    Setting a value is achieved by using name=value without spaces. The value
2846
 
    is set in the most relevant scope and can be checked by displaying the
2847
 
    option again.
2848
 
    """
2849
 
 
2850
 
    takes_args = ['name?']
2851
 
 
2852
 
    takes_options = [
2853
 
        'directory',
2854
 
        # FIXME: This should be a registry option so that plugins can register
2855
 
        # their own config files (or not) -- vila 20101002
2856
 
        commands.Option('scope', help='Reduce the scope to the specified'
2857
 
                        ' configuration file',
2858
 
                        type=unicode),
2859
 
        commands.Option('all',
2860
 
            help='Display all the defined values for the matching options.',
2861
 
            ),
2862
 
        commands.Option('remove', help='Remove the option from'
2863
 
                        ' the configuration file'),
2864
 
        ]
2865
 
 
2866
 
    _see_also = ['configuration']
2867
 
 
2868
 
    @commands.display_command
2869
 
    def run(self, name=None, all=False, directory=None, scope=None,
2870
 
            remove=False):
2871
 
        if directory is None:
2872
 
            directory = '.'
2873
 
        directory = urlutils.normalize_url(directory)
2874
 
        if remove and all:
2875
 
            raise errors.BzrError(
2876
 
                '--all and --remove are mutually exclusive.')
2877
 
        elif remove:
2878
 
            # Delete the option in the given scope
2879
 
            self._remove_config_option(name, directory, scope)
2880
 
        elif name is None:
2881
 
            # Defaults to all options
2882
 
            self._show_matching_options('.*', directory, scope)
2883
 
        else:
2884
 
            try:
2885
 
                name, value = name.split('=', 1)
2886
 
            except ValueError:
2887
 
                # Display the option(s) value(s)
2888
 
                if all:
2889
 
                    self._show_matching_options(name, directory, scope)
2890
 
                else:
2891
 
                    self._show_value(name, directory, scope)
2892
 
            else:
2893
 
                if all:
2894
 
                    raise errors.BzrError(
2895
 
                        'Only one option can be set.')
2896
 
                # Set the option value
2897
 
                self._set_config_option(name, value, directory, scope)
2898
 
 
2899
 
    def _get_configs(self, directory, scope=None):
2900
 
        """Iterate the configurations specified by ``directory`` and ``scope``.
2901
 
 
2902
 
        :param directory: Where the configurations are derived from.
2903
 
 
2904
 
        :param scope: A specific config to start from.
2905
 
        """
2906
 
        if scope is not None:
2907
 
            if scope == 'bazaar':
2908
 
                yield GlobalConfig()
2909
 
            elif scope == 'locations':
2910
 
                yield LocationConfig(directory)
2911
 
            elif scope == 'branch':
2912
 
                (_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
2913
 
                    directory)
2914
 
                yield br.get_config()
2915
 
        else:
2916
 
            try:
2917
 
                (_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
2918
 
                    directory)
2919
 
                yield br.get_config()
2920
 
            except errors.NotBranchError:
2921
 
                yield LocationConfig(directory)
2922
 
                yield GlobalConfig()
2923
 
 
2924
 
    def _show_value(self, name, directory, scope):
2925
 
        displayed = False
2926
 
        for c in self._get_configs(directory, scope):
2927
 
            if displayed:
2928
 
                break
2929
 
            for (oname, value, section, conf_id, parser) in c._get_options():
2930
 
                if name == oname:
2931
 
                    # Display only the first value and exit
2932
 
 
2933
 
                    # FIXME: We need to use get_user_option to take policies
2934
 
                    # into account and we need to make sure the option exists
2935
 
                    # too (hence the two for loops), this needs a better API
2936
 
                    # -- vila 20101117
2937
 
                    value = c.get_user_option(name)
2938
 
                    # Quote the value appropriately
2939
 
                    value = parser._quote(value)
2940
 
                    self.outf.write('%s\n' % (value,))
2941
 
                    displayed = True
2942
 
                    break
2943
 
        if not displayed:
2944
 
            raise errors.NoSuchConfigOption(name)
2945
 
 
2946
 
    def _show_matching_options(self, name, directory, scope):
2947
 
        name = lazy_regex.lazy_compile(name)
2948
 
        # We want any error in the regexp to be raised *now* so we need to
2949
 
        # avoid the delay introduced by the lazy regexp.  But, we still do
2950
 
        # want the nicer errors raised by lazy_regex.
2951
 
        name._compile_and_collapse()
2952
 
        cur_conf_id = None
2953
 
        cur_section = None
2954
 
        for c in self._get_configs(directory, scope):
2955
 
            for (oname, value, section, conf_id, parser) in c._get_options():
2956
 
                if name.search(oname):
2957
 
                    if cur_conf_id != conf_id:
2958
 
                        # Explain where the options are defined
2959
 
                        self.outf.write('%s:\n' % (conf_id,))
2960
 
                        cur_conf_id = conf_id
2961
 
                        cur_section = None
2962
 
                    if (section not in (None, 'DEFAULT')
2963
 
                        and cur_section != section):
2964
 
                        # Display the section if it's not the default (or only)
2965
 
                        # one.
2966
 
                        self.outf.write('  [%s]\n' % (section,))
2967
 
                        cur_section = section
2968
 
                    self.outf.write('  %s = %s\n' % (oname, value))
2969
 
 
2970
 
    def _set_config_option(self, name, value, directory, scope):
2971
 
        for conf in self._get_configs(directory, scope):
2972
 
            conf.set_user_option(name, value)
2973
 
            break
2974
 
        else:
2975
 
            raise errors.NoSuchConfig(scope)
2976
 
 
2977
 
    def _remove_config_option(self, name, directory, scope):
2978
 
        if name is None:
2979
 
            raise errors.BzrCommandError(
2980
 
                '--remove expects an option to remove.')
2981
 
        removed = False
2982
 
        for conf in self._get_configs(directory, scope):
2983
 
            for (section_name, section, conf_id) in conf._get_sections():
2984
 
                if scope is not None and conf_id != scope:
2985
 
                    # Not the right configuration file
2986
 
                    continue
2987
 
                if name in section:
2988
 
                    if conf_id != conf.config_id():
2989
 
                        conf = self._get_configs(directory, conf_id).next()
2990
 
                    # We use the first section in the first config where the
2991
 
                    # option is defined to remove it
2992
 
                    conf.remove_user_option(name, section_name)
2993
 
                    removed = True
2994
 
                    break
2995
 
            break
2996
 
        else:
2997
 
            raise errors.NoSuchConfig(scope)
2998
 
        if not removed:
2999
 
            raise errors.NoSuchConfigOption(name)
3000
 
 
3001
 
# Test registries
3002
 
#
3003
 
# We need adapters that can build a Store or a Stack in a test context. Test
3004
 
# classes, based on TestCaseWithTransport, can use the registry to parametrize
3005
 
# themselves. The builder will receive a test instance and should return a
3006
 
# ready-to-use store or stack.  Plugins that define new store/stacks can also
3007
 
# register themselves here to be tested against the tests defined in
3008
 
# bzrlib.tests.test_config. Note that the builder can be called multiple times
3009
 
# for the same tests.
3010
 
 
3011
 
# The registered object should be a callable receiving a test instance
3012
 
# parameter (inheriting from tests.TestCaseWithTransport) and returning a Store
3013
 
# object.
3014
 
test_store_builder_registry = registry.Registry()
3015
 
 
3016
 
# The registered object should be a callable receiving a test instance
3017
 
# parameter (inheriting from tests.TestCaseWithTransport) and returning a Stack
3018
 
# object.
3019
 
test_stack_builder_registry = registry.Registry()