~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Robert Collins
  • Date: 2007-04-19 02:27:44 UTC
  • mto: This revision was merged to the branch mainline in revision 2426.
  • Revision ID: robertc@robertcollins.net-20070419022744-pfdqz42kp1wizh43
``make docs`` now creates a man page at ``man1/bzr.1`` fixing bug 107388.
(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, 2007 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#            and others
4
4
#
14
14
#
15
15
# You should have received a copy of the GNU General Public License
16
16
# along with this program; if not, write to the Free Software
17
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
 
19
19
"""Configuration that affects the behaviour of Bazaar.
20
20
 
37
37
[/home/robertc/source]
38
38
recurse=False|True(default)
39
39
email= as above
40
 
check_signatures= as above
 
40
check_signatures= as above 
41
41
create_signatures= as above.
42
42
 
43
43
explanation of options
45
45
editor - this option sets the pop up editor to use during commits.
46
46
email - this option sets the user id bzr will use when committing.
47
47
check_signatures - this option controls whether bzr will require good gpg
48
 
                   signatures, ignore them, or check them if they are
 
48
                   signatures, ignore them, or check them if they are 
49
49
                   present.
50
 
create_signatures - this option controls whether bzr will always create
 
50
create_signatures - this option controls whether bzr will always create 
51
51
                    gpg signatures, never create them, or create them if the
52
52
                    branch is configured to require them.
53
53
log_format - this option sets the default log format.  Possible values are
65
65
import os
66
66
import sys
67
67
 
68
 
from bzrlib import commands
69
 
from bzrlib.decorators import needs_write_lock
70
68
from bzrlib.lazy_import import lazy_import
71
69
lazy_import(globals(), """
72
70
import errno
73
 
import fnmatch
 
71
from fnmatch import fnmatch
74
72
import re
75
 
from cStringIO import StringIO
 
73
from StringIO import StringIO
76
74
 
77
75
import bzrlib
78
76
from bzrlib import (
79
 
    atomicfile,
80
 
    bzrdir,
81
 
    debug,
82
77
    errors,
83
 
    lockdir,
84
 
    mail_client,
85
 
    mergetools,
86
78
    osutils,
87
 
    registry,
88
79
    symbol_versioning,
89
 
    trace,
90
 
    transport,
91
 
    ui,
92
80
    urlutils,
93
81
    win32utils,
94
82
    )
95
 
from bzrlib.util.configobj import configobj
 
83
import bzrlib.util.configobj.configobj as configobj
96
84
""")
97
85
 
 
86
from bzrlib.trace import mutter, warning
 
87
 
98
88
 
99
89
CHECK_IF_POSSIBLE=0
100
90
CHECK_ALWAYS=1
132
122
 
133
123
class ConfigObj(configobj.ConfigObj):
134
124
 
135
 
    def __init__(self, infile=None, **kwargs):
136
 
        # We define our own interpolation mechanism
137
 
        super(ConfigObj, self).__init__(infile=infile,
138
 
                                        interpolation=False,
139
 
                                        **kwargs)
140
 
 
141
 
 
142
125
    def get_bool(self, section, key):
143
126
        return self[section].as_bool(key)
144
127
 
152
135
        return self[section][name]
153
136
 
154
137
 
155
 
 
156
138
class Config(object):
157
139
    """A configuration policy - what username, editor, gpg needs etc."""
158
140
 
159
 
    def __init__(self):
160
 
        super(Config, self).__init__()
161
 
 
162
 
    def config_id(self):
163
 
        """Returns a unique ID for the config."""
164
 
        raise NotImplementedError(self.config_id)
165
 
 
166
141
    def get_editor(self):
167
142
        """Get the users pop up editor."""
168
143
        raise NotImplementedError
169
144
 
170
 
    def get_change_editor(self, old_tree, new_tree):
171
 
        from bzrlib import diff
172
 
        cmd = self._get_change_editor()
173
 
        if cmd is None:
174
 
            return None
175
 
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
176
 
                                             sys.stdout)
177
 
 
178
 
 
179
 
    def get_mail_client(self):
180
 
        """Get a mail client to use"""
181
 
        selected_client = self.get_user_option('mail_client')
182
 
        _registry = mail_client.mail_client_registry
183
 
        try:
184
 
            mail_client_class = _registry.get(selected_client)
185
 
        except KeyError:
186
 
            raise errors.UnknownMailClient(selected_client)
187
 
        return mail_client_class(self)
188
 
 
189
145
    def _get_signature_checking(self):
190
146
        """Template method to override signature checking policy."""
191
147
 
192
148
    def _get_signing_policy(self):
193
149
        """Template method to override signature creation policy."""
194
150
 
195
 
    option_ref_re = None
196
 
 
197
 
    def interpolate(self, string, env=None):
198
 
        """Interpolate the string in the configuration context.
199
 
 
200
 
        :param string: The string to interpolate
201
 
 
202
 
        :param env: An option dict defining additional configuration options or
203
 
            overriding existing ones.
204
 
 
205
 
        :returns: The interpolated string.
206
 
        """
207
 
        return self._interpolate_string(string, env)
208
 
 
209
 
    def _interpolate_list(self, slist, env=None, _ref_stack=None):
210
 
        """Interpolate a list of strings in the configuration context.
211
 
 
212
 
        :param slist: A list of strings.
213
 
 
214
 
        :param env: An option dict defining additional configuration options or
215
 
            overriding existing ones.
216
 
 
217
 
        :param _ref_stack: Private list containing the options being
218
 
            interpolated to detect loops.
219
 
 
220
 
        :returns: The flatten list of interpolated strings.
221
 
        """
222
 
        # interpolate each value separately flattening lists
223
 
        result = []
224
 
        for s in slist:
225
 
            value = self._interpolate_string(s, env, _ref_stack)
226
 
            if isinstance(value, list):
227
 
                result.extend(value)
228
 
            else:
229
 
                result.append(value)
230
 
        return result
231
 
 
232
 
    def _interpolate_string(self, string, env=None, _ref_stack=None):
233
 
        """Interpolate the string in the configuration context.
234
 
 
235
 
        :param string: The string to interpolate
236
 
 
237
 
        :param env: An option dict defining additional configuration options or
238
 
            overriding existing ones.
239
 
 
240
 
        :param _ref_stack: Private list containing the options being
241
 
            interpolated to detect loops.
242
 
 
243
 
        :returns: The interpolated string.
244
 
        """
245
 
        if string is None:
246
 
            # Not much to interpolate there
247
 
            return None
248
 
        if _ref_stack is None:
249
 
            # What references are currently resolved (to detect loops)
250
 
            _ref_stack = []
251
 
        if self.option_ref_re is None:
252
 
            # We want to match the most embedded reference first (i.e. for
253
 
            # '{{foo}}' we will get '{foo}',
254
 
            # for '{bar{baz}}' we will get '{baz}'
255
 
            self.option_ref_re = re.compile('({[^{}]+})')
256
 
        result = string
257
 
        # We need to iterate until no more refs appear ({{foo}} will need two
258
 
        # iterations for example).
259
 
        while True:
260
 
            try:
261
 
                raw_chunks = self.option_ref_re.split(result)
262
 
            except TypeError:
263
 
                import pdb; pdb.set_trace()
264
 
            if len(raw_chunks) == 1:
265
 
                # Shorcut the trivial case: no refs
266
 
                return result
267
 
            chunks = []
268
 
            list_value = False
269
 
            # Split will isolate refs so that every other chunk is a ref
270
 
            chunk_is_ref = False
271
 
            for chunk in raw_chunks:
272
 
                if not chunk_is_ref:
273
 
                    if chunk:
274
 
                        # Keep only non-empty strings
275
 
                        chunks.append(chunk)
276
 
                    chunk_is_ref = True
277
 
                else:
278
 
                    name = chunk[1:-1]
279
 
                    if name in _ref_stack:
280
 
                        raise errors.InterpolationLoop(string, _ref_stack)
281
 
                    _ref_stack.append(name)
282
 
                    value = self._interpolate_option(name, env, _ref_stack)
283
 
                    if value is None:
284
 
                        raise errors.InterpolationUnknownOption(name, string)
285
 
                    if isinstance(value, list):
286
 
                        list_value = True
287
 
                        chunks.extend(value)
288
 
                    else:
289
 
                        chunks.append(value)
290
 
                    _ref_stack.pop()
291
 
                    chunk_is_ref = False
292
 
            if list_value:
293
 
                # Once a list appears as the result of an interpolation, all
294
 
                # callers will get a list result. This allows a consistent
295
 
                # behavior even when some options in the interpolation chain
296
 
                # may be seen defined as strings even if their interpolated
297
 
                # value is a list.
298
 
                return self._interpolate_list(chunks, env, _ref_stack)
299
 
            else:
300
 
                result = ''.join(chunks)
301
 
        return result
302
 
 
303
 
    def _interpolate_option(self, name, env, _ref_stack):
304
 
        if env is not None and name in env:
305
 
            # Special case, values provided in env takes precedence over
306
 
            # anything else
307
 
            value = env[name]
308
 
        else:
309
 
            # FIXME: This is a limited implementation, what we really need
310
 
            # is a way to query the bzr config for the value of an option,
311
 
            # respecting the scope rules -- vila 20101222
312
 
            value = self.get_user_option(name, interpolate=False)
313
 
            if isinstance(value, list):
314
 
                value = self._interpolate_list(value, env, _ref_stack)
315
 
            else:
316
 
                value = self._interpolate_string(value, env, _ref_stack)
317
 
        return value
318
 
 
319
151
    def _get_user_option(self, option_name):
320
152
        """Template method to provide a user option."""
321
153
        return None
322
154
 
323
 
    def get_user_option(self, option_name, interpolate=True):
 
155
    def get_user_option(self, option_name):
324
156
        """Get a generic option - no special process, no default."""
325
 
        value = self._get_user_option(option_name)
326
 
        if interpolate:
327
 
            if isinstance(value, list):
328
 
                value = self._interpolate_list(value)
329
 
            elif isinstance(value, dict):
330
 
                trace.warning('Cannot expand "%s":'
331
 
                              ' Dicts do not support option expansion'
332
 
                              % (option_name,))
333
 
            else:
334
 
                value = self._interpolate_string(value)
335
 
        return value
336
 
 
337
 
    def get_user_option_as_bool(self, option_name):
338
 
        """Get a generic option as a boolean - no special process, no default.
339
 
 
340
 
        :return None if the option doesn't exist or its value can't be
341
 
            interpreted as a boolean. Returns True or False otherwise.
342
 
        """
343
 
        s = self._get_user_option(option_name)
344
 
        if s is None:
345
 
            # The option doesn't exist
346
 
            return None
347
 
        val = ui.bool_from_string(s)
348
 
        if val is None:
349
 
            # The value can't be interpreted as a boolean
350
 
            trace.warning('Value "%s" is not a boolean for "%s"',
351
 
                          s, option_name)
352
 
        return val
353
 
 
354
 
    def get_user_option_as_list(self, option_name):
355
 
        """Get a generic option as a list - no special process, no default.
356
 
 
357
 
        :return None if the option doesn't exist. Returns the value as a list
358
 
            otherwise.
359
 
        """
360
 
        l = self._get_user_option(option_name)
361
 
        if isinstance(l, (str, unicode)):
362
 
            # A single value, most probably the user forgot (or didn't care to
363
 
            # add) the final ','
364
 
            l = [l]
365
 
        return l
 
157
        return self._get_user_option(option_name)
366
158
 
367
159
    def gpg_signing_command(self):
368
160
        """What program should be used to sign signatures?"""
386
178
        """See log_format()."""
387
179
        return None
388
180
 
 
181
    def __init__(self):
 
182
        super(Config, self).__init__()
 
183
 
389
184
    def post_commit(self):
390
185
        """An ordered list of python functions to call.
391
186
 
403
198
 
404
199
    def username(self):
405
200
        """Return email-style username.
406
 
 
 
201
    
407
202
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
408
 
 
409
 
        $BZR_EMAIL can be set to override this, then
 
203
        
 
204
        $BZR_EMAIL can be set to override this (as well as the
 
205
        deprecated $BZREMAIL), then
410
206
        the concrete policy type is checked, and finally
411
207
        $EMAIL is examined.
412
 
        If no username can be found, errors.NoWhoami exception is raised.
413
 
 
 
208
        If none is found, a reasonable default is (hopefully)
 
209
        created.
 
210
    
414
211
        TODO: Check it's reasonably well-formed.
415
212
        """
416
213
        v = os.environ.get('BZR_EMAIL')
417
214
        if v:
418
 
            return v.decode(osutils.get_user_encoding())
419
 
 
 
215
            return v.decode(bzrlib.user_encoding)
 
216
        v = os.environ.get('BZREMAIL')
 
217
        if v:
 
218
            warning('BZREMAIL is deprecated in favor of BZR_EMAIL. Please update your configuration.')
 
219
            return v.decode(bzrlib.user_encoding)
 
220
    
420
221
        v = self._get_user_id()
421
222
        if v:
422
223
            return v
423
 
 
 
224
        
424
225
        v = os.environ.get('EMAIL')
425
226
        if v:
426
 
            return v.decode(osutils.get_user_encoding())
427
 
 
428
 
        raise errors.NoWhoami()
429
 
 
430
 
    def ensure_username(self):
431
 
        """Raise errors.NoWhoami if username is not set.
432
 
 
433
 
        This method relies on the username() function raising the error.
434
 
        """
435
 
        self.username()
 
227
            return v.decode(bzrlib.user_encoding)
 
228
 
 
229
        name, email = _auto_user_id()
 
230
        if name:
 
231
            return '%s <%s>' % (name, email)
 
232
        else:
 
233
            return email
436
234
 
437
235
    def signature_checking(self):
438
236
        """What is the current policy for signature checking?."""
454
252
        if policy is None:
455
253
            policy = self._get_signature_checking()
456
254
            if policy is not None:
457
 
                trace.warning("Please use create_signatures,"
458
 
                              " not check_signatures to set signing policy.")
 
255
                warning("Please use create_signatures, not check_signatures "
 
256
                        "to set signing policy.")
459
257
            if policy == CHECK_ALWAYS:
460
258
                return True
461
259
        elif policy == SIGN_ALWAYS:
474
272
    def _get_nickname(self):
475
273
        return None
476
274
 
477
 
    def get_bzr_remote_path(self):
478
 
        try:
479
 
            return os.environ['BZR_REMOTE_PATH']
480
 
        except KeyError:
481
 
            path = self.get_user_option("bzr_remote_path")
482
 
            if path is None:
483
 
                path = 'bzr'
484
 
            return path
485
 
 
486
 
    def suppress_warning(self, warning):
487
 
        """Should the warning be suppressed or emitted.
488
 
 
489
 
        :param warning: The name of the warning being tested.
490
 
 
491
 
        :returns: True if the warning should be suppressed, False otherwise.
492
 
        """
493
 
        warnings = self.get_user_option_as_list('suppress_warnings')
494
 
        if warnings is None or warning not in warnings:
495
 
            return False
496
 
        else:
497
 
            return True
498
 
 
499
 
    def get_merge_tools(self):
500
 
        tools = {}
501
 
        for (oname, value, section, conf_id, parser) in self._get_options():
502
 
            if oname.startswith('bzr.mergetool.'):
503
 
                tool_name = oname[len('bzr.mergetool.'):]
504
 
                tools[tool_name] = value
505
 
        trace.mutter('loaded merge tools: %r' % tools)
506
 
        return tools
507
 
 
508
 
    def find_merge_tool(self, name):
509
 
        # We fake a defaults mechanism here by checking if the given name can 
510
 
        # be found in the known_merge_tools if it's not found in the config.
511
 
        # This should be done through the proposed config defaults mechanism
512
 
        # when it becomes available in the future.
513
 
        command_line = (self.get_user_option('bzr.mergetool.%s' % name,
514
 
                                             interpolate=False)
515
 
                        or mergetools.known_merge_tools.get(name, None))
516
 
        return command_line
517
 
 
518
275
 
519
276
class IniBasedConfig(Config):
520
277
    """A configuration policy that draws from ini files."""
521
278
 
522
 
    def __init__(self, get_filename=symbol_versioning.DEPRECATED_PARAMETER,
523
 
                 file_name=None):
524
 
        """Base class for configuration files using an ini-like syntax.
525
 
 
526
 
        :param file_name: The configuration file path.
527
 
        """
528
 
        super(IniBasedConfig, self).__init__()
529
 
        self.file_name = file_name
530
 
        if symbol_versioning.deprecated_passed(get_filename):
531
 
            symbol_versioning.warn(
532
 
                'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
533
 
                ' Use file_name instead.',
534
 
                DeprecationWarning,
535
 
                stacklevel=2)
536
 
            if get_filename is not None:
537
 
                self.file_name = get_filename()
538
 
        else:
539
 
            self.file_name = file_name
540
 
        self._content = None
541
 
        self._parser = None
542
 
 
543
 
    @classmethod
544
 
    def from_string(cls, str_or_unicode, file_name=None, save=False):
545
 
        """Create a config object from a string.
546
 
 
547
 
        :param str_or_unicode: A string representing the file content. This will
548
 
            be utf-8 encoded.
549
 
 
550
 
        :param file_name: The configuration file path.
551
 
 
552
 
        :param _save: Whether the file should be saved upon creation.
553
 
        """
554
 
        conf = cls(file_name=file_name)
555
 
        conf._create_from_string(str_or_unicode, save)
556
 
        return conf
557
 
 
558
 
    def _create_from_string(self, str_or_unicode, save):
559
 
        self._content = StringIO(str_or_unicode.encode('utf-8'))
560
 
        # Some tests use in-memory configs, some other always need the config
561
 
        # file to exist on disk.
562
 
        if save:
563
 
            self._write_config_file()
564
 
 
565
 
    def _get_parser(self, file=symbol_versioning.DEPRECATED_PARAMETER):
 
279
    def _get_parser(self, file=None):
566
280
        if self._parser is not None:
567
281
            return self._parser
568
 
        if symbol_versioning.deprecated_passed(file):
569
 
            symbol_versioning.warn(
570
 
                'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
571
 
                ' Use IniBasedConfig(_content=xxx) instead.',
572
 
                DeprecationWarning,
573
 
                stacklevel=2)
574
 
        if self._content is not None:
575
 
            co_input = self._content
576
 
        elif self.file_name is None:
577
 
            raise AssertionError('We have no content to create the config')
 
282
        if file is None:
 
283
            input = self._get_filename()
578
284
        else:
579
 
            co_input = self.file_name
 
285
            input = file
580
286
        try:
581
 
            self._parser = ConfigObj(co_input, encoding='utf-8')
 
287
            self._parser = ConfigObj(input, encoding='utf-8')
582
288
        except configobj.ConfigObjError, e:
583
289
            raise errors.ParseConfigError(e.errors, e.config.filename)
584
 
        # Make sure self.reload() will use the right file name
585
 
        self._parser.filename = self.file_name
586
290
        return self._parser
587
291
 
588
 
    def reload(self):
589
 
        """Reload the config file from disk."""
590
 
        if self.file_name is None:
591
 
            raise AssertionError('We need a file name to reload the config')
592
 
        if self._parser is not None:
593
 
            self._parser.reload()
594
 
 
595
292
    def _get_matching_sections(self):
596
293
        """Return an ordered list of (section_name, extra_path) pairs.
597
294
 
608
305
        """Override this to define the section used by the config."""
609
306
        return "DEFAULT"
610
307
 
611
 
    def _get_sections(self, name=None):
612
 
        """Returns an iterator of the sections specified by ``name``.
613
 
 
614
 
        :param name: The section name. If None is supplied, the default
615
 
            configurations are yielded.
616
 
 
617
 
        :return: A tuple (name, section, config_id) for all sections that will
618
 
            be walked by user_get_option() in the 'right' order. The first one
619
 
            is where set_user_option() will update the value.
620
 
        """
621
 
        parser = self._get_parser()
622
 
        if name is not None:
623
 
            yield (name, parser[name], self.config_id())
624
 
        else:
625
 
            # No section name has been given so we fallback to the configobj
626
 
            # itself which holds the variables defined outside of any section.
627
 
            yield (None, parser, self.config_id())
628
 
 
629
 
    def _get_options(self, sections=None):
630
 
        """Return an ordered list of (name, value, section, config_id) tuples.
631
 
 
632
 
        All options are returned with their associated value and the section
633
 
        they appeared in. ``config_id`` is a unique identifier for the
634
 
        configuration file the option is defined in.
635
 
 
636
 
        :param sections: Default to ``_get_matching_sections`` if not
637
 
            specified. This gives a better control to daughter classes about
638
 
            which sections should be searched. This is a list of (name,
639
 
            configobj) tuples.
640
 
        """
641
 
        opts = []
642
 
        if sections is None:
643
 
            parser = self._get_parser()
644
 
            sections = []
645
 
            for (section_name, _) in self._get_matching_sections():
646
 
                try:
647
 
                    section = parser[section_name]
648
 
                except KeyError:
649
 
                    # This could happen for an empty file for which we define a
650
 
                    # DEFAULT section. FIXME: Force callers to provide sections
651
 
                    # instead ? -- vila 20100930
652
 
                    continue
653
 
                sections.append((section_name, section))
654
 
        config_id = self.config_id()
655
 
        for (section_name, section) in sections:
656
 
            for (name, value) in section.iteritems():
657
 
                yield (name, parser._quote(value), section_name,
658
 
                       config_id, parser)
659
 
 
660
308
    def _get_option_policy(self, section, option_name):
661
309
        """Return the policy for the given (section, option_name) pair."""
662
310
        return POLICY_NONE
663
311
 
664
 
    def _get_change_editor(self):
665
 
        return self.get_user_option('change_editor')
666
 
 
667
312
    def _get_signature_checking(self):
668
313
        """See Config._get_signature_checking."""
669
314
        policy = self._get_user_option('check_signatures')
713
358
        """See Config.log_format."""
714
359
        return self._get_user_option('log_format')
715
360
 
 
361
    def __init__(self, get_filename):
 
362
        super(IniBasedConfig, self).__init__()
 
363
        self._get_filename = get_filename
 
364
        self._parser = None
 
365
        
716
366
    def _post_commit(self):
717
367
        """See Config.post_commit."""
718
368
        return self._get_user_option('post_commit')
741
391
 
742
392
    def _get_alias(self, value):
743
393
        try:
744
 
            return self._get_parser().get_value("ALIASES",
 
394
            return self._get_parser().get_value("ALIASES", 
745
395
                                                value)
746
396
        except KeyError:
747
397
            pass
749
399
    def _get_nickname(self):
750
400
        return self.get_user_option('nickname')
751
401
 
752
 
    def remove_user_option(self, option_name, section_name=None):
753
 
        """Remove a user option and save the configuration file.
754
 
 
755
 
        :param option_name: The option to be removed.
756
 
 
757
 
        :param section_name: The section the option is defined in, default to
758
 
            the default section.
759
 
        """
760
 
        self.reload()
761
 
        parser = self._get_parser()
762
 
        if section_name is None:
763
 
            section = parser
764
 
        else:
765
 
            section = parser[section_name]
766
 
        try:
767
 
            del section[option_name]
768
 
        except KeyError:
769
 
            raise errors.NoSuchConfigOption(option_name)
770
 
        self._write_config_file()
771
 
 
772
 
    def _write_config_file(self):
773
 
        if self.file_name is None:
774
 
            raise AssertionError('We cannot save, self.file_name is None')
775
 
        conf_dir = os.path.dirname(self.file_name)
776
 
        ensure_config_dir_exists(conf_dir)
777
 
        atomic_file = atomicfile.AtomicFile(self.file_name)
778
 
        self._get_parser().write(atomic_file)
779
 
        atomic_file.commit()
780
 
        atomic_file.close()
781
 
        osutils.copy_ownership_from_path(self.file_name)
782
 
 
783
 
 
784
 
class LockableConfig(IniBasedConfig):
785
 
    """A configuration needing explicit locking for access.
786
 
 
787
 
    If several processes try to write the config file, the accesses need to be
788
 
    serialized.
789
 
 
790
 
    Daughter classes should decorate all methods that update a config with the
791
 
    ``@needs_write_lock`` decorator (they call, directly or indirectly, the
792
 
    ``_write_config_file()`` method. These methods (typically ``set_option()``
793
 
    and variants must reload the config file from disk before calling
794
 
    ``_write_config_file()``), this can be achieved by calling the
795
 
    ``self.reload()`` method. Note that the lock scope should cover both the
796
 
    reading and the writing of the config file which is why the decorator can't
797
 
    be applied to ``_write_config_file()`` only.
798
 
 
799
 
    This should be enough to implement the following logic:
800
 
    - lock for exclusive write access,
801
 
    - reload the config file from disk,
802
 
    - set the new value
803
 
    - unlock
804
 
 
805
 
    This logic guarantees that a writer can update a value without erasing an
806
 
    update made by another writer.
807
 
    """
808
 
 
809
 
    lock_name = 'lock'
810
 
 
811
 
    def __init__(self, file_name):
812
 
        super(LockableConfig, self).__init__(file_name=file_name)
813
 
        self.dir = osutils.dirname(osutils.safe_unicode(self.file_name))
814
 
        # FIXME: It doesn't matter that we don't provide possible_transports
815
 
        # below since this is currently used only for local config files ;
816
 
        # local transports are not shared. But if/when we start using
817
 
        # LockableConfig for other kind of transports, we will need to reuse
818
 
        # whatever connection is already established -- vila 20100929
819
 
        self.transport = transport.get_transport(self.dir)
820
 
        self._lock = lockdir.LockDir(self.transport, 'lock')
821
 
 
822
 
    def _create_from_string(self, unicode_bytes, save):
823
 
        super(LockableConfig, self)._create_from_string(unicode_bytes, False)
824
 
        if save:
825
 
            # We need to handle the saving here (as opposed to IniBasedConfig)
826
 
            # to be able to lock
827
 
            self.lock_write()
828
 
            self._write_config_file()
829
 
            self.unlock()
830
 
 
831
 
    def lock_write(self, token=None):
832
 
        """Takes a write lock in the directory containing the config file.
833
 
 
834
 
        If the directory doesn't exist it is created.
835
 
        """
836
 
        ensure_config_dir_exists(self.dir)
837
 
        return self._lock.lock_write(token)
838
 
 
839
 
    def unlock(self):
840
 
        self._lock.unlock()
841
 
 
842
 
    def break_lock(self):
843
 
        self._lock.break_lock()
844
 
 
845
 
    @needs_write_lock
846
 
    def remove_user_option(self, option_name, section_name=None):
847
 
        super(LockableConfig, self).remove_user_option(option_name,
848
 
                                                       section_name)
849
 
 
850
 
    def _write_config_file(self):
851
 
        if self._lock is None or not self._lock.is_held:
852
 
            # NB: if the following exception is raised it probably means a
853
 
            # missing @needs_write_lock decorator on one of the callers.
854
 
            raise errors.ObjectNotLocked(self)
855
 
        super(LockableConfig, self)._write_config_file()
856
 
 
857
 
 
858
 
class GlobalConfig(LockableConfig):
 
402
 
 
403
class GlobalConfig(IniBasedConfig):
859
404
    """The configuration that should be used for a specific location."""
860
405
 
861
 
    def __init__(self):
862
 
        super(GlobalConfig, self).__init__(file_name=config_filename())
863
 
 
864
 
    def config_id(self):
865
 
        return 'bazaar'
866
 
 
867
 
    @classmethod
868
 
    def from_string(cls, str_or_unicode, save=False):
869
 
        """Create a config object from a string.
870
 
 
871
 
        :param str_or_unicode: A string representing the file content. This
872
 
            will be utf-8 encoded.
873
 
 
874
 
        :param save: Whether the file should be saved upon creation.
875
 
        """
876
 
        conf = cls()
877
 
        conf._create_from_string(str_or_unicode, save)
878
 
        return conf
879
 
 
880
406
    def get_editor(self):
881
407
        return self._get_user_option('editor')
882
408
 
883
 
    @needs_write_lock
 
409
    def __init__(self):
 
410
        super(GlobalConfig, self).__init__(config_filename)
 
411
 
884
412
    def set_user_option(self, option, value):
885
413
        """Save option and its value in the configuration."""
886
 
        self._set_option(option, value, 'DEFAULT')
887
 
 
888
 
    def get_aliases(self):
889
 
        """Return the aliases section."""
890
 
        if 'ALIASES' in self._get_parser():
891
 
            return self._get_parser()['ALIASES']
892
 
        else:
893
 
            return {}
894
 
 
895
 
    @needs_write_lock
896
 
    def set_alias(self, alias_name, alias_command):
897
 
        """Save the alias in the configuration."""
898
 
        self._set_option(alias_name, alias_command, 'ALIASES')
899
 
 
900
 
    @needs_write_lock
901
 
    def unset_alias(self, alias_name):
902
 
        """Unset an existing alias."""
903
 
        self.reload()
904
 
        aliases = self._get_parser().get('ALIASES')
905
 
        if not aliases or alias_name not in aliases:
906
 
            raise errors.NoSuchAlias(alias_name)
907
 
        del aliases[alias_name]
908
 
        self._write_config_file()
909
 
 
910
 
    def _set_option(self, option, value, section):
911
 
        self.reload()
912
 
        self._get_parser().setdefault(section, {})[option] = value
913
 
        self._write_config_file()
914
 
 
915
 
 
916
 
    def _get_sections(self, name=None):
917
 
        """See IniBasedConfig._get_sections()."""
918
 
        parser = self._get_parser()
919
 
        # We don't give access to options defined outside of any section, we
920
 
        # used the DEFAULT section by... default.
921
 
        if name in (None, 'DEFAULT'):
922
 
            # This could happen for an empty file where the DEFAULT section
923
 
            # doesn't exist yet. So we force DEFAULT when yielding
924
 
            name = 'DEFAULT'
925
 
            if 'DEFAULT' not in parser:
926
 
               parser['DEFAULT']= {}
927
 
        yield (name, parser[name], self.config_id())
928
 
 
929
 
    @needs_write_lock
930
 
    def remove_user_option(self, option_name, section_name=None):
931
 
        if section_name is None:
932
 
            # We need to force the default section.
933
 
            section_name = 'DEFAULT'
934
 
        # We need to avoid the LockableConfig implementation or we'll lock
935
 
        # twice
936
 
        super(LockableConfig, self).remove_user_option(option_name,
937
 
                                                       section_name)
938
 
 
939
 
 
940
 
class LocationConfig(LockableConfig):
 
414
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
415
        # file lock on bazaar.conf.
 
416
        conf_dir = os.path.dirname(self._get_filename())
 
417
        ensure_config_dir_exists(conf_dir)
 
418
        if 'DEFAULT' not in self._get_parser():
 
419
            self._get_parser()['DEFAULT'] = {}
 
420
        self._get_parser()['DEFAULT'][option] = value
 
421
        f = open(self._get_filename(), 'wb')
 
422
        self._get_parser().write(f)
 
423
        f.close()
 
424
 
 
425
 
 
426
class LocationConfig(IniBasedConfig):
941
427
    """A configuration object that gives the policy for a location."""
942
428
 
943
429
    def __init__(self, location):
944
 
        super(LocationConfig, self).__init__(
945
 
            file_name=locations_config_filename())
 
430
        name_generator = locations_config_filename
 
431
        if (not os.path.exists(name_generator()) and 
 
432
                os.path.exists(branches_config_filename())):
 
433
            if sys.platform == 'win32':
 
434
                warning('Please rename %s to %s' 
 
435
                         % (branches_config_filename(),
 
436
                            locations_config_filename()))
 
437
            else:
 
438
                warning('Please rename ~/.bazaar/branches.conf'
 
439
                        ' to ~/.bazaar/locations.conf')
 
440
            name_generator = branches_config_filename
 
441
        super(LocationConfig, self).__init__(name_generator)
946
442
        # local file locations are looked up by local path, rather than
947
443
        # by file url. This is because the config file is a user
948
444
        # file, and we would rather not expose the user to file urls.
950
446
            location = urlutils.local_path_from_url(location)
951
447
        self.location = location
952
448
 
953
 
    def config_id(self):
954
 
        return 'locations'
955
 
 
956
 
    @classmethod
957
 
    def from_string(cls, str_or_unicode, location, save=False):
958
 
        """Create a config object from a string.
959
 
 
960
 
        :param str_or_unicode: A string representing the file content. This will
961
 
            be utf-8 encoded.
962
 
 
963
 
        :param location: The location url to filter the configuration.
964
 
 
965
 
        :param save: Whether the file should be saved upon creation.
966
 
        """
967
 
        conf = cls(location)
968
 
        conf._create_from_string(str_or_unicode, save)
969
 
        return conf
970
 
 
971
449
    def _get_matching_sections(self):
972
450
        """Return an ordered list of section names matching this location."""
973
451
        sections = self._get_parser()
990
468
            names = zip(location_names, section_names)
991
469
            matched = True
992
470
            for name in names:
993
 
                if not fnmatch.fnmatch(name[0], name[1]):
 
471
                if not fnmatch(name[0], name[1]):
994
472
                    matched = False
995
473
                    break
996
474
            if not matched:
1001
479
                continue
1002
480
            matches.append((len(section_names), section,
1003
481
                            '/'.join(location_names[len(section_names):])))
1004
 
        # put the longest (aka more specific) locations first
1005
482
        matches.sort(reverse=True)
1006
483
        sections = []
1007
484
        for (length, section, extra_path) in matches:
1014
491
                pass
1015
492
        return sections
1016
493
 
1017
 
    def _get_sections(self, name=None):
1018
 
        """See IniBasedConfig._get_sections()."""
1019
 
        # We ignore the name here as the only sections handled are named with
1020
 
        # the location path and we don't expose embedded sections either.
1021
 
        parser = self._get_parser()
1022
 
        for name, extra_path in self._get_matching_sections():
1023
 
            yield (name, parser[name], self.config_id())
1024
 
 
1025
494
    def _get_option_policy(self, section, option_name):
1026
495
        """Return the policy for the given (section, option_name) pair."""
1027
496
        # check for the old 'recurse=False' flag
1070
539
            if policy_key in self._get_parser()[section]:
1071
540
                del self._get_parser()[section][policy_key]
1072
541
 
1073
 
    @needs_write_lock
1074
542
    def set_user_option(self, option, value, store=STORE_LOCATION):
1075
543
        """Save option and its value in the configuration."""
1076
 
        if store not in [STORE_LOCATION,
 
544
        assert store in [STORE_LOCATION,
1077
545
                         STORE_LOCATION_NORECURSE,
1078
 
                         STORE_LOCATION_APPENDPATH]:
1079
 
            raise ValueError('bad storage policy %r for %r' %
1080
 
                (store, option))
1081
 
        self.reload()
 
546
                         STORE_LOCATION_APPENDPATH], 'bad storage policy'
 
547
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
548
        # file lock on locations.conf.
 
549
        conf_dir = os.path.dirname(self._get_filename())
 
550
        ensure_config_dir_exists(conf_dir)
1082
551
        location = self.location
1083
552
        if location.endswith('/'):
1084
553
            location = location[:-1]
1085
 
        parser = self._get_parser()
1086
 
        if not location in parser and not location + '/' in parser:
1087
 
            parser[location] = {}
1088
 
        elif location + '/' in parser:
 
554
        if (not location in self._get_parser() and
 
555
            not location + '/' in self._get_parser()):
 
556
            self._get_parser()[location]={}
 
557
        elif location + '/' in self._get_parser():
1089
558
            location = location + '/'
1090
 
        parser[location][option]=value
 
559
        self._get_parser()[location][option]=value
1091
560
        # the allowed values of store match the config policies
1092
561
        self._set_option_policy(location, option, store)
1093
 
        self._write_config_file()
 
562
        self._get_parser().write(file(self._get_filename(), 'wb'))
1094
563
 
1095
564
 
1096
565
class BranchConfig(Config):
1097
566
    """A configuration object giving the policy for a branch."""
1098
567
 
1099
 
    def __init__(self, branch):
1100
 
        super(BranchConfig, self).__init__()
1101
 
        self._location_config = None
1102
 
        self._branch_data_config = None
1103
 
        self._global_config = None
1104
 
        self.branch = branch
1105
 
        self.option_sources = (self._get_location_config,
1106
 
                               self._get_branch_data_config,
1107
 
                               self._get_global_config)
1108
 
 
1109
 
    def config_id(self):
1110
 
        return 'branch'
1111
 
 
1112
568
    def _get_branch_data_config(self):
1113
569
        if self._branch_data_config is None:
1114
570
            self._branch_data_config = TreeConfig(self.branch)
1115
 
            self._branch_data_config.config_id = self.config_id
1116
571
        return self._branch_data_config
1117
572
 
1118
573
    def _get_location_config(self):
1139
594
 
1140
595
    def _get_safe_value(self, option_name):
1141
596
        """This variant of get_best_value never returns untrusted values.
1142
 
 
 
597
        
1143
598
        It does not return values from the branch data, because the branch may
1144
599
        not be controlled by the user.
1145
600
 
1154
609
 
1155
610
    def _get_user_id(self):
1156
611
        """Return the full user id for the branch.
1157
 
 
1158
 
        e.g. "John Hacker <jhacker@example.com>"
 
612
    
 
613
        e.g. "John Hacker <jhacker@foo.org>"
1159
614
        This is looked up in the email controlfile for the branch.
1160
615
        """
1161
616
        try:
1162
 
            return (self.branch._transport.get_bytes("email")
1163
 
                    .decode(osutils.get_user_encoding())
 
617
            return (self.branch.control_files.get_utf8("email") 
 
618
                    .read()
 
619
                    .decode(bzrlib.user_encoding)
1164
620
                    .rstrip("\r\n"))
1165
621
        except errors.NoSuchFile, e:
1166
622
            pass
1167
 
 
 
623
        
1168
624
        return self._get_best_value('_get_user_id')
1169
625
 
1170
 
    def _get_change_editor(self):
1171
 
        return self._get_best_value('_get_change_editor')
1172
 
 
1173
626
    def _get_signature_checking(self):
1174
627
        """See Config._get_signature_checking."""
1175
628
        return self._get_best_value('_get_signature_checking')
1186
639
                return value
1187
640
        return None
1188
641
 
1189
 
    def _get_sections(self, name=None):
1190
 
        """See IniBasedConfig.get_sections()."""
1191
 
        for source in self.option_sources:
1192
 
            for section in source()._get_sections(name):
1193
 
                yield section
1194
 
 
1195
 
    def _get_options(self, sections=None):
1196
 
        opts = []
1197
 
        # First the locations options
1198
 
        for option in self._get_location_config()._get_options():
1199
 
            yield option
1200
 
        # Then the branch options
1201
 
        branch_config = self._get_branch_data_config()
1202
 
        if sections is None:
1203
 
            sections = [('DEFAULT', branch_config._get_parser())]
1204
 
        # FIXME: We shouldn't have to duplicate the code in IniBasedConfig but
1205
 
        # Config itself has no notion of sections :( -- vila 20101001
1206
 
        config_id = self.config_id()
1207
 
        for (section_name, section) in sections:
1208
 
            for (name, value) in section.iteritems():
1209
 
                yield (name, value, section_name,
1210
 
                       config_id, branch_config._get_parser())
1211
 
        # Then the global options
1212
 
        for option in self._get_global_config()._get_options():
1213
 
            yield option
1214
 
 
1215
 
    def set_user_option(self, name, value, store=STORE_BRANCH,
1216
 
        warn_masked=False):
 
642
    def set_user_option(self, name, value, store=STORE_BRANCH):
1217
643
        if store == STORE_BRANCH:
1218
644
            self._get_branch_data_config().set_option(value, name)
1219
645
        elif store == STORE_GLOBAL:
1220
646
            self._get_global_config().set_user_option(name, value)
1221
647
        else:
1222
648
            self._get_location_config().set_user_option(name, value, store)
1223
 
        if not warn_masked:
1224
 
            return
1225
 
        if store in (STORE_GLOBAL, STORE_BRANCH):
1226
 
            mask_value = self._get_location_config().get_user_option(name)
1227
 
            if mask_value is not None:
1228
 
                trace.warning('Value "%s" is masked by "%s" from'
1229
 
                              ' locations.conf', value, mask_value)
1230
 
            else:
1231
 
                if store == STORE_GLOBAL:
1232
 
                    branch_config = self._get_branch_data_config()
1233
 
                    mask_value = branch_config.get_user_option(name)
1234
 
                    if mask_value is not None:
1235
 
                        trace.warning('Value "%s" is masked by "%s" from'
1236
 
                                      ' branch.conf', value, mask_value)
1237
 
 
1238
 
    def remove_user_option(self, option_name, section_name=None):
1239
 
        self._get_branch_data_config().remove_option(option_name, section_name)
1240
649
 
1241
650
    def _gpg_signing_command(self):
1242
651
        """See Config.gpg_signing_command."""
1243
652
        return self._get_safe_value('_gpg_signing_command')
 
653
        
 
654
    def __init__(self, branch):
 
655
        super(BranchConfig, self).__init__()
 
656
        self._location_config = None
 
657
        self._branch_data_config = None
 
658
        self._global_config = None
 
659
        self.branch = branch
 
660
        self.option_sources = (self._get_location_config, 
 
661
                               self._get_branch_data_config,
 
662
                               self._get_global_config)
1244
663
 
1245
664
    def _post_commit(self):
1246
665
        """See Config.post_commit."""
1276
695
        if sys.platform == 'win32':
1277
696
            parent_dir = os.path.dirname(path)
1278
697
            if not os.path.isdir(parent_dir):
1279
 
                trace.mutter('creating config parent directory: %r', parent_dir)
1280
 
                os.mkdir(parent_dir)
1281
 
        trace.mutter('creating config directory: %r', path)
 
698
                mutter('creating config parent directory: %r', parent_dir)
 
699
            os.mkdir(parent_dir)
 
700
        mutter('creating config directory: %r', path)
1282
701
        os.mkdir(path)
1283
 
        osutils.copy_ownership_from_path(path)
1284
702
 
1285
703
 
1286
704
def config_dir():
1287
705
    """Return per-user configuration directory.
1288
706
 
1289
 
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
1290
 
    and Linux.  On Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
1291
 
    that will be used instead.
1292
 
 
 
707
    By default this is ~/.bazaar/
 
708
    
1293
709
    TODO: Global option --config-dir to override this.
1294
710
    """
1295
711
    base = os.environ.get('BZR_HOME', None)
1296
712
    if sys.platform == 'win32':
1297
 
        # environ variables on Windows are in user encoding/mbcs. So decode
1298
 
        # before using one
1299
 
        if base is not None:
1300
 
            base = base.decode('mbcs')
1301
713
        if base is None:
1302
714
            base = win32utils.get_appdata_location_unicode()
1303
715
        if base is None:
1304
716
            base = os.environ.get('HOME', None)
1305
 
            if base is not None:
1306
 
                base = base.decode('mbcs')
1307
717
        if base is None:
1308
 
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
1309
 
                                  ' or HOME set')
 
718
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
1310
719
        return osutils.pathjoin(base, 'bazaar', '2.0')
1311
 
    elif sys.platform == 'darwin':
1312
 
        if base is None:
1313
 
            # this takes into account $HOME
1314
 
            base = os.path.expanduser("~")
1315
 
        return osutils.pathjoin(base, '.bazaar')
1316
720
    else:
 
721
        # cygwin, linux, and darwin all have a $HOME directory
1317
722
        if base is None:
1318
 
 
1319
 
            xdg_dir = os.environ.get('XDG_CONFIG_HOME', None)
1320
 
            if xdg_dir is None:
1321
 
                xdg_dir = osutils.pathjoin(os.path.expanduser("~"), ".config")
1322
 
            xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
1323
 
            if osutils.isdir(xdg_dir):
1324
 
                trace.mutter(
1325
 
                    "Using configuration in XDG directory %s." % xdg_dir)
1326
 
                return xdg_dir
1327
 
 
1328
723
            base = os.path.expanduser("~")
1329
724
        return osutils.pathjoin(base, ".bazaar")
1330
725
 
1334
729
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
1335
730
 
1336
731
 
 
732
def branches_config_filename():
 
733
    """Return per-user configuration ini file filename."""
 
734
    return osutils.pathjoin(config_dir(), 'branches.conf')
 
735
 
 
736
 
1337
737
def locations_config_filename():
1338
738
    """Return per-user configuration ini file filename."""
1339
739
    return osutils.pathjoin(config_dir(), 'locations.conf')
1340
740
 
1341
741
 
1342
 
def authentication_config_filename():
1343
 
    """Return per-user authentication ini file filename."""
1344
 
    return osutils.pathjoin(config_dir(), 'authentication.conf')
1345
 
 
1346
 
 
1347
742
def user_ignore_config_filename():
1348
743
    """Return the user default ignore filename"""
1349
744
    return osutils.pathjoin(config_dir(), 'ignore')
1350
745
 
1351
746
 
1352
 
def crash_dir():
1353
 
    """Return the directory name to store crash files.
1354
 
 
1355
 
    This doesn't implicitly create it.
1356
 
 
1357
 
    On Windows it's in the config directory; elsewhere it's /var/crash
1358
 
    which may be monitored by apport.  It can be overridden by
1359
 
    $APPORT_CRASH_DIR.
 
747
def _auto_user_id():
 
748
    """Calculate automatic user identification.
 
749
 
 
750
    Returns (realname, email).
 
751
 
 
752
    Only used when none is set in the environment or the id file.
 
753
 
 
754
    This previously used the FQDN as the default domain, but that can
 
755
    be very slow on machines where DNS is broken.  So now we simply
 
756
    use the hostname.
1360
757
    """
 
758
    import socket
 
759
 
1361
760
    if sys.platform == 'win32':
1362
 
        return osutils.pathjoin(config_dir(), 'Crash')
1363
 
    else:
1364
 
        # XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
1365
 
        # 2010-01-31
1366
 
        return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
1367
 
 
1368
 
 
1369
 
def xdg_cache_dir():
1370
 
    # See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
1371
 
    # Possibly this should be different on Windows?
1372
 
    e = os.environ.get('XDG_CACHE_DIR', None)
1373
 
    if e:
1374
 
        return e
1375
 
    else:
1376
 
        return os.path.expanduser('~/.cache')
1377
 
 
1378
 
 
1379
 
def parse_username(username):
1380
 
    """Parse e-mail username and return a (name, address) tuple."""
1381
 
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1382
 
    if match is None:
1383
 
        return (username, '')
1384
 
    else:
1385
 
        return (match.group(1), match.group(2))
 
761
        name = win32utils.get_user_name_unicode()
 
762
        if name is None:
 
763
            raise errors.BzrError("Cannot autodetect user name.\n"
 
764
                                  "Please, set your name with command like:\n"
 
765
                                  'bzr whoami "Your Name <name@domain.com>"')
 
766
        host = win32utils.get_host_name_unicode()
 
767
        if host is None:
 
768
            host = socket.gethostname()
 
769
        return name, (name + '@' + host)
 
770
 
 
771
    try:
 
772
        import pwd
 
773
        uid = os.getuid()
 
774
        w = pwd.getpwuid(uid)
 
775
 
 
776
        # we try utf-8 first, because on many variants (like Linux),
 
777
        # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
778
        # false positives.  (many users will have their user encoding set to
 
779
        # latin-1, which cannot raise UnicodeError.)
 
780
        try:
 
781
            gecos = w.pw_gecos.decode('utf-8')
 
782
            encoding = 'utf-8'
 
783
        except UnicodeError:
 
784
            try:
 
785
                gecos = w.pw_gecos.decode(bzrlib.user_encoding)
 
786
                encoding = bzrlib.user_encoding
 
787
            except UnicodeError:
 
788
                raise errors.BzrCommandError('Unable to determine your name.  '
 
789
                   'Use "bzr whoami" to set it.')
 
790
        try:
 
791
            username = w.pw_name.decode(encoding)
 
792
        except UnicodeError:
 
793
            raise errors.BzrCommandError('Unable to determine your name.  '
 
794
                'Use "bzr whoami" to set it.')
 
795
 
 
796
        comma = gecos.find(',')
 
797
        if comma == -1:
 
798
            realname = gecos
 
799
        else:
 
800
            realname = gecos[:comma]
 
801
        if not realname:
 
802
            realname = username
 
803
 
 
804
    except ImportError:
 
805
        import getpass
 
806
        try:
 
807
            realname = username = getpass.getuser().decode(bzrlib.user_encoding)
 
808
        except UnicodeDecodeError:
 
809
            raise errors.BzrError("Can't decode username as %s." % \
 
810
                    bzrlib.user_encoding)
 
811
 
 
812
    return realname, (username + '@' + socket.gethostname())
1386
813
 
1387
814
 
1388
815
def extract_email_address(e):
1389
816
    """Return just the address part of an email string.
1390
 
 
1391
 
    That is just the user@domain part, nothing else.
 
817
    
 
818
    That is just the user@domain part, nothing else. 
1392
819
    This part is required to contain only ascii characters.
1393
820
    If it can't be extracted, raises an error.
1394
 
 
 
821
    
1395
822
    >>> extract_email_address('Jane Tester <jane@test.com>')
1396
823
    "jane@test.com"
1397
824
    """
1398
 
    name, email = parse_username(e)
1399
 
    if not email:
 
825
    m = re.search(r'[\w+.-]+@[\w+.-]+', e)
 
826
    if not m:
1400
827
        raise errors.NoEmailInUsername(e)
1401
 
    return email
 
828
    return m.group(0)
1402
829
 
1403
830
 
1404
831
class TreeConfig(IniBasedConfig):
1405
832
    """Branch configuration data associated with its contents, not location"""
1406
 
 
1407
 
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
1408
 
 
1409
833
    def __init__(self, branch):
1410
 
        self._config = branch._get_config()
1411
834
        self.branch = branch
1412
835
 
1413
836
    def _get_parser(self, file=None):
1414
837
        if file is not None:
1415
838
            return IniBasedConfig._get_parser(file)
1416
 
        return self._config._get_configobj()
 
839
        return self._get_config()
 
840
 
 
841
    def _get_config(self):
 
842
        try:
 
843
            obj = ConfigObj(self.branch.control_files.get('branch.conf'), 
 
844
                            encoding='utf-8')
 
845
        except errors.NoSuchFile:
 
846
            obj = ConfigObj(encoding='utf=8')
 
847
        return obj
1417
848
 
1418
849
    def get_option(self, name, section=None, default=None):
1419
850
        self.branch.lock_read()
1420
851
        try:
1421
 
            return self._config.get_option(name, section, default)
 
852
            obj = self._get_config()
 
853
            try:
 
854
                if section is not None:
 
855
                    obj[section]
 
856
                result = obj[name]
 
857
            except KeyError:
 
858
                result = default
1422
859
        finally:
1423
860
            self.branch.unlock()
 
861
        return result
1424
862
 
1425
863
    def set_option(self, value, name, section=None):
1426
864
        """Set a per-branch configuration option"""
1427
 
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
1428
 
        # higher levels providing the right lock -- vila 20101004
1429
 
        self.branch.lock_write()
1430
 
        try:
1431
 
            self._config.set_option(value, name, section)
1432
 
        finally:
1433
 
            self.branch.unlock()
1434
 
 
1435
 
    def remove_option(self, option_name, section_name=None):
1436
 
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
1437
 
        # higher levels providing the right lock -- vila 20101004
1438
 
        self.branch.lock_write()
1439
 
        try:
1440
 
            self._config.remove_option(option_name, section_name)
1441
 
        finally:
1442
 
            self.branch.unlock()
1443
 
 
1444
 
 
1445
 
class AuthenticationConfig(object):
1446
 
    """The authentication configuration file based on a ini file.
1447
 
 
1448
 
    Implements the authentication.conf file described in
1449
 
    doc/developers/authentication-ring.txt.
1450
 
    """
1451
 
 
1452
 
    def __init__(self, _file=None):
1453
 
        self._config = None # The ConfigObj
1454
 
        if _file is None:
1455
 
            self._filename = authentication_config_filename()
1456
 
            self._input = self._filename = authentication_config_filename()
1457
 
        else:
1458
 
            # Tests can provide a string as _file
1459
 
            self._filename = None
1460
 
            self._input = _file
1461
 
 
1462
 
    def _get_config(self):
1463
 
        if self._config is not None:
1464
 
            return self._config
1465
 
        try:
1466
 
            # FIXME: Should we validate something here ? Includes: empty
1467
 
            # sections are useless, at least one of
1468
 
            # user/password/password_encoding should be defined, etc.
1469
 
 
1470
 
            # Note: the encoding below declares that the file itself is utf-8
1471
 
            # encoded, but the values in the ConfigObj are always Unicode.
1472
 
            self._config = ConfigObj(self._input, encoding='utf-8')
1473
 
        except configobj.ConfigObjError, e:
1474
 
            raise errors.ParseConfigError(e.errors, e.config.filename)
1475
 
        return self._config
1476
 
 
1477
 
    def _save(self):
1478
 
        """Save the config file, only tests should use it for now."""
1479
 
        conf_dir = os.path.dirname(self._filename)
1480
 
        ensure_config_dir_exists(conf_dir)
1481
 
        f = file(self._filename, 'wb')
1482
 
        try:
1483
 
            self._get_config().write(f)
1484
 
        finally:
1485
 
            f.close()
1486
 
 
1487
 
    def _set_option(self, section_name, option_name, value):
1488
 
        """Set an authentication configuration option"""
1489
 
        conf = self._get_config()
1490
 
        section = conf.get(section_name)
1491
 
        if section is None:
1492
 
            conf[section] = {}
1493
 
            section = conf[section]
1494
 
        section[option_name] = value
1495
 
        self._save()
1496
 
 
1497
 
    def get_credentials(self, scheme, host, port=None, user=None, path=None, 
1498
 
                        realm=None):
1499
 
        """Returns the matching credentials from authentication.conf file.
1500
 
 
1501
 
        :param scheme: protocol
1502
 
 
1503
 
        :param host: the server address
1504
 
 
1505
 
        :param port: the associated port (optional)
1506
 
 
1507
 
        :param user: login (optional)
1508
 
 
1509
 
        :param path: the absolute path on the server (optional)
1510
 
        
1511
 
        :param realm: the http authentication realm (optional)
1512
 
 
1513
 
        :return: A dict containing the matching credentials or None.
1514
 
           This includes:
1515
 
           - name: the section name of the credentials in the
1516
 
             authentication.conf file,
1517
 
           - user: can't be different from the provided user if any,
1518
 
           - scheme: the server protocol,
1519
 
           - host: the server address,
1520
 
           - port: the server port (can be None),
1521
 
           - path: the absolute server path (can be None),
1522
 
           - realm: the http specific authentication realm (can be None),
1523
 
           - password: the decoded password, could be None if the credential
1524
 
             defines only the user
1525
 
           - verify_certificates: https specific, True if the server
1526
 
             certificate should be verified, False otherwise.
1527
 
        """
1528
 
        credentials = None
1529
 
        for auth_def_name, auth_def in self._get_config().items():
1530
 
            if type(auth_def) is not configobj.Section:
1531
 
                raise ValueError("%s defined outside a section" % auth_def_name)
1532
 
 
1533
 
            a_scheme, a_host, a_user, a_path = map(
1534
 
                auth_def.get, ['scheme', 'host', 'user', 'path'])
1535
 
 
1536
 
            try:
1537
 
                a_port = auth_def.as_int('port')
1538
 
            except KeyError:
1539
 
                a_port = None
1540
 
            except ValueError:
1541
 
                raise ValueError("'port' not numeric in %s" % auth_def_name)
1542
 
            try:
1543
 
                a_verify_certificates = auth_def.as_bool('verify_certificates')
1544
 
            except KeyError:
1545
 
                a_verify_certificates = True
1546
 
            except ValueError:
1547
 
                raise ValueError(
1548
 
                    "'verify_certificates' not boolean in %s" % auth_def_name)
1549
 
 
1550
 
            # Attempt matching
1551
 
            if a_scheme is not None and scheme != a_scheme:
1552
 
                continue
1553
 
            if a_host is not None:
1554
 
                if not (host == a_host
1555
 
                        or (a_host.startswith('.') and host.endswith(a_host))):
1556
 
                    continue
1557
 
            if a_port is not None and port != a_port:
1558
 
                continue
1559
 
            if (a_path is not None and path is not None
1560
 
                and not path.startswith(a_path)):
1561
 
                continue
1562
 
            if (a_user is not None and user is not None
1563
 
                and a_user != user):
1564
 
                # Never contradict the caller about the user to be used
1565
 
                continue
1566
 
            if a_user is None:
1567
 
                # Can't find a user
1568
 
                continue
1569
 
            # Prepare a credentials dictionary with additional keys
1570
 
            # for the credential providers
1571
 
            credentials = dict(name=auth_def_name,
1572
 
                               user=a_user,
1573
 
                               scheme=a_scheme,
1574
 
                               host=host,
1575
 
                               port=port,
1576
 
                               path=path,
1577
 
                               realm=realm,
1578
 
                               password=auth_def.get('password', None),
1579
 
                               verify_certificates=a_verify_certificates)
1580
 
            # Decode the password in the credentials (or get one)
1581
 
            self.decode_password(credentials,
1582
 
                                 auth_def.get('password_encoding', None))
1583
 
            if 'auth' in debug.debug_flags:
1584
 
                trace.mutter("Using authentication section: %r", auth_def_name)
1585
 
            break
1586
 
 
1587
 
        if credentials is None:
1588
 
            # No credentials were found in authentication.conf, try the fallback
1589
 
            # credentials stores.
1590
 
            credentials = credential_store_registry.get_fallback_credentials(
1591
 
                scheme, host, port, user, path, realm)
1592
 
 
1593
 
        return credentials
1594
 
 
1595
 
    def set_credentials(self, name, host, user, scheme=None, password=None,
1596
 
                        port=None, path=None, verify_certificates=None,
1597
 
                        realm=None):
1598
 
        """Set authentication credentials for a host.
1599
 
 
1600
 
        Any existing credentials with matching scheme, host, port and path
1601
 
        will be deleted, regardless of name.
1602
 
 
1603
 
        :param name: An arbitrary name to describe this set of credentials.
1604
 
        :param host: Name of the host that accepts these credentials.
1605
 
        :param user: The username portion of these credentials.
1606
 
        :param scheme: The URL scheme (e.g. ssh, http) the credentials apply
1607
 
            to.
1608
 
        :param password: Password portion of these credentials.
1609
 
        :param port: The IP port on the host that these credentials apply to.
1610
 
        :param path: A filesystem path on the host that these credentials
1611
 
            apply to.
1612
 
        :param verify_certificates: On https, verify server certificates if
1613
 
            True.
1614
 
        :param realm: The http authentication realm (optional).
1615
 
        """
1616
 
        values = {'host': host, 'user': user}
1617
 
        if password is not None:
1618
 
            values['password'] = password
1619
 
        if scheme is not None:
1620
 
            values['scheme'] = scheme
1621
 
        if port is not None:
1622
 
            values['port'] = '%d' % port
1623
 
        if path is not None:
1624
 
            values['path'] = path
1625
 
        if verify_certificates is not None:
1626
 
            values['verify_certificates'] = str(verify_certificates)
1627
 
        if realm is not None:
1628
 
            values['realm'] = realm
1629
 
        config = self._get_config()
1630
 
        for_deletion = []
1631
 
        for section, existing_values in config.items():
1632
 
            for key in ('scheme', 'host', 'port', 'path', 'realm'):
1633
 
                if existing_values.get(key) != values.get(key):
1634
 
                    break
1635
 
            else:
1636
 
                del config[section]
1637
 
        config.update({name: values})
1638
 
        self._save()
1639
 
 
1640
 
    def get_user(self, scheme, host, port=None, realm=None, path=None,
1641
 
                 prompt=None, ask=False, default=None):
1642
 
        """Get a user from authentication file.
1643
 
 
1644
 
        :param scheme: protocol
1645
 
 
1646
 
        :param host: the server address
1647
 
 
1648
 
        :param port: the associated port (optional)
1649
 
 
1650
 
        :param realm: the realm sent by the server (optional)
1651
 
 
1652
 
        :param path: the absolute path on the server (optional)
1653
 
 
1654
 
        :param ask: Ask the user if there is no explicitly configured username 
1655
 
                    (optional)
1656
 
 
1657
 
        :param default: The username returned if none is defined (optional).
1658
 
 
1659
 
        :return: The found user.
1660
 
        """
1661
 
        credentials = self.get_credentials(scheme, host, port, user=None,
1662
 
                                           path=path, realm=realm)
1663
 
        if credentials is not None:
1664
 
            user = credentials['user']
1665
 
        else:
1666
 
            user = None
1667
 
        if user is None:
1668
 
            if ask:
1669
 
                if prompt is None:
1670
 
                    # Create a default prompt suitable for most cases
1671
 
                    prompt = scheme.upper() + ' %(host)s username'
1672
 
                # Special handling for optional fields in the prompt
1673
 
                if port is not None:
1674
 
                    prompt_host = '%s:%d' % (host, port)
1675
 
                else:
1676
 
                    prompt_host = host
1677
 
                user = ui.ui_factory.get_username(prompt, host=prompt_host)
1678
 
            else:
1679
 
                user = default
1680
 
        return user
1681
 
 
1682
 
    def get_password(self, scheme, host, user, port=None,
1683
 
                     realm=None, path=None, prompt=None):
1684
 
        """Get a password from authentication file or prompt the user for one.
1685
 
 
1686
 
        :param scheme: protocol
1687
 
 
1688
 
        :param host: the server address
1689
 
 
1690
 
        :param port: the associated port (optional)
1691
 
 
1692
 
        :param user: login
1693
 
 
1694
 
        :param realm: the realm sent by the server (optional)
1695
 
 
1696
 
        :param path: the absolute path on the server (optional)
1697
 
 
1698
 
        :return: The found password or the one entered by the user.
1699
 
        """
1700
 
        credentials = self.get_credentials(scheme, host, port, user, path,
1701
 
                                           realm)
1702
 
        if credentials is not None:
1703
 
            password = credentials['password']
1704
 
            if password is not None and scheme is 'ssh':
1705
 
                trace.warning('password ignored in section [%s],'
1706
 
                              ' use an ssh agent instead'
1707
 
                              % credentials['name'])
1708
 
                password = None
1709
 
        else:
1710
 
            password = None
1711
 
        # Prompt user only if we could't find a password
1712
 
        if password is None:
1713
 
            if prompt is None:
1714
 
                # Create a default prompt suitable for most cases
1715
 
                prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1716
 
            # Special handling for optional fields in the prompt
1717
 
            if port is not None:
1718
 
                prompt_host = '%s:%d' % (host, port)
1719
 
            else:
1720
 
                prompt_host = host
1721
 
            password = ui.ui_factory.get_password(prompt,
1722
 
                                                  host=prompt_host, user=user)
1723
 
        return password
1724
 
 
1725
 
    def decode_password(self, credentials, encoding):
1726
 
        try:
1727
 
            cs = credential_store_registry.get_credential_store(encoding)
1728
 
        except KeyError:
1729
 
            raise ValueError('%r is not a known password_encoding' % encoding)
1730
 
        credentials['password'] = cs.decode_password(credentials)
1731
 
        return credentials
1732
 
 
1733
 
 
1734
 
class CredentialStoreRegistry(registry.Registry):
1735
 
    """A class that registers credential stores.
1736
 
 
1737
 
    A credential store provides access to credentials via the password_encoding
1738
 
    field in authentication.conf sections.
1739
 
 
1740
 
    Except for stores provided by bzr itself, most stores are expected to be
1741
 
    provided by plugins that will therefore use
1742
 
    register_lazy(password_encoding, module_name, member_name, help=help,
1743
 
    fallback=fallback) to install themselves.
1744
 
 
1745
 
    A fallback credential store is one that is queried if no credentials can be
1746
 
    found via authentication.conf.
1747
 
    """
1748
 
 
1749
 
    def get_credential_store(self, encoding=None):
1750
 
        cs = self.get(encoding)
1751
 
        if callable(cs):
1752
 
            cs = cs()
1753
 
        return cs
1754
 
 
1755
 
    def is_fallback(self, name):
1756
 
        """Check if the named credentials store should be used as fallback."""
1757
 
        return self.get_info(name)
1758
 
 
1759
 
    def get_fallback_credentials(self, scheme, host, port=None, user=None,
1760
 
                                 path=None, realm=None):
1761
 
        """Request credentials from all fallback credentials stores.
1762
 
 
1763
 
        The first credentials store that can provide credentials wins.
1764
 
        """
1765
 
        credentials = None
1766
 
        for name in self.keys():
1767
 
            if not self.is_fallback(name):
1768
 
                continue
1769
 
            cs = self.get_credential_store(name)
1770
 
            credentials = cs.get_credentials(scheme, host, port, user,
1771
 
                                             path, realm)
1772
 
            if credentials is not None:
1773
 
                # We found some credentials
1774
 
                break
1775
 
        return credentials
1776
 
 
1777
 
    def register(self, key, obj, help=None, override_existing=False,
1778
 
                 fallback=False):
1779
 
        """Register a new object to a name.
1780
 
 
1781
 
        :param key: This is the key to use to request the object later.
1782
 
        :param obj: The object to register.
1783
 
        :param help: Help text for this entry. This may be a string or
1784
 
                a callable. If it is a callable, it should take two
1785
 
                parameters (registry, key): this registry and the key that
1786
 
                the help was registered under.
1787
 
        :param override_existing: Raise KeyErorr if False and something has
1788
 
                already been registered for that key. If True, ignore if there
1789
 
                is an existing key (always register the new value).
1790
 
        :param fallback: Whether this credential store should be 
1791
 
                used as fallback.
1792
 
        """
1793
 
        return super(CredentialStoreRegistry,
1794
 
                     self).register(key, obj, help, info=fallback,
1795
 
                                    override_existing=override_existing)
1796
 
 
1797
 
    def register_lazy(self, key, module_name, member_name,
1798
 
                      help=None, override_existing=False,
1799
 
                      fallback=False):
1800
 
        """Register a new credential store to be loaded on request.
1801
 
 
1802
 
        :param module_name: The python path to the module. Such as 'os.path'.
1803
 
        :param member_name: The member of the module to return.  If empty or
1804
 
                None, get() will return the module itself.
1805
 
        :param help: Help text for this entry. This may be a string or
1806
 
                a callable.
1807
 
        :param override_existing: If True, replace the existing object
1808
 
                with the new one. If False, if there is already something
1809
 
                registered with the same key, raise a KeyError
1810
 
        :param fallback: Whether this credential store should be 
1811
 
                used as fallback.
1812
 
        """
1813
 
        return super(CredentialStoreRegistry, self).register_lazy(
1814
 
            key, module_name, member_name, help,
1815
 
            info=fallback, override_existing=override_existing)
1816
 
 
1817
 
 
1818
 
credential_store_registry = CredentialStoreRegistry()
1819
 
 
1820
 
 
1821
 
class CredentialStore(object):
1822
 
    """An abstract class to implement storage for credentials"""
1823
 
 
1824
 
    def decode_password(self, credentials):
1825
 
        """Returns a clear text password for the provided credentials."""
1826
 
        raise NotImplementedError(self.decode_password)
1827
 
 
1828
 
    def get_credentials(self, scheme, host, port=None, user=None, path=None,
1829
 
                        realm=None):
1830
 
        """Return the matching credentials from this credential store.
1831
 
 
1832
 
        This method is only called on fallback credential stores.
1833
 
        """
1834
 
        raise NotImplementedError(self.get_credentials)
1835
 
 
1836
 
 
1837
 
 
1838
 
class PlainTextCredentialStore(CredentialStore):
1839
 
    __doc__ = """Plain text credential store for the authentication.conf file"""
1840
 
 
1841
 
    def decode_password(self, credentials):
1842
 
        """See CredentialStore.decode_password."""
1843
 
        return credentials['password']
1844
 
 
1845
 
 
1846
 
credential_store_registry.register('plain', PlainTextCredentialStore,
1847
 
                                   help=PlainTextCredentialStore.__doc__)
1848
 
credential_store_registry.default_key = 'plain'
1849
 
 
1850
 
 
1851
 
class BzrDirConfig(object):
1852
 
 
1853
 
    def __init__(self, bzrdir):
1854
 
        self._bzrdir = bzrdir
1855
 
        self._config = bzrdir._get_config()
1856
 
 
1857
 
    def set_default_stack_on(self, value):
1858
 
        """Set the default stacking location.
1859
 
 
1860
 
        It may be set to a location, or None.
1861
 
 
1862
 
        This policy affects all branches contained by this bzrdir, except for
1863
 
        those under repositories.
1864
 
        """
1865
 
        if self._config is None:
1866
 
            raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
1867
 
        if value is None:
1868
 
            self._config.set_option('', 'default_stack_on')
1869
 
        else:
1870
 
            self._config.set_option(value, 'default_stack_on')
1871
 
 
1872
 
    def get_default_stack_on(self):
1873
 
        """Return the default stacking location.
1874
 
 
1875
 
        This will either be a location, or None.
1876
 
 
1877
 
        This policy affects all branches contained by this bzrdir, except for
1878
 
        those under repositories.
1879
 
        """
1880
 
        if self._config is None:
1881
 
            return None
1882
 
        value = self._config.get_option('default_stack_on')
1883
 
        if value == '':
1884
 
            value = None
1885
 
        return value
1886
 
 
1887
 
 
1888
 
class TransportConfig(object):
1889
 
    """A Config that reads/writes a config file on a Transport.
1890
 
 
1891
 
    It is a low-level object that considers config data to be name/value pairs
1892
 
    that may be associated with a section.  Assigning meaning to these values
1893
 
    is done at higher levels like TreeConfig.
1894
 
    """
1895
 
 
1896
 
    def __init__(self, transport, filename):
1897
 
        self._transport = transport
1898
 
        self._filename = filename
1899
 
 
1900
 
    def get_option(self, name, section=None, default=None):
1901
 
        """Return the value associated with a named option.
1902
 
 
1903
 
        :param name: The name of the value
1904
 
        :param section: The section the option is in (if any)
1905
 
        :param default: The value to return if the value is not set
1906
 
        :return: The value or default value
1907
 
        """
1908
 
        configobj = self._get_configobj()
1909
 
        if section is None:
1910
 
            section_obj = configobj
1911
 
        else:
1912
 
            try:
1913
 
                section_obj = configobj[section]
1914
 
            except KeyError:
1915
 
                return default
1916
 
        return section_obj.get(name, default)
1917
 
 
1918
 
    def set_option(self, value, name, section=None):
1919
 
        """Set the value associated with a named option.
1920
 
 
1921
 
        :param value: The value to set
1922
 
        :param name: The name of the value to set
1923
 
        :param section: The section the option is in (if any)
1924
 
        """
1925
 
        configobj = self._get_configobj()
1926
 
        if section is None:
1927
 
            configobj[name] = value
1928
 
        else:
1929
 
            configobj.setdefault(section, {})[name] = value
1930
 
        self._set_configobj(configobj)
1931
 
 
1932
 
    def remove_option(self, option_name, section_name=None):
1933
 
        configobj = self._get_configobj()
1934
 
        if section_name is None:
1935
 
            del configobj[option_name]
1936
 
        else:
1937
 
            del configobj[section_name][option_name]
1938
 
        self._set_configobj(configobj)
1939
 
 
1940
 
    def _get_config_file(self):
1941
 
        try:
1942
 
            return StringIO(self._transport.get_bytes(self._filename))
1943
 
        except errors.NoSuchFile:
1944
 
            return StringIO()
1945
 
 
1946
 
    def _get_configobj(self):
1947
 
        f = self._get_config_file()
1948
 
        try:
1949
 
            return ConfigObj(f, encoding='utf-8')
1950
 
        finally:
1951
 
            f.close()
1952
 
 
1953
 
    def _set_configobj(self, configobj):
1954
 
        out_file = StringIO()
1955
 
        configobj.write(out_file)
1956
 
        out_file.seek(0)
1957
 
        self._transport.put_file(self._filename, out_file)
1958
 
 
1959
 
 
1960
 
class cmd_config(commands.Command):
1961
 
    __doc__ = """Display, set or remove a configuration option.
1962
 
 
1963
 
    Display the active value for a given option.
1964
 
 
1965
 
    If --all is specified, NAME is interpreted as a regular expression and all
1966
 
    matching options are displayed mentioning their scope. The active value
1967
 
    that bzr will take into account is the first one displayed for each option.
1968
 
 
1969
 
    If no NAME is given, --all .* is implied.
1970
 
 
1971
 
    Setting a value is achieved by using name=value without spaces. The value
1972
 
    is set in the most relevant scope and can be checked by displaying the
1973
 
    option again.
1974
 
    """
1975
 
 
1976
 
    takes_args = ['name?']
1977
 
 
1978
 
    takes_options = [
1979
 
        'directory',
1980
 
        # FIXME: This should be a registry option so that plugins can register
1981
 
        # their own config files (or not) -- vila 20101002
1982
 
        commands.Option('scope', help='Reduce the scope to the specified'
1983
 
                        ' configuration file',
1984
 
                        type=unicode),
1985
 
        commands.Option('all',
1986
 
            help='Display all the defined values for the matching options.',
1987
 
            ),
1988
 
        commands.Option('remove', help='Remove the option from'
1989
 
                        ' the configuration file'),
1990
 
        ]
1991
 
 
1992
 
    @commands.display_command
1993
 
    def run(self, name=None, all=False, directory=None, scope=None,
1994
 
            remove=False):
1995
 
        if directory is None:
1996
 
            directory = '.'
1997
 
        directory = urlutils.normalize_url(directory)
1998
 
        if remove and all:
1999
 
            raise errors.BzrError(
2000
 
                '--all and --remove are mutually exclusive.')
2001
 
        elif remove:
2002
 
            # Delete the option in the given scope
2003
 
            self._remove_config_option(name, directory, scope)
2004
 
        elif name is None:
2005
 
            # Defaults to all options
2006
 
            self._show_matching_options('.*', directory, scope)
2007
 
        else:
2008
 
            try:
2009
 
                name, value = name.split('=', 1)
2010
 
            except ValueError:
2011
 
                # Display the option(s) value(s)
2012
 
                if all:
2013
 
                    self._show_matching_options(name, directory, scope)
2014
 
                else:
2015
 
                    self._show_value(name, directory, scope)
2016
 
            else:
2017
 
                if all:
2018
 
                    raise errors.BzrError(
2019
 
                        'Only one option can be set.')
2020
 
                # Set the option value
2021
 
                self._set_config_option(name, value, directory, scope)
2022
 
 
2023
 
    def _get_configs(self, directory, scope=None):
2024
 
        """Iterate the configurations specified by ``directory`` and ``scope``.
2025
 
 
2026
 
        :param directory: Where the configurations are derived from.
2027
 
 
2028
 
        :param scope: A specific config to start from.
2029
 
        """
2030
 
        if scope is not None:
2031
 
            if scope == 'bazaar':
2032
 
                yield GlobalConfig()
2033
 
            elif scope == 'locations':
2034
 
                yield LocationConfig(directory)
2035
 
            elif scope == 'branch':
2036
 
                (_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
2037
 
                    directory)
2038
 
                yield br.get_config()
2039
 
        else:
2040
 
            try:
2041
 
                (_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
2042
 
                    directory)
2043
 
                yield br.get_config()
2044
 
            except errors.NotBranchError:
2045
 
                yield LocationConfig(directory)
2046
 
                yield GlobalConfig()
2047
 
 
2048
 
    def _show_value(self, name, directory, scope):
2049
 
        displayed = False
2050
 
        for c in self._get_configs(directory, scope):
2051
 
            if displayed:
2052
 
                break
2053
 
            for (oname, value, section, conf_id, parser) in c._get_options():
2054
 
                if name == oname:
2055
 
                    # Display only the first value and exit
2056
 
 
2057
 
                    # FIXME: We need to use get_user_option to take policies
2058
 
                    # into account and we need to make sure the option exists
2059
 
                    # too (hence the two for loops), this needs a better API
2060
 
                    # -- vila 20101117
2061
 
                    value = c.get_user_option(name)
2062
 
                    # Quote the value appropriately
2063
 
                    value = parser._quote(value)
2064
 
                    self.outf.write('%s\n' % (value,))
2065
 
                    displayed = True
2066
 
                    break
2067
 
        if not displayed:
2068
 
            raise errors.NoSuchConfigOption(name)
2069
 
 
2070
 
    def _show_matching_options(self, name, directory, scope):
2071
 
        name = re.compile(name)
2072
 
        # We want any error in the regexp to be raised *now* so we need to
2073
 
        # avoid the delay introduced by the lazy regexp.
2074
 
        name._compile_and_collapse()
2075
 
        cur_conf_id = None
2076
 
        cur_section = None
2077
 
        for c in self._get_configs(directory, scope):
2078
 
            for (oname, value, section, conf_id, parser) in c._get_options():
2079
 
                if name.search(oname):
2080
 
                    if cur_conf_id != conf_id:
2081
 
                        # Explain where the options are defined
2082
 
                        self.outf.write('%s:\n' % (conf_id,))
2083
 
                        cur_conf_id = conf_id
2084
 
                        cur_section = None
2085
 
                    if (section not in (None, 'DEFAULT')
2086
 
                        and cur_section != section):
2087
 
                        # Display the section if it's not the default (or only)
2088
 
                        # one.
2089
 
                        self.outf.write('  [%s]\n' % (section,))
2090
 
                        cur_section = section
2091
 
                    self.outf.write('  %s = %s\n' % (oname, value))
2092
 
 
2093
 
    def _set_config_option(self, name, value, directory, scope):
2094
 
        for conf in self._get_configs(directory, scope):
2095
 
            conf.set_user_option(name, value)
2096
 
            break
2097
 
        else:
2098
 
            raise errors.NoSuchConfig(scope)
2099
 
 
2100
 
    def _remove_config_option(self, name, directory, scope):
2101
 
        if name is None:
2102
 
            raise errors.BzrCommandError(
2103
 
                '--remove expects an option to remove.')
2104
 
        removed = False
2105
 
        for conf in self._get_configs(directory, scope):
2106
 
            for (section_name, section, conf_id) in conf._get_sections():
2107
 
                if scope is not None and conf_id != scope:
2108
 
                    # Not the right configuration file
2109
 
                    continue
2110
 
                if name in section:
2111
 
                    if conf_id != conf.config_id():
2112
 
                        conf = self._get_configs(directory, conf_id).next()
2113
 
                    # We use the first section in the first config where the
2114
 
                    # option is defined to remove it
2115
 
                    conf.remove_user_option(name, section_name)
2116
 
                    removed = True
2117
 
                    break
2118
 
            break
2119
 
        else:
2120
 
            raise errors.NoSuchConfig(scope)
2121
 
        if not removed:
2122
 
            raise errors.NoSuchConfigOption(name)
 
865
        self.branch.lock_write()
 
866
        try:
 
867
            cfg_obj = self._get_config()
 
868
            if section is None:
 
869
                obj = cfg_obj
 
870
            else:
 
871
                try:
 
872
                    obj = cfg_obj[section]
 
873
                except KeyError:
 
874
                    cfg_obj[section] = {}
 
875
                    obj = cfg_obj[section]
 
876
            obj[name] = value
 
877
            out_file = StringIO()
 
878
            cfg_obj.write(out_file)
 
879
            out_file.seek(0)
 
880
            self.branch.control_files.put('branch.conf', out_file)
 
881
        finally:
 
882
            self.branch.unlock()