~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: 2007-09-20 02:40:52 UTC
  • mfrom: (2835.1.1 ianc-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20070920024052-y2l7r5o00zrpnr73
No longer propagate index differences automatically (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
 
1
# Copyright (C) 2005, 2007 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
 
3
#            and others
3
4
#
4
5
# This program is free software; you can redistribute it and/or modify
5
6
# it under the terms of the GNU General Public License as published by
18
19
"""Configuration that affects the behaviour of Bazaar.
19
20
 
20
21
Currently this configuration resides in ~/.bazaar/bazaar.conf
21
 
and ~/.bazaar/branches.conf, which is written to by bzr.
 
22
and ~/.bazaar/locations.conf, which is written to by bzr.
22
23
 
23
24
In bazaar.conf the following options may be set:
24
25
[DEFAULT]
29
30
gpg_signing_command=name-of-program
30
31
log_format=name-of-format
31
32
 
32
 
in branches.conf, you specify the url of a branch and options for it.
 
33
in locations.conf, you specify the url of a branch and options for it.
33
34
Wildcards may be used - * and ? as normal in shell completion. Options
34
 
set in both bazaar.conf and branches.conf are overriden by the branches.conf
 
35
set in both bazaar.conf and locations.conf are overridden by the locations.conf
35
36
setting.
36
37
[/home/robertc/source]
37
38
recurse=False|True(default)
38
39
email= as above
39
 
check_signatures= as abive 
 
40
check_signatures= as above 
40
41
create_signatures= as above.
41
42
 
42
43
explanation of options
49
50
create_signatures - this option controls whether bzr will always create 
50
51
                    gpg signatures, never create them, or create them if the
51
52
                    branch is configured to require them.
52
 
                    NB: This option is planned, but not implemented yet.
53
 
log_format - This options set the default log format.  Options are long, 
54
 
             short, line, or a plugin can register new formats
 
53
log_format - this option sets the default log format.  Possible values are
 
54
             long, short, line, or a plugin can register new formats.
55
55
 
56
56
In bazaar.conf you can also define aliases in the ALIASES sections, example
57
57
 
62
62
up=pull
63
63
"""
64
64
 
65
 
 
66
 
import errno
67
65
import os
68
66
import sys
 
67
 
 
68
from bzrlib.lazy_import import lazy_import
 
69
lazy_import(globals(), """
 
70
import errno
69
71
from fnmatch import fnmatch
70
72
import re
 
73
from StringIO import StringIO
71
74
 
72
75
import bzrlib
73
 
import bzrlib.errors as errors
74
 
from bzrlib.osutils import pathjoin
75
 
from bzrlib.trace import mutter
 
76
from bzrlib import (
 
77
    errors,
 
78
    mail_client,
 
79
    osutils,
 
80
    symbol_versioning,
 
81
    trace,
 
82
    urlutils,
 
83
    win32utils,
 
84
    )
76
85
import bzrlib.util.configobj.configobj as configobj
77
 
from StringIO import StringIO
 
86
""")
 
87
 
 
88
from bzrlib.trace import mutter, warning
 
89
 
78
90
 
79
91
CHECK_IF_POSSIBLE=0
80
92
CHECK_ALWAYS=1
81
93
CHECK_NEVER=2
82
94
 
83
95
 
 
96
SIGN_WHEN_REQUIRED=0
 
97
SIGN_ALWAYS=1
 
98
SIGN_NEVER=2
 
99
 
 
100
 
 
101
POLICY_NONE = 0
 
102
POLICY_NORECURSE = 1
 
103
POLICY_APPENDPATH = 2
 
104
 
 
105
_policy_name = {
 
106
    POLICY_NONE: None,
 
107
    POLICY_NORECURSE: 'norecurse',
 
108
    POLICY_APPENDPATH: 'appendpath',
 
109
    }
 
110
_policy_value = {
 
111
    None: POLICY_NONE,
 
112
    'none': POLICY_NONE,
 
113
    'norecurse': POLICY_NORECURSE,
 
114
    'appendpath': POLICY_APPENDPATH,
 
115
    }
 
116
 
 
117
 
 
118
STORE_LOCATION = POLICY_NONE
 
119
STORE_LOCATION_NORECURSE = POLICY_NORECURSE
 
120
STORE_LOCATION_APPENDPATH = POLICY_APPENDPATH
 
121
STORE_BRANCH = 3
 
122
STORE_GLOBAL = 4
 
123
 
 
124
 
84
125
class ConfigObj(configobj.ConfigObj):
85
126
 
86
127
    def get_bool(self, section, key):
103
144
        """Get the users pop up editor."""
104
145
        raise NotImplementedError
105
146
 
 
147
    def get_mail_client(self):
 
148
        """Get a mail client to use"""
 
149
        selected_client = self.get_user_option('mail_client')
 
150
        try:
 
151
            mail_client_class = {
 
152
                None: mail_client.DefaultMail,
 
153
                # Specific clients
 
154
                'evolution': mail_client.Evolution,
 
155
                'kmail': mail_client.KMail,
 
156
                'mutt': mail_client.Mutt,
 
157
                'thunderbird': mail_client.Thunderbird,
 
158
                # Generic options
 
159
                'default': mail_client.DefaultMail,
 
160
                'editor': mail_client.Editor,
 
161
                'mapi': mail_client.MAPIClient,
 
162
                'xdg-email': mail_client.XDGEmail,
 
163
            }[selected_client]
 
164
        except KeyError:
 
165
            raise errors.UnknownMailClient(selected_client)
 
166
        return mail_client_class(self)
 
167
 
106
168
    def _get_signature_checking(self):
107
169
        """Template method to override signature checking policy."""
108
170
 
 
171
    def _get_signing_policy(self):
 
172
        """Template method to override signature creation policy."""
 
173
 
109
174
    def _get_user_option(self, option_name):
110
175
        """Template method to provide a user option."""
111
176
        return None
159
224
    
160
225
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
161
226
        
162
 
        $BZREMAIL can be set to override this, then
 
227
        $BZR_EMAIL can be set to override this (as well as the
 
228
        deprecated $BZREMAIL), then
163
229
        the concrete policy type is checked, and finally
164
230
        $EMAIL is examined.
165
231
        If none is found, a reasonable default is (hopefully)
167
233
    
168
234
        TODO: Check it's reasonably well-formed.
169
235
        """
 
236
        v = os.environ.get('BZR_EMAIL')
 
237
        if v:
 
238
            return v.decode(bzrlib.user_encoding)
170
239
        v = os.environ.get('BZREMAIL')
171
240
        if v:
 
241
            warning('BZREMAIL is deprecated in favor of BZR_EMAIL. Please update your configuration.')
172
242
            return v.decode(bzrlib.user_encoding)
173
243
    
174
244
        v = self._get_user_id()
192
262
            return policy
193
263
        return CHECK_IF_POSSIBLE
194
264
 
 
265
    def signing_policy(self):
 
266
        """What is the current policy for signature checking?."""
 
267
        policy = self._get_signing_policy()
 
268
        if policy is not None:
 
269
            return policy
 
270
        return SIGN_WHEN_REQUIRED
 
271
 
195
272
    def signature_needed(self):
196
273
        """Is a signature needed when committing ?."""
197
 
        policy = self._get_signature_checking()
198
 
        if policy == CHECK_ALWAYS:
 
274
        policy = self._get_signing_policy()
 
275
        if policy is None:
 
276
            policy = self._get_signature_checking()
 
277
            if policy is not None:
 
278
                warning("Please use create_signatures, not check_signatures "
 
279
                        "to set signing policy.")
 
280
            if policy == CHECK_ALWAYS:
 
281
                return True
 
282
        elif policy == SIGN_ALWAYS:
199
283
            return True
200
284
        return False
201
285
 
205
289
    def _get_alias(self, value):
206
290
        pass
207
291
 
 
292
    def get_nickname(self):
 
293
        return self._get_nickname()
 
294
 
 
295
    def _get_nickname(self):
 
296
        return None
 
297
 
208
298
 
209
299
class IniBasedConfig(Config):
210
300
    """A configuration policy that draws from ini files."""
222
312
            raise errors.ParseConfigError(e.errors, e.config.filename)
223
313
        return self._parser
224
314
 
 
315
    def _get_matching_sections(self):
 
316
        """Return an ordered list of (section_name, extra_path) pairs.
 
317
 
 
318
        If the section contains inherited configuration, extra_path is
 
319
        a string containing the additional path components.
 
320
        """
 
321
        section = self._get_section()
 
322
        if section is not None:
 
323
            return [(section, '')]
 
324
        else:
 
325
            return []
 
326
 
225
327
    def _get_section(self):
226
328
        """Override this to define the section used by the config."""
227
329
        return "DEFAULT"
228
330
 
 
331
    def _get_option_policy(self, section, option_name):
 
332
        """Return the policy for the given (section, option_name) pair."""
 
333
        return POLICY_NONE
 
334
 
229
335
    def _get_signature_checking(self):
230
336
        """See Config._get_signature_checking."""
231
337
        policy = self._get_user_option('check_signatures')
232
338
        if policy:
233
339
            return self._string_to_signature_policy(policy)
234
340
 
 
341
    def _get_signing_policy(self):
 
342
        """See Config._get_signing_policy"""
 
343
        policy = self._get_user_option('create_signatures')
 
344
        if policy:
 
345
            return self._string_to_signing_policy(policy)
 
346
 
235
347
    def _get_user_id(self):
236
348
        """Get the user id from the 'email' key in the current section."""
237
349
        return self._get_user_option('email')
238
350
 
239
351
    def _get_user_option(self, option_name):
240
352
        """See Config._get_user_option."""
241
 
        try:
242
 
            return self._get_parser().get_value(self._get_section(),
243
 
                                                option_name)
244
 
        except KeyError:
245
 
            pass
 
353
        for (section, extra_path) in self._get_matching_sections():
 
354
            try:
 
355
                value = self._get_parser().get_value(section, option_name)
 
356
            except KeyError:
 
357
                continue
 
358
            policy = self._get_option_policy(section, option_name)
 
359
            if policy == POLICY_NONE:
 
360
                return value
 
361
            elif policy == POLICY_NORECURSE:
 
362
                # norecurse items only apply to the exact path
 
363
                if extra_path:
 
364
                    continue
 
365
                else:
 
366
                    return value
 
367
            elif policy == POLICY_APPENDPATH:
 
368
                if extra_path:
 
369
                    value = urlutils.join(value, extra_path)
 
370
                return value
 
371
            else:
 
372
                raise AssertionError('Unexpected config policy %r' % policy)
 
373
        else:
 
374
            return None
246
375
 
247
376
    def _gpg_signing_command(self):
248
377
        """See Config.gpg_signing_command."""
272
401
        raise errors.BzrError("Invalid signatures policy '%s'"
273
402
                              % signature_string)
274
403
 
 
404
    def _string_to_signing_policy(self, signature_string):
 
405
        """Convert a string to a signing policy."""
 
406
        if signature_string.lower() == 'when-required':
 
407
            return SIGN_WHEN_REQUIRED
 
408
        if signature_string.lower() == 'never':
 
409
            return SIGN_NEVER
 
410
        if signature_string.lower() == 'always':
 
411
            return SIGN_ALWAYS
 
412
        raise errors.BzrError("Invalid signing policy '%s'"
 
413
                              % signature_string)
 
414
 
275
415
    def _get_alias(self, value):
276
416
        try:
277
417
            return self._get_parser().get_value("ALIASES", 
279
419
        except KeyError:
280
420
            pass
281
421
 
 
422
    def _get_nickname(self):
 
423
        return self.get_user_option('nickname')
 
424
 
282
425
 
283
426
class GlobalConfig(IniBasedConfig):
284
427
    """The configuration that should be used for a specific location."""
289
432
    def __init__(self):
290
433
        super(GlobalConfig, self).__init__(config_filename)
291
434
 
 
435
    def set_user_option(self, option, value):
 
436
        """Save option and its value in the configuration."""
 
437
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
438
        # file lock on bazaar.conf.
 
439
        conf_dir = os.path.dirname(self._get_filename())
 
440
        ensure_config_dir_exists(conf_dir)
 
441
        if 'DEFAULT' not in self._get_parser():
 
442
            self._get_parser()['DEFAULT'] = {}
 
443
        self._get_parser()['DEFAULT'][option] = value
 
444
        f = open(self._get_filename(), 'wb')
 
445
        self._get_parser().write(f)
 
446
        f.close()
 
447
 
292
448
 
293
449
class LocationConfig(IniBasedConfig):
294
450
    """A configuration object that gives the policy for a location."""
295
451
 
296
452
    def __init__(self, location):
297
 
        super(LocationConfig, self).__init__(branches_config_filename)
298
 
        self._global_config = None
 
453
        name_generator = locations_config_filename
 
454
        if (not os.path.exists(name_generator()) and 
 
455
                os.path.exists(branches_config_filename())):
 
456
            if sys.platform == 'win32':
 
457
                warning('Please rename %s to %s' 
 
458
                         % (branches_config_filename(),
 
459
                            locations_config_filename()))
 
460
            else:
 
461
                warning('Please rename ~/.bazaar/branches.conf'
 
462
                        ' to ~/.bazaar/locations.conf')
 
463
            name_generator = branches_config_filename
 
464
        super(LocationConfig, self).__init__(name_generator)
 
465
        # local file locations are looked up by local path, rather than
 
466
        # by file url. This is because the config file is a user
 
467
        # file, and we would rather not expose the user to file urls.
 
468
        if location.startswith('file://'):
 
469
            location = urlutils.local_path_from_url(location)
299
470
        self.location = location
300
471
 
301
 
    def _get_global_config(self):
302
 
        if self._global_config is None:
303
 
            self._global_config = GlobalConfig()
304
 
        return self._global_config
305
 
 
306
 
    def _get_section(self):
307
 
        """Get the section we should look in for config items.
308
 
 
309
 
        Returns None if none exists. 
310
 
        TODO: perhaps return a NullSection that thunks through to the 
311
 
              global config.
312
 
        """
 
472
    def _get_matching_sections(self):
 
473
        """Return an ordered list of section names matching this location."""
313
474
        sections = self._get_parser()
314
475
        location_names = self.location.split('/')
315
476
        if self.location.endswith('/'):
316
477
            del location_names[-1]
317
478
        matches=[]
318
479
        for section in sections:
319
 
            section_names = section.split('/')
 
480
            # location is a local path if possible, so we need
 
481
            # to convert 'file://' urls to local paths if necessary.
 
482
            # This also avoids having file:///path be a more exact
 
483
            # match than '/path'.
 
484
            if section.startswith('file://'):
 
485
                section_path = urlutils.local_path_from_url(section)
 
486
            else:
 
487
                section_path = section
 
488
            section_names = section_path.split('/')
320
489
            if section.endswith('/'):
321
490
                del section_names[-1]
322
491
            names = zip(location_names, section_names)
331
500
            # if section is longer, no match.
332
501
            if len(section_names) > len(location_names):
333
502
                continue
334
 
            # if path is longer, and recurse is not true, no match
335
 
            if len(section_names) < len(location_names):
336
 
                try:
337
 
                    if not self._get_parser()[section].as_bool('recurse'):
338
 
                        continue
339
 
                except KeyError:
340
 
                    pass
341
 
            matches.append((len(section_names), section))
342
 
        if not len(matches):
343
 
            return None
 
503
            matches.append((len(section_names), section,
 
504
                            '/'.join(location_names[len(section_names):])))
344
505
        matches.sort(reverse=True)
345
 
        return matches[0][1]
346
 
 
347
 
    def _gpg_signing_command(self):
348
 
        """See Config.gpg_signing_command."""
349
 
        command = super(LocationConfig, self)._gpg_signing_command()
350
 
        if command is not None:
351
 
            return command
352
 
        return self._get_global_config()._gpg_signing_command()
353
 
 
354
 
    def _log_format(self):
355
 
        """See Config.log_format."""
356
 
        command = super(LocationConfig, self)._log_format()
357
 
        if command is not None:
358
 
            return command
359
 
        return self._get_global_config()._log_format()
360
 
 
361
 
    def _get_user_id(self):
362
 
        user_id = super(LocationConfig, self)._get_user_id()
363
 
        if user_id is not None:
364
 
            return user_id
365
 
        return self._get_global_config()._get_user_id()
366
 
 
367
 
    def _get_user_option(self, option_name):
368
 
        """See Config._get_user_option."""
369
 
        option_value = super(LocationConfig, 
370
 
                             self)._get_user_option(option_name)
371
 
        if option_value is not None:
372
 
            return option_value
373
 
        return self._get_global_config()._get_user_option(option_name)
374
 
 
375
 
    def _get_signature_checking(self):
376
 
        """See Config._get_signature_checking."""
377
 
        check = super(LocationConfig, self)._get_signature_checking()
378
 
        if check is not None:
379
 
            return check
380
 
        return self._get_global_config()._get_signature_checking()
381
 
 
382
 
    def _post_commit(self):
383
 
        """See Config.post_commit."""
384
 
        hook = self._get_user_option('post_commit')
385
 
        if hook is not None:
386
 
            return hook
387
 
        return self._get_global_config()._post_commit()
388
 
 
389
 
    def set_user_option(self, option, value):
 
506
        sections = []
 
507
        for (length, section, extra_path) in matches:
 
508
            sections.append((section, extra_path))
 
509
            # should we stop looking for parent configs here?
 
510
            try:
 
511
                if self._get_parser()[section].as_bool('ignore_parents'):
 
512
                    break
 
513
            except KeyError:
 
514
                pass
 
515
        return sections
 
516
 
 
517
    def _get_option_policy(self, section, option_name):
 
518
        """Return the policy for the given (section, option_name) pair."""
 
519
        # check for the old 'recurse=False' flag
 
520
        try:
 
521
            recurse = self._get_parser()[section].as_bool('recurse')
 
522
        except KeyError:
 
523
            recurse = True
 
524
        if not recurse:
 
525
            return POLICY_NORECURSE
 
526
 
 
527
        policy_key = option_name + ':policy'
 
528
        try:
 
529
            policy_name = self._get_parser()[section][policy_key]
 
530
        except KeyError:
 
531
            policy_name = None
 
532
 
 
533
        return _policy_value[policy_name]
 
534
 
 
535
    def _set_option_policy(self, section, option_name, option_policy):
 
536
        """Set the policy for the given option name in the given section."""
 
537
        # The old recurse=False option affects all options in the
 
538
        # section.  To handle multiple policies in the section, we
 
539
        # need to convert it to a policy_norecurse key.
 
540
        try:
 
541
            recurse = self._get_parser()[section].as_bool('recurse')
 
542
        except KeyError:
 
543
            pass
 
544
        else:
 
545
            symbol_versioning.warn(
 
546
                'The recurse option is deprecated as of 0.14.  '
 
547
                'The section "%s" has been converted to use policies.'
 
548
                % section,
 
549
                DeprecationWarning)
 
550
            del self._get_parser()[section]['recurse']
 
551
            if not recurse:
 
552
                for key in self._get_parser()[section].keys():
 
553
                    if not key.endswith(':policy'):
 
554
                        self._get_parser()[section][key +
 
555
                                                    ':policy'] = 'norecurse'
 
556
 
 
557
        policy_key = option_name + ':policy'
 
558
        policy_name = _policy_name[option_policy]
 
559
        if policy_name is not None:
 
560
            self._get_parser()[section][policy_key] = policy_name
 
561
        else:
 
562
            if policy_key in self._get_parser()[section]:
 
563
                del self._get_parser()[section][policy_key]
 
564
 
 
565
    def set_user_option(self, option, value, store=STORE_LOCATION):
390
566
        """Save option and its value in the configuration."""
 
567
        assert store in [STORE_LOCATION,
 
568
                         STORE_LOCATION_NORECURSE,
 
569
                         STORE_LOCATION_APPENDPATH], 'bad storage policy'
391
570
        # FIXME: RBC 20051029 This should refresh the parser and also take a
392
 
        # file lock on branches.conf.
 
571
        # file lock on locations.conf.
393
572
        conf_dir = os.path.dirname(self._get_filename())
394
573
        ensure_config_dir_exists(conf_dir)
395
574
        location = self.location
401
580
        elif location + '/' in self._get_parser():
402
581
            location = location + '/'
403
582
        self._get_parser()[location][option]=value
 
583
        # the allowed values of store match the config policies
 
584
        self._set_option_policy(location, option, store)
404
585
        self._get_parser().write(file(self._get_filename(), 'wb'))
405
586
 
406
587
 
407
588
class BranchConfig(Config):
408
589
    """A configuration object giving the policy for a branch."""
409
590
 
 
591
    def _get_branch_data_config(self):
 
592
        if self._branch_data_config is None:
 
593
            self._branch_data_config = TreeConfig(self.branch)
 
594
        return self._branch_data_config
 
595
 
410
596
    def _get_location_config(self):
411
597
        if self._location_config is None:
412
598
            self._location_config = LocationConfig(self.branch.base)
413
599
        return self._location_config
414
600
 
 
601
    def _get_global_config(self):
 
602
        if self._global_config is None:
 
603
            self._global_config = GlobalConfig()
 
604
        return self._global_config
 
605
 
 
606
    def _get_best_value(self, option_name):
 
607
        """This returns a user option from local, tree or global config.
 
608
 
 
609
        They are tried in that order.  Use get_safe_value if trusted values
 
610
        are necessary.
 
611
        """
 
612
        for source in self.option_sources:
 
613
            value = getattr(source(), option_name)()
 
614
            if value is not None:
 
615
                return value
 
616
        return None
 
617
 
 
618
    def _get_safe_value(self, option_name):
 
619
        """This variant of get_best_value never returns untrusted values.
 
620
        
 
621
        It does not return values from the branch data, because the branch may
 
622
        not be controlled by the user.
 
623
 
 
624
        We may wish to allow locations.conf to control whether branches are
 
625
        trusted in the future.
 
626
        """
 
627
        for source in (self._get_location_config, self._get_global_config):
 
628
            value = getattr(source(), option_name)()
 
629
            if value is not None:
 
630
                return value
 
631
        return None
 
632
 
415
633
    def _get_user_id(self):
416
634
        """Return the full user id for the branch.
417
635
    
426
644
        except errors.NoSuchFile, e:
427
645
            pass
428
646
        
429
 
        return self._get_location_config()._get_user_id()
 
647
        return self._get_best_value('_get_user_id')
430
648
 
431
649
    def _get_signature_checking(self):
432
650
        """See Config._get_signature_checking."""
433
 
        return self._get_location_config()._get_signature_checking()
 
651
        return self._get_best_value('_get_signature_checking')
 
652
 
 
653
    def _get_signing_policy(self):
 
654
        """See Config._get_signing_policy."""
 
655
        return self._get_best_value('_get_signing_policy')
434
656
 
435
657
    def _get_user_option(self, option_name):
436
658
        """See Config._get_user_option."""
437
 
        return self._get_location_config()._get_user_option(option_name)
 
659
        for source in self.option_sources:
 
660
            value = source()._get_user_option(option_name)
 
661
            if value is not None:
 
662
                return value
 
663
        return None
 
664
 
 
665
    def set_user_option(self, name, value, store=STORE_BRANCH,
 
666
        warn_masked=False):
 
667
        if store == STORE_BRANCH:
 
668
            self._get_branch_data_config().set_option(value, name)
 
669
        elif store == STORE_GLOBAL:
 
670
            self._get_global_config().set_user_option(name, value)
 
671
        else:
 
672
            self._get_location_config().set_user_option(name, value, store)
 
673
        if not warn_masked:
 
674
            return
 
675
        if store in (STORE_GLOBAL, STORE_BRANCH):
 
676
            mask_value = self._get_location_config().get_user_option(name)
 
677
            if mask_value is not None:
 
678
                trace.warning('Value "%s" is masked by "%s" from'
 
679
                              ' locations.conf', value, mask_value)
 
680
            else:
 
681
                if store == STORE_GLOBAL:
 
682
                    branch_config = self._get_branch_data_config()
 
683
                    mask_value = branch_config.get_user_option(name)
 
684
                    if mask_value is not None:
 
685
                        trace.warning('Value "%s" is masked by "%s" from'
 
686
                                      ' branch.conf', value, mask_value)
 
687
 
438
688
 
439
689
    def _gpg_signing_command(self):
440
690
        """See Config.gpg_signing_command."""
441
 
        return self._get_location_config()._gpg_signing_command()
 
691
        return self._get_safe_value('_gpg_signing_command')
442
692
        
443
693
    def __init__(self, branch):
444
694
        super(BranchConfig, self).__init__()
445
695
        self._location_config = None
 
696
        self._branch_data_config = None
 
697
        self._global_config = None
446
698
        self.branch = branch
 
699
        self.option_sources = (self._get_location_config, 
 
700
                               self._get_branch_data_config,
 
701
                               self._get_global_config)
447
702
 
448
703
    def _post_commit(self):
449
704
        """See Config.post_commit."""
450
 
        return self._get_location_config()._post_commit()
 
705
        return self._get_safe_value('_post_commit')
 
706
 
 
707
    def _get_nickname(self):
 
708
        value = self._get_explicit_nickname()
 
709
        if value is not None:
 
710
            return value
 
711
        return urlutils.unescape(self.branch.base.split('/')[-2])
 
712
 
 
713
    def has_explicit_nickname(self):
 
714
        """Return true if a nickname has been explicitly assigned."""
 
715
        return self._get_explicit_nickname() is not None
 
716
 
 
717
    def _get_explicit_nickname(self):
 
718
        return self._get_best_value('_get_nickname')
451
719
 
452
720
    def _log_format(self):
453
721
        """See Config.log_format."""
454
 
        return self._get_location_config()._log_format()
 
722
        return self._get_best_value('_log_format')
455
723
 
456
724
 
457
725
def ensure_config_dir_exists(path=None):
482
750
    base = os.environ.get('BZR_HOME', None)
483
751
    if sys.platform == 'win32':
484
752
        if base is None:
485
 
            base = os.environ.get('APPDATA', None)
 
753
            base = win32utils.get_appdata_location_unicode()
486
754
        if base is None:
487
755
            base = os.environ.get('HOME', None)
488
756
        if base is None:
489
 
            raise BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
490
 
        return pathjoin(base, 'bazaar', '2.0')
 
757
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
 
758
        return osutils.pathjoin(base, 'bazaar', '2.0')
491
759
    else:
492
760
        # cygwin, linux, and darwin all have a $HOME directory
493
761
        if base is None:
494
762
            base = os.path.expanduser("~")
495
 
        return pathjoin(base, ".bazaar")
 
763
        return osutils.pathjoin(base, ".bazaar")
496
764
 
497
765
 
498
766
def config_filename():
499
767
    """Return per-user configuration ini file filename."""
500
 
    return pathjoin(config_dir(), 'bazaar.conf')
 
768
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
501
769
 
502
770
 
503
771
def branches_config_filename():
504
772
    """Return per-user configuration ini file filename."""
505
 
    return pathjoin(config_dir(), 'branches.conf')
 
773
    return osutils.pathjoin(config_dir(), 'branches.conf')
 
774
 
 
775
 
 
776
def locations_config_filename():
 
777
    """Return per-user configuration ini file filename."""
 
778
    return osutils.pathjoin(config_dir(), 'locations.conf')
 
779
 
 
780
 
 
781
def user_ignore_config_filename():
 
782
    """Return the user default ignore filename"""
 
783
    return osutils.pathjoin(config_dir(), 'ignore')
506
784
 
507
785
 
508
786
def _auto_user_id():
518
796
    """
519
797
    import socket
520
798
 
521
 
    # XXX: Any good way to get real user name on win32?
 
799
    if sys.platform == 'win32':
 
800
        name = win32utils.get_user_name_unicode()
 
801
        if name is None:
 
802
            raise errors.BzrError("Cannot autodetect user name.\n"
 
803
                                  "Please, set your name with command like:\n"
 
804
                                  'bzr whoami "Your Name <name@domain.com>"')
 
805
        host = win32utils.get_host_name_unicode()
 
806
        if host is None:
 
807
            host = socket.gethostname()
 
808
        return name, (name + '@' + host)
522
809
 
523
810
    try:
524
811
        import pwd
525
812
        uid = os.getuid()
526
813
        w = pwd.getpwuid(uid)
527
814
 
528
 
        try:
529
 
            gecos = w.pw_gecos.decode(bzrlib.user_encoding)
530
 
            username = w.pw_name.decode(bzrlib.user_encoding)
531
 
        except UnicodeDecodeError:
532
 
            # We're using pwd, therefore we're on Unix, so /etc/passwd is ok.
533
 
            raise errors.BzrError("Can't decode username in " \
534
 
                    "/etc/passwd as %s." % bzrlib.user_encoding)
 
815
        # we try utf-8 first, because on many variants (like Linux),
 
816
        # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
817
        # false positives.  (many users will have their user encoding set to
 
818
        # latin-1, which cannot raise UnicodeError.)
 
819
        try:
 
820
            gecos = w.pw_gecos.decode('utf-8')
 
821
            encoding = 'utf-8'
 
822
        except UnicodeError:
 
823
            try:
 
824
                gecos = w.pw_gecos.decode(bzrlib.user_encoding)
 
825
                encoding = bzrlib.user_encoding
 
826
            except UnicodeError:
 
827
                raise errors.BzrCommandError('Unable to determine your name.  '
 
828
                   'Use "bzr whoami" to set it.')
 
829
        try:
 
830
            username = w.pw_name.decode(encoding)
 
831
        except UnicodeError:
 
832
            raise errors.BzrCommandError('Unable to determine your name.  '
 
833
                'Use "bzr whoami" to set it.')
535
834
 
536
835
        comma = gecos.find(',')
537
836
        if comma == -1:
564
863
    """
565
864
    m = re.search(r'[\w+.-]+@[\w+.-]+', e)
566
865
    if not m:
567
 
        raise errors.BzrError("%r doesn't seem to contain "
568
 
                              "a reasonable email address" % e)
 
866
        raise errors.NoEmailInUsername(e)
569
867
    return m.group(0)
570
868
 
571
 
class TreeConfig(object):
 
869
 
 
870
class TreeConfig(IniBasedConfig):
572
871
    """Branch configuration data associated with its contents, not location"""
573
872
    def __init__(self, branch):
574
873
        self.branch = branch
575
874
 
 
875
    def _get_parser(self, file=None):
 
876
        if file is not None:
 
877
            return IniBasedConfig._get_parser(file)
 
878
        return self._get_config()
 
879
 
576
880
    def _get_config(self):
577
881
        try:
578
 
            obj = ConfigObj(self.branch.control_files.get('branch.conf'), 
 
882
            obj = ConfigObj(self.branch.control_files.get('branch.conf'),
579
883
                            encoding='utf-8')
580
884
        except errors.NoSuchFile:
581
885
            obj = ConfigObj(encoding='utf=8')
587
891
            obj = self._get_config()
588
892
            try:
589
893
                if section is not None:
590
 
                    obj[section]
 
894
                    obj = obj[section]
591
895
                result = obj[name]
592
896
            except KeyError:
593
897
                result = default