1
# Copyright (C) 2005 by Canonical Ltd
 
 
2
#   Authors: Robert Collins <robert.collins@canonical.com>
 
 
4
# This program is free software; you can redistribute it and/or modify
 
 
5
# it under the terms of the GNU General Public License as published by
 
 
6
# the Free Software Foundation; either version 2 of the License, or
 
 
7
# (at your option) any later version.
 
 
9
# This program is distributed in the hope that it will be useful,
 
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 
12
# GNU General Public License for more details.
 
 
14
# You should have received a copy of the GNU General Public License
 
 
15
# along with this program; if not, write to the Free Software
 
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 
18
"""Configuration that affects the behaviour of Bazaar.
 
 
20
Currently this configuration resides in ~/.bazaar/bazaar.conf
 
 
21
and ~/.bazaar/locations.conf, which is written to by bzr.
 
 
23
In bazaar.conf the following options may be set:
 
 
25
editor=name-of-program
 
 
26
email=Your Name <your@email.address>
 
 
27
check_signatures=require|ignore|check-available(default)
 
 
28
create_signatures=always|never|when-required(default)
 
 
29
gpg_signing_command=name-of-program
 
 
30
log_format=name-of-format
 
 
32
in locations.conf, you specify the url of a branch and options for it.
 
 
33
Wildcards may be used - * and ? as normal in shell completion. Options
 
 
34
set in both bazaar.conf and locations.conf are overridden by the locations.conf
 
 
36
[/home/robertc/source]
 
 
37
recurse=False|True(default)
 
 
39
check_signatures= as above 
 
 
40
create_signatures= as above.
 
 
42
explanation of options
 
 
43
----------------------
 
 
44
editor - this option sets the pop up editor to use during commits.
 
 
45
email - this option sets the user id bzr will use when committing.
 
 
46
check_signatures - this option controls whether bzr will require good gpg
 
 
47
                   signatures, ignore them, or check them if they are 
 
 
49
create_signatures - this option controls whether bzr will always create 
 
 
50
                    gpg signatures, never create them, or create them if the
 
 
51
                    branch is configured to require them.
 
 
52
log_format - this option sets the default log format.  Possible values are
 
 
53
             long, short, line, or a plugin can register new formats.
 
 
55
In bazaar.conf you can also define aliases in the ALIASES sections, example
 
 
58
lastlog=log --line -r-10..-1
 
 
59
ll=log --line -r-10..-1
 
 
67
from bzrlib.lazy_import import lazy_import
 
 
68
lazy_import(globals(), """
 
 
70
from fnmatch import fnmatch
 
 
72
from StringIO import StringIO
 
 
80
import bzrlib.util.configobj.configobj as configobj
 
 
83
from bzrlib.trace import mutter, warning
 
 
96
class ConfigObj(configobj.ConfigObj):
 
 
98
    def get_bool(self, section, key):
 
 
99
        return self[section].as_bool(key)
 
 
101
    def get_value(self, section, name):
 
 
102
        # Try [] for the old DEFAULT section.
 
 
103
        if section == "DEFAULT":
 
 
108
        return self[section][name]
 
 
111
class Config(object):
 
 
112
    """A configuration policy - what username, editor, gpg needs etc."""
 
 
114
    def get_editor(self):
 
 
115
        """Get the users pop up editor."""
 
 
116
        raise NotImplementedError
 
 
118
    def _get_signature_checking(self):
 
 
119
        """Template method to override signature checking policy."""
 
 
121
    def _get_signing_policy(self):
 
 
122
        """Template method to override signature creation policy."""
 
 
124
    def _get_user_option(self, option_name):
 
 
125
        """Template method to provide a user option."""
 
 
128
    def get_user_option(self, option_name):
 
 
129
        """Get a generic option - no special process, no default."""
 
 
130
        return self._get_user_option(option_name)
 
 
132
    def gpg_signing_command(self):
 
 
133
        """What program should be used to sign signatures?"""
 
 
134
        result = self._gpg_signing_command()
 
 
139
    def _gpg_signing_command(self):
 
 
140
        """See gpg_signing_command()."""
 
 
143
    def log_format(self):
 
 
144
        """What log format should be used"""
 
 
145
        result = self._log_format()
 
 
150
    def _log_format(self):
 
 
151
        """See log_format()."""
 
 
155
        super(Config, self).__init__()
 
 
157
    def post_commit(self):
 
 
158
        """An ordered list of python functions to call.
 
 
160
        Each function takes branch, rev_id as parameters.
 
 
162
        return self._post_commit()
 
 
164
    def _post_commit(self):
 
 
165
        """See Config.post_commit."""
 
 
168
    def user_email(self):
 
 
169
        """Return just the email component of a username."""
 
 
170
        return extract_email_address(self.username())
 
 
173
        """Return email-style username.
 
 
175
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
 
 
177
        $BZR_EMAIL can be set to override this (as well as the
 
 
178
        deprecated $BZREMAIL), then
 
 
179
        the concrete policy type is checked, and finally
 
 
181
        If none is found, a reasonable default is (hopefully)
 
 
184
        TODO: Check it's reasonably well-formed.
 
 
186
        v = os.environ.get('BZR_EMAIL')
 
 
188
            return v.decode(bzrlib.user_encoding)
 
 
189
        v = os.environ.get('BZREMAIL')
 
 
191
            warning('BZREMAIL is deprecated in favor of BZR_EMAIL. Please update your configuration.')
 
 
192
            return v.decode(bzrlib.user_encoding)
 
 
194
        v = self._get_user_id()
 
 
198
        v = os.environ.get('EMAIL')
 
 
200
            return v.decode(bzrlib.user_encoding)
 
 
202
        name, email = _auto_user_id()
 
 
204
            return '%s <%s>' % (name, email)
 
 
208
    def signature_checking(self):
 
 
209
        """What is the current policy for signature checking?."""
 
 
210
        policy = self._get_signature_checking()
 
 
211
        if policy is not None:
 
 
213
        return CHECK_IF_POSSIBLE
 
 
215
    def signing_policy(self):
 
 
216
        """What is the current policy for signature checking?."""
 
 
217
        policy = self._get_signing_policy()
 
 
218
        if policy is not None:
 
 
220
        return SIGN_WHEN_REQUIRED
 
 
222
    def signature_needed(self):
 
 
223
        """Is a signature needed when committing ?."""
 
 
224
        policy = self._get_signing_policy()
 
 
226
            policy = self._get_signature_checking()
 
 
227
            if policy is not None:
 
 
228
                warning("Please use create_signatures, not check_signatures "
 
 
229
                        "to set signing policy.")
 
 
230
            if policy == CHECK_ALWAYS:
 
 
232
        elif policy == SIGN_ALWAYS:
 
 
236
    def get_alias(self, value):
 
 
237
        return self._get_alias(value)
 
 
239
    def _get_alias(self, value):
 
 
242
    def get_nickname(self):
 
 
243
        return self._get_nickname()
 
 
245
    def _get_nickname(self):
 
 
249
class IniBasedConfig(Config):
 
 
250
    """A configuration policy that draws from ini files."""
 
 
252
    def _get_parser(self, file=None):
 
 
253
        if self._parser is not None:
 
 
256
            input = self._get_filename()
 
 
260
            self._parser = ConfigObj(input, encoding='utf-8')
 
 
261
        except configobj.ConfigObjError, e:
 
 
262
            raise errors.ParseConfigError(e.errors, e.config.filename)
 
 
265
    def _get_matching_sections(self):
 
 
266
        """Return an ordered list of (section_name, extra_path) pairs.
 
 
268
        If the section contains inherited configuration, extra_path is
 
 
269
        a string containing the additional path components.
 
 
271
        section = self._get_section()
 
 
272
        if section is not None:
 
 
273
            return [(section, '')]
 
 
277
    def _get_section(self):
 
 
278
        """Override this to define the section used by the config."""
 
 
281
    def _get_signature_checking(self):
 
 
282
        """See Config._get_signature_checking."""
 
 
283
        policy = self._get_user_option('check_signatures')
 
 
285
            return self._string_to_signature_policy(policy)
 
 
287
    def _get_signing_policy(self):
 
 
288
        """See Config._get_signing_policy"""
 
 
289
        policy = self._get_user_option('create_signatures')
 
 
291
            return self._string_to_signing_policy(policy)
 
 
293
    def _get_user_id(self):
 
 
294
        """Get the user id from the 'email' key in the current section."""
 
 
295
        return self._get_user_option('email')
 
 
297
    def _get_user_option(self, option_name):
 
 
298
        """See Config._get_user_option."""
 
 
299
        for (section, extra_path) in self._get_matching_sections():
 
 
301
                return self._get_parser().get_value(section, option_name)
 
 
307
    def _gpg_signing_command(self):
 
 
308
        """See Config.gpg_signing_command."""
 
 
309
        return self._get_user_option('gpg_signing_command')
 
 
311
    def _log_format(self):
 
 
312
        """See Config.log_format."""
 
 
313
        return self._get_user_option('log_format')
 
 
315
    def __init__(self, get_filename):
 
 
316
        super(IniBasedConfig, self).__init__()
 
 
317
        self._get_filename = get_filename
 
 
320
    def _post_commit(self):
 
 
321
        """See Config.post_commit."""
 
 
322
        return self._get_user_option('post_commit')
 
 
324
    def _string_to_signature_policy(self, signature_string):
 
 
325
        """Convert a string to a signing policy."""
 
 
326
        if signature_string.lower() == 'check-available':
 
 
327
            return CHECK_IF_POSSIBLE
 
 
328
        if signature_string.lower() == 'ignore':
 
 
330
        if signature_string.lower() == 'require':
 
 
332
        raise errors.BzrError("Invalid signatures policy '%s'"
 
 
335
    def _string_to_signing_policy(self, signature_string):
 
 
336
        """Convert a string to a signing policy."""
 
 
337
        if signature_string.lower() == 'when-required':
 
 
338
            return SIGN_WHEN_REQUIRED
 
 
339
        if signature_string.lower() == 'never':
 
 
341
        if signature_string.lower() == 'always':
 
 
343
        raise errors.BzrError("Invalid signing policy '%s'"
 
 
346
    def _get_alias(self, value):
 
 
348
            return self._get_parser().get_value("ALIASES", 
 
 
353
    def _get_nickname(self):
 
 
354
        return self.get_user_option('nickname')
 
 
357
class GlobalConfig(IniBasedConfig):
 
 
358
    """The configuration that should be used for a specific location."""
 
 
360
    def get_editor(self):
 
 
361
        return self._get_user_option('editor')
 
 
364
        super(GlobalConfig, self).__init__(config_filename)
 
 
366
    def set_user_option(self, option, value):
 
 
367
        """Save option and its value in the configuration."""
 
 
368
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
 
369
        # file lock on bazaar.conf.
 
 
370
        conf_dir = os.path.dirname(self._get_filename())
 
 
371
        ensure_config_dir_exists(conf_dir)
 
 
372
        if 'DEFAULT' not in self._get_parser():
 
 
373
            self._get_parser()['DEFAULT'] = {}
 
 
374
        self._get_parser()['DEFAULT'][option] = value
 
 
375
        f = open(self._get_filename(), 'wb')
 
 
376
        self._get_parser().write(f)
 
 
380
class LocationConfig(IniBasedConfig):
 
 
381
    """A configuration object that gives the policy for a location."""
 
 
383
    def __init__(self, location):
 
 
384
        name_generator = locations_config_filename
 
 
385
        if (not os.path.exists(name_generator()) and 
 
 
386
                os.path.exists(branches_config_filename())):
 
 
387
            if sys.platform == 'win32':
 
 
388
                warning('Please rename %s to %s' 
 
 
389
                         % (branches_config_filename(),
 
 
390
                            locations_config_filename()))
 
 
392
                warning('Please rename ~/.bazaar/branches.conf'
 
 
393
                        ' to ~/.bazaar/locations.conf')
 
 
394
            name_generator = branches_config_filename
 
 
395
        super(LocationConfig, self).__init__(name_generator)
 
 
396
        # local file locations are looked up by local path, rather than
 
 
397
        # by file url. This is because the config file is a user
 
 
398
        # file, and we would rather not expose the user to file urls.
 
 
399
        if location.startswith('file://'):
 
 
400
            location = urlutils.local_path_from_url(location)
 
 
401
        self.location = location
 
 
403
    def _get_matching_sections(self):
 
 
404
        """Return an ordered list of section names matching this location."""
 
 
405
        sections = self._get_parser()
 
 
406
        location_names = self.location.split('/')
 
 
407
        if self.location.endswith('/'):
 
 
408
            del location_names[-1]
 
 
410
        for section in sections:
 
 
411
            # location is a local path if possible, so we need
 
 
412
            # to convert 'file://' urls to local paths if necessary.
 
 
413
            # This also avoids having file:///path be a more exact
 
 
414
            # match than '/path'.
 
 
415
            if section.startswith('file://'):
 
 
416
                section_path = urlutils.local_path_from_url(section)
 
 
418
                section_path = section
 
 
419
            section_names = section_path.split('/')
 
 
420
            if section.endswith('/'):
 
 
421
                del section_names[-1]
 
 
422
            names = zip(location_names, section_names)
 
 
425
                if not fnmatch(name[0], name[1]):
 
 
430
            # so, for the common prefix they matched.
 
 
431
            # if section is longer, no match.
 
 
432
            if len(section_names) > len(location_names):
 
 
434
            # if path is longer, and recurse is not true, no match
 
 
435
            if len(section_names) < len(location_names):
 
 
437
                    if not self._get_parser()[section].as_bool('recurse'):
 
 
441
            matches.append((len(section_names), section,
 
 
442
                            '/'.join(location_names[len(section_names):])))
 
 
443
        matches.sort(reverse=True)
 
 
445
        for (length, section, extra_path) in matches:
 
 
446
            sections.append((section, extra_path))
 
 
447
            # should we stop looking for parent configs here?
 
 
449
                if self._get_parser()[section].as_bool('ignore_parents'):
 
 
455
    def set_user_option(self, option, value):
 
 
456
        """Save option and its value in the configuration."""
 
 
457
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
 
458
        # file lock on locations.conf.
 
 
459
        conf_dir = os.path.dirname(self._get_filename())
 
 
460
        ensure_config_dir_exists(conf_dir)
 
 
461
        location = self.location
 
 
462
        if location.endswith('/'):
 
 
463
            location = location[:-1]
 
 
464
        if (not location in self._get_parser() and
 
 
465
            not location + '/' in self._get_parser()):
 
 
466
            self._get_parser()[location]={}
 
 
467
        elif location + '/' in self._get_parser():
 
 
468
            location = location + '/'
 
 
469
        self._get_parser()[location][option]=value
 
 
470
        self._get_parser().write(file(self._get_filename(), 'wb'))
 
 
473
class BranchConfig(Config):
 
 
474
    """A configuration object giving the policy for a branch."""
 
 
476
    def _get_branch_data_config(self):
 
 
477
        if self._branch_data_config is None:
 
 
478
            self._branch_data_config = TreeConfig(self.branch)
 
 
479
        return self._branch_data_config
 
 
481
    def _get_location_config(self):
 
 
482
        if self._location_config is None:
 
 
483
            self._location_config = LocationConfig(self.branch.base)
 
 
484
        return self._location_config
 
 
486
    def _get_global_config(self):
 
 
487
        if self._global_config is None:
 
 
488
            self._global_config = GlobalConfig()
 
 
489
        return self._global_config
 
 
491
    def _get_best_value(self, option_name):
 
 
492
        """This returns a user option from local, tree or global config.
 
 
494
        They are tried in that order.  Use get_safe_value if trusted values
 
 
497
        for source in self.option_sources:
 
 
498
            value = getattr(source(), option_name)()
 
 
499
            if value is not None:
 
 
503
    def _get_safe_value(self, option_name):
 
 
504
        """This variant of get_best_value never returns untrusted values.
 
 
506
        It does not return values from the branch data, because the branch may
 
 
507
        not be controlled by the user.
 
 
509
        We may wish to allow locations.conf to control whether branches are
 
 
510
        trusted in the future.
 
 
512
        for source in (self._get_location_config, self._get_global_config):
 
 
513
            value = getattr(source(), option_name)()
 
 
514
            if value is not None:
 
 
518
    def _get_user_id(self):
 
 
519
        """Return the full user id for the branch.
 
 
521
        e.g. "John Hacker <jhacker@foo.org>"
 
 
522
        This is looked up in the email controlfile for the branch.
 
 
525
            return (self.branch.control_files.get_utf8("email") 
 
 
527
                    .decode(bzrlib.user_encoding)
 
 
529
        except errors.NoSuchFile, e:
 
 
532
        return self._get_best_value('_get_user_id')
 
 
534
    def _get_signature_checking(self):
 
 
535
        """See Config._get_signature_checking."""
 
 
536
        return self._get_best_value('_get_signature_checking')
 
 
538
    def _get_signing_policy(self):
 
 
539
        """See Config._get_signing_policy."""
 
 
540
        return self._get_best_value('_get_signing_policy')
 
 
542
    def _get_user_option(self, option_name):
 
 
543
        """See Config._get_user_option."""
 
 
544
        for source in self.option_sources:
 
 
545
            value = source()._get_user_option(option_name)
 
 
546
            if value is not None:
 
 
550
    def set_user_option(self, name, value, local=False):
 
 
552
            self._get_location_config().set_user_option(name, value)
 
 
554
            self._get_branch_data_config().set_option(value, name)
 
 
557
    def _gpg_signing_command(self):
 
 
558
        """See Config.gpg_signing_command."""
 
 
559
        return self._get_safe_value('_gpg_signing_command')
 
 
561
    def __init__(self, branch):
 
 
562
        super(BranchConfig, self).__init__()
 
 
563
        self._location_config = None
 
 
564
        self._branch_data_config = None
 
 
565
        self._global_config = None
 
 
567
        self.option_sources = (self._get_location_config, 
 
 
568
                               self._get_branch_data_config,
 
 
569
                               self._get_global_config)
 
 
571
    def _post_commit(self):
 
 
572
        """See Config.post_commit."""
 
 
573
        return self._get_safe_value('_post_commit')
 
 
575
    def _get_nickname(self):
 
 
576
        value = self._get_explicit_nickname()
 
 
577
        if value is not None:
 
 
579
        return self.branch.base.split('/')[-2]
 
 
581
    def has_explicit_nickname(self):
 
 
582
        """Return true if a nickname has been explicitly assigned."""
 
 
583
        return self._get_explicit_nickname() is not None
 
 
585
    def _get_explicit_nickname(self):
 
 
586
        return self._get_best_value('_get_nickname')
 
 
588
    def _log_format(self):
 
 
589
        """See Config.log_format."""
 
 
590
        return self._get_best_value('_log_format')
 
 
593
def ensure_config_dir_exists(path=None):
 
 
594
    """Make sure a configuration directory exists.
 
 
595
    This makes sure that the directory exists.
 
 
596
    On windows, since configuration directories are 2 levels deep,
 
 
597
    it makes sure both the directory and the parent directory exists.
 
 
601
    if not os.path.isdir(path):
 
 
602
        if sys.platform == 'win32':
 
 
603
            parent_dir = os.path.dirname(path)
 
 
604
            if not os.path.isdir(parent_dir):
 
 
605
                mutter('creating config parent directory: %r', parent_dir)
 
 
607
        mutter('creating config directory: %r', path)
 
 
612
    """Return per-user configuration directory.
 
 
614
    By default this is ~/.bazaar/
 
 
616
    TODO: Global option --config-dir to override this.
 
 
618
    base = os.environ.get('BZR_HOME', None)
 
 
619
    if sys.platform == 'win32':
 
 
621
            base = os.environ.get('APPDATA', None)
 
 
623
            base = os.environ.get('HOME', None)
 
 
625
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
 
 
626
        return osutils.pathjoin(base, 'bazaar', '2.0')
 
 
628
        # cygwin, linux, and darwin all have a $HOME directory
 
 
630
            base = os.path.expanduser("~")
 
 
631
        return osutils.pathjoin(base, ".bazaar")
 
 
634
def config_filename():
 
 
635
    """Return per-user configuration ini file filename."""
 
 
636
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
 
 
639
def branches_config_filename():
 
 
640
    """Return per-user configuration ini file filename."""
 
 
641
    return osutils.pathjoin(config_dir(), 'branches.conf')
 
 
644
def locations_config_filename():
 
 
645
    """Return per-user configuration ini file filename."""
 
 
646
    return osutils.pathjoin(config_dir(), 'locations.conf')
 
 
649
def user_ignore_config_filename():
 
 
650
    """Return the user default ignore filename"""
 
 
651
    return osutils.pathjoin(config_dir(), 'ignore')
 
 
655
    """Calculate automatic user identification.
 
 
657
    Returns (realname, email).
 
 
659
    Only used when none is set in the environment or the id file.
 
 
661
    This previously used the FQDN as the default domain, but that can
 
 
662
    be very slow on machines where DNS is broken.  So now we simply
 
 
667
    # XXX: Any good way to get real user name on win32?
 
 
672
        w = pwd.getpwuid(uid)
 
 
674
        # we try utf-8 first, because on many variants (like Linux),
 
 
675
        # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
 
676
        # false positives.  (many users will have their user encoding set to
 
 
677
        # latin-1, which cannot raise UnicodeError.)
 
 
679
            gecos = w.pw_gecos.decode('utf-8')
 
 
683
                gecos = w.pw_gecos.decode(bzrlib.user_encoding)
 
 
684
                encoding = bzrlib.user_encoding
 
 
686
                raise errors.BzrCommandError('Unable to determine your name.  '
 
 
687
                   'Use "bzr whoami" to set it.')
 
 
689
            username = w.pw_name.decode(encoding)
 
 
691
            raise errors.BzrCommandError('Unable to determine your name.  '
 
 
692
                'Use "bzr whoami" to set it.')
 
 
694
        comma = gecos.find(',')
 
 
698
            realname = gecos[:comma]
 
 
705
            realname = username = getpass.getuser().decode(bzrlib.user_encoding)
 
 
706
        except UnicodeDecodeError:
 
 
707
            raise errors.BzrError("Can't decode username as %s." % \
 
 
708
                    bzrlib.user_encoding)
 
 
710
    return realname, (username + '@' + socket.gethostname())
 
 
713
def extract_email_address(e):
 
 
714
    """Return just the address part of an email string.
 
 
716
    That is just the user@domain part, nothing else. 
 
 
717
    This part is required to contain only ascii characters.
 
 
718
    If it can't be extracted, raises an error.
 
 
720
    >>> extract_email_address('Jane Tester <jane@test.com>')
 
 
723
    m = re.search(r'[\w+.-]+@[\w+.-]+', e)
 
 
725
        raise errors.NoEmailInUsername(e)
 
 
729
class TreeConfig(IniBasedConfig):
 
 
730
    """Branch configuration data associated with its contents, not location"""
 
 
731
    def __init__(self, branch):
 
 
734
    def _get_parser(self, file=None):
 
 
736
            return IniBasedConfig._get_parser(file)
 
 
737
        return self._get_config()
 
 
739
    def _get_config(self):
 
 
741
            obj = ConfigObj(self.branch.control_files.get('branch.conf'), 
 
 
743
        except errors.NoSuchFile:
 
 
744
            obj = ConfigObj(encoding='utf=8')
 
 
747
    def get_option(self, name, section=None, default=None):
 
 
748
        self.branch.lock_read()
 
 
750
            obj = self._get_config()
 
 
752
                if section is not None:
 
 
761
    def set_option(self, value, name, section=None):
 
 
762
        """Set a per-branch configuration option"""
 
 
763
        self.branch.lock_write()
 
 
765
            cfg_obj = self._get_config()
 
 
770
                    obj = cfg_obj[section]
 
 
772
                    cfg_obj[section] = {}
 
 
773
                    obj = cfg_obj[section]
 
 
775
            out_file = StringIO()
 
 
776
            cfg_obj.write(out_file)
 
 
778
            self.branch.control_files.put('branch.conf', out_file)