~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Martin Pool
  • Date: 2005-07-04 12:26:02 UTC
  • Revision ID: mbp@sourcefrog.net-20050704122602-69901910521e62c3
- check command checks that all inventory-ids are the same as in the revision.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007 Canonical Ltd
2
 
#   Authors: Robert Collins <robert.collins@canonical.com>
3
 
#            and others
4
 
#
5
 
# This program is free software; you can redistribute it and/or modify
6
 
# it under the terms of the GNU General Public License as published by
7
 
# the Free Software Foundation; either version 2 of the License, or
8
 
# (at your option) any later version.
9
 
#
10
 
# This program is distributed in the hope that it will be useful,
11
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
# GNU General Public License for more details.
14
 
#
15
 
# You should have received a copy of the GNU General Public License
16
 
# along with this program; if not, write to the Free Software
17
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
 
19
 
"""Configuration that affects the behaviour of Bazaar.
20
 
 
21
 
Currently this configuration resides in ~/.bazaar/bazaar.conf
22
 
and ~/.bazaar/locations.conf, which is written to by bzr.
23
 
 
24
 
In bazaar.conf the following options may be set:
25
 
[DEFAULT]
26
 
editor=name-of-program
27
 
email=Your Name <your@email.address>
28
 
check_signatures=require|ignore|check-available(default)
29
 
create_signatures=always|never|when-required(default)
30
 
gpg_signing_command=name-of-program
31
 
log_format=name-of-format
32
 
 
33
 
in locations.conf, you specify the url of a branch and options for it.
34
 
Wildcards may be used - * and ? as normal in shell completion. Options
35
 
set in both bazaar.conf and locations.conf are overridden by the locations.conf
36
 
setting.
37
 
[/home/robertc/source]
38
 
recurse=False|True(default)
39
 
email= as above
40
 
check_signatures= as above 
41
 
create_signatures= as above.
42
 
 
43
 
explanation of options
44
 
----------------------
45
 
editor - this option sets the pop up editor to use during commits.
46
 
email - this option sets the user id bzr will use when committing.
47
 
check_signatures - this option controls whether bzr will require good gpg
48
 
                   signatures, ignore them, or check them if they are 
49
 
                   present.
50
 
create_signatures - this option controls whether bzr will always create 
51
 
                    gpg signatures, never create them, or create them if the
52
 
                    branch is configured to require them.
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
 
 
56
 
In bazaar.conf you can also define aliases in the ALIASES sections, example
57
 
 
58
 
[ALIASES]
59
 
lastlog=log --line -r-10..-1
60
 
ll=log --line -r-10..-1
61
 
h=help
62
 
up=pull
63
 
"""
64
 
 
65
 
import os
66
 
import sys
67
 
 
68
 
from bzrlib.lazy_import import lazy_import
69
 
lazy_import(globals(), """
70
 
import errno
71
 
from fnmatch import fnmatch
72
 
import re
73
 
from StringIO import StringIO
74
 
 
75
 
import bzrlib
76
 
from bzrlib import (
77
 
    errors,
78
 
    mail_client,
79
 
    osutils,
80
 
    symbol_versioning,
81
 
    trace,
82
 
    urlutils,
83
 
    win32utils,
84
 
    )
85
 
import bzrlib.util.configobj.configobj as configobj
86
 
""")
87
 
 
88
 
from bzrlib.trace import mutter, warning
89
 
 
90
 
 
91
 
CHECK_IF_POSSIBLE=0
92
 
CHECK_ALWAYS=1
93
 
CHECK_NEVER=2
94
 
 
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
 
 
125
 
class ConfigObj(configobj.ConfigObj):
126
 
 
127
 
    def get_bool(self, section, key):
128
 
        return self[section].as_bool(key)
129
 
 
130
 
    def get_value(self, section, name):
131
 
        # Try [] for the old DEFAULT section.
132
 
        if section == "DEFAULT":
133
 
            try:
134
 
                return self[name]
135
 
            except KeyError:
136
 
                pass
137
 
        return self[section][name]
138
 
 
139
 
 
140
 
class Config(object):
141
 
    """A configuration policy - what username, editor, gpg needs etc."""
142
 
 
143
 
    def get_editor(self):
144
 
        """Get the users pop up editor."""
145
 
        raise NotImplementedError
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
 
 
168
 
    def _get_signature_checking(self):
169
 
        """Template method to override signature checking policy."""
170
 
 
171
 
    def _get_signing_policy(self):
172
 
        """Template method to override signature creation policy."""
173
 
 
174
 
    def _get_user_option(self, option_name):
175
 
        """Template method to provide a user option."""
176
 
        return None
177
 
 
178
 
    def get_user_option(self, option_name):
179
 
        """Get a generic option - no special process, no default."""
180
 
        return self._get_user_option(option_name)
181
 
 
182
 
    def gpg_signing_command(self):
183
 
        """What program should be used to sign signatures?"""
184
 
        result = self._gpg_signing_command()
185
 
        if result is None:
186
 
            result = "gpg"
187
 
        return result
188
 
 
189
 
    def _gpg_signing_command(self):
190
 
        """See gpg_signing_command()."""
191
 
        return None
192
 
 
193
 
    def log_format(self):
194
 
        """What log format should be used"""
195
 
        result = self._log_format()
196
 
        if result is None:
197
 
            result = "long"
198
 
        return result
199
 
 
200
 
    def _log_format(self):
201
 
        """See log_format()."""
202
 
        return None
203
 
 
204
 
    def __init__(self):
205
 
        super(Config, self).__init__()
206
 
 
207
 
    def post_commit(self):
208
 
        """An ordered list of python functions to call.
209
 
 
210
 
        Each function takes branch, rev_id as parameters.
211
 
        """
212
 
        return self._post_commit()
213
 
 
214
 
    def _post_commit(self):
215
 
        """See Config.post_commit."""
216
 
        return None
217
 
 
218
 
    def user_email(self):
219
 
        """Return just the email component of a username."""
220
 
        return extract_email_address(self.username())
221
 
 
222
 
    def username(self):
223
 
        """Return email-style username.
224
 
    
225
 
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
226
 
        
227
 
        $BZR_EMAIL can be set to override this (as well as the
228
 
        deprecated $BZREMAIL), then
229
 
        the concrete policy type is checked, and finally
230
 
        $EMAIL is examined.
231
 
        If none is found, a reasonable default is (hopefully)
232
 
        created.
233
 
    
234
 
        TODO: Check it's reasonably well-formed.
235
 
        """
236
 
        v = os.environ.get('BZR_EMAIL')
237
 
        if v:
238
 
            return v.decode(bzrlib.user_encoding)
239
 
        v = os.environ.get('BZREMAIL')
240
 
        if v:
241
 
            warning('BZREMAIL is deprecated in favor of BZR_EMAIL. Please update your configuration.')
242
 
            return v.decode(bzrlib.user_encoding)
243
 
    
244
 
        v = self._get_user_id()
245
 
        if v:
246
 
            return v
247
 
        
248
 
        v = os.environ.get('EMAIL')
249
 
        if v:
250
 
            return v.decode(bzrlib.user_encoding)
251
 
 
252
 
        name, email = _auto_user_id()
253
 
        if name:
254
 
            return '%s <%s>' % (name, email)
255
 
        else:
256
 
            return email
257
 
 
258
 
    def signature_checking(self):
259
 
        """What is the current policy for signature checking?."""
260
 
        policy = self._get_signature_checking()
261
 
        if policy is not None:
262
 
            return policy
263
 
        return CHECK_IF_POSSIBLE
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
 
 
272
 
    def signature_needed(self):
273
 
        """Is a signature needed when committing ?."""
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:
283
 
            return True
284
 
        return False
285
 
 
286
 
    def get_alias(self, value):
287
 
        return self._get_alias(value)
288
 
 
289
 
    def _get_alias(self, value):
290
 
        pass
291
 
 
292
 
    def get_nickname(self):
293
 
        return self._get_nickname()
294
 
 
295
 
    def _get_nickname(self):
296
 
        return None
297
 
 
298
 
 
299
 
class IniBasedConfig(Config):
300
 
    """A configuration policy that draws from ini files."""
301
 
 
302
 
    def _get_parser(self, file=None):
303
 
        if self._parser is not None:
304
 
            return self._parser
305
 
        if file is None:
306
 
            input = self._get_filename()
307
 
        else:
308
 
            input = file
309
 
        try:
310
 
            self._parser = ConfigObj(input, encoding='utf-8')
311
 
        except configobj.ConfigObjError, e:
312
 
            raise errors.ParseConfigError(e.errors, e.config.filename)
313
 
        return self._parser
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
 
 
327
 
    def _get_section(self):
328
 
        """Override this to define the section used by the config."""
329
 
        return "DEFAULT"
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
 
 
335
 
    def _get_signature_checking(self):
336
 
        """See Config._get_signature_checking."""
337
 
        policy = self._get_user_option('check_signatures')
338
 
        if policy:
339
 
            return self._string_to_signature_policy(policy)
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
 
 
347
 
    def _get_user_id(self):
348
 
        """Get the user id from the 'email' key in the current section."""
349
 
        return self._get_user_option('email')
350
 
 
351
 
    def _get_user_option(self, option_name):
352
 
        """See Config._get_user_option."""
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
375
 
 
376
 
    def _gpg_signing_command(self):
377
 
        """See Config.gpg_signing_command."""
378
 
        return self._get_user_option('gpg_signing_command')
379
 
 
380
 
    def _log_format(self):
381
 
        """See Config.log_format."""
382
 
        return self._get_user_option('log_format')
383
 
 
384
 
    def __init__(self, get_filename):
385
 
        super(IniBasedConfig, self).__init__()
386
 
        self._get_filename = get_filename
387
 
        self._parser = None
388
 
        
389
 
    def _post_commit(self):
390
 
        """See Config.post_commit."""
391
 
        return self._get_user_option('post_commit')
392
 
 
393
 
    def _string_to_signature_policy(self, signature_string):
394
 
        """Convert a string to a signing policy."""
395
 
        if signature_string.lower() == 'check-available':
396
 
            return CHECK_IF_POSSIBLE
397
 
        if signature_string.lower() == 'ignore':
398
 
            return CHECK_NEVER
399
 
        if signature_string.lower() == 'require':
400
 
            return CHECK_ALWAYS
401
 
        raise errors.BzrError("Invalid signatures policy '%s'"
402
 
                              % signature_string)
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
 
 
415
 
    def _get_alias(self, value):
416
 
        try:
417
 
            return self._get_parser().get_value("ALIASES", 
418
 
                                                value)
419
 
        except KeyError:
420
 
            pass
421
 
 
422
 
    def _get_nickname(self):
423
 
        return self.get_user_option('nickname')
424
 
 
425
 
 
426
 
class GlobalConfig(IniBasedConfig):
427
 
    """The configuration that should be used for a specific location."""
428
 
 
429
 
    def get_editor(self):
430
 
        return self._get_user_option('editor')
431
 
 
432
 
    def __init__(self):
433
 
        super(GlobalConfig, self).__init__(config_filename)
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
 
 
448
 
 
449
 
class LocationConfig(IniBasedConfig):
450
 
    """A configuration object that gives the policy for a location."""
451
 
 
452
 
    def __init__(self, location):
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)
470
 
        self.location = location
471
 
 
472
 
    def _get_matching_sections(self):
473
 
        """Return an ordered list of section names matching this location."""
474
 
        sections = self._get_parser()
475
 
        location_names = self.location.split('/')
476
 
        if self.location.endswith('/'):
477
 
            del location_names[-1]
478
 
        matches=[]
479
 
        for section in sections:
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('/')
489
 
            if section.endswith('/'):
490
 
                del section_names[-1]
491
 
            names = zip(location_names, section_names)
492
 
            matched = True
493
 
            for name in names:
494
 
                if not fnmatch(name[0], name[1]):
495
 
                    matched = False
496
 
                    break
497
 
            if not matched:
498
 
                continue
499
 
            # so, for the common prefix they matched.
500
 
            # if section is longer, no match.
501
 
            if len(section_names) > len(location_names):
502
 
                continue
503
 
            matches.append((len(section_names), section,
504
 
                            '/'.join(location_names[len(section_names):])))
505
 
        matches.sort(reverse=True)
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):
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'
570
 
        # FIXME: RBC 20051029 This should refresh the parser and also take a
571
 
        # file lock on locations.conf.
572
 
        conf_dir = os.path.dirname(self._get_filename())
573
 
        ensure_config_dir_exists(conf_dir)
574
 
        location = self.location
575
 
        if location.endswith('/'):
576
 
            location = location[:-1]
577
 
        if (not location in self._get_parser() and
578
 
            not location + '/' in self._get_parser()):
579
 
            self._get_parser()[location]={}
580
 
        elif location + '/' in self._get_parser():
581
 
            location = location + '/'
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)
585
 
        self._get_parser().write(file(self._get_filename(), 'wb'))
586
 
 
587
 
 
588
 
class BranchConfig(Config):
589
 
    """A configuration object giving the policy for a branch."""
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
 
 
596
 
    def _get_location_config(self):
597
 
        if self._location_config is None:
598
 
            self._location_config = LocationConfig(self.branch.base)
599
 
        return self._location_config
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
 
 
633
 
    def _get_user_id(self):
634
 
        """Return the full user id for the branch.
635
 
    
636
 
        e.g. "John Hacker <jhacker@foo.org>"
637
 
        This is looked up in the email controlfile for the branch.
638
 
        """
639
 
        try:
640
 
            return (self.branch.control_files.get_utf8("email") 
641
 
                    .read()
642
 
                    .decode(bzrlib.user_encoding)
643
 
                    .rstrip("\r\n"))
644
 
        except errors.NoSuchFile, e:
645
 
            pass
646
 
        
647
 
        return self._get_best_value('_get_user_id')
648
 
 
649
 
    def _get_signature_checking(self):
650
 
        """See 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')
656
 
 
657
 
    def _get_user_option(self, option_name):
658
 
        """See Config._get_user_option."""
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
 
 
688
 
 
689
 
    def _gpg_signing_command(self):
690
 
        """See Config.gpg_signing_command."""
691
 
        return self._get_safe_value('_gpg_signing_command')
692
 
        
693
 
    def __init__(self, branch):
694
 
        super(BranchConfig, self).__init__()
695
 
        self._location_config = None
696
 
        self._branch_data_config = None
697
 
        self._global_config = None
698
 
        self.branch = branch
699
 
        self.option_sources = (self._get_location_config, 
700
 
                               self._get_branch_data_config,
701
 
                               self._get_global_config)
702
 
 
703
 
    def _post_commit(self):
704
 
        """See 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')
719
 
 
720
 
    def _log_format(self):
721
 
        """See Config.log_format."""
722
 
        return self._get_best_value('_log_format')
723
 
 
724
 
 
725
 
def ensure_config_dir_exists(path=None):
726
 
    """Make sure a configuration directory exists.
727
 
    This makes sure that the directory exists.
728
 
    On windows, since configuration directories are 2 levels deep,
729
 
    it makes sure both the directory and the parent directory exists.
730
 
    """
731
 
    if path is None:
732
 
        path = config_dir()
733
 
    if not os.path.isdir(path):
734
 
        if sys.platform == 'win32':
735
 
            parent_dir = os.path.dirname(path)
736
 
            if not os.path.isdir(parent_dir):
737
 
                mutter('creating config parent directory: %r', parent_dir)
738
 
            os.mkdir(parent_dir)
739
 
        mutter('creating config directory: %r', path)
740
 
        os.mkdir(path)
741
 
 
742
 
 
743
 
def config_dir():
744
 
    """Return per-user configuration directory.
745
 
 
746
 
    By default this is ~/.bazaar/
747
 
    
748
 
    TODO: Global option --config-dir to override this.
749
 
    """
750
 
    base = os.environ.get('BZR_HOME', None)
751
 
    if sys.platform == 'win32':
752
 
        if base is None:
753
 
            base = win32utils.get_appdata_location_unicode()
754
 
        if base is None:
755
 
            base = os.environ.get('HOME', None)
756
 
        if base is None:
757
 
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
758
 
        return osutils.pathjoin(base, 'bazaar', '2.0')
759
 
    else:
760
 
        # cygwin, linux, and darwin all have a $HOME directory
761
 
        if base is None:
762
 
            base = os.path.expanduser("~")
763
 
        return osutils.pathjoin(base, ".bazaar")
764
 
 
765
 
 
766
 
def config_filename():
767
 
    """Return per-user configuration ini file filename."""
768
 
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
769
 
 
770
 
 
771
 
def branches_config_filename():
772
 
    """Return per-user configuration ini file filename."""
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')
784
 
 
785
 
 
786
 
def _auto_user_id():
787
 
    """Calculate automatic user identification.
788
 
 
789
 
    Returns (realname, email).
790
 
 
791
 
    Only used when none is set in the environment or the id file.
792
 
 
793
 
    This previously used the FQDN as the default domain, but that can
794
 
    be very slow on machines where DNS is broken.  So now we simply
795
 
    use the hostname.
796
 
    """
797
 
    import socket
798
 
 
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)
809
 
 
810
 
    try:
811
 
        import pwd
812
 
        uid = os.getuid()
813
 
        w = pwd.getpwuid(uid)
814
 
 
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.')
834
 
 
835
 
        comma = gecos.find(',')
836
 
        if comma == -1:
837
 
            realname = gecos
838
 
        else:
839
 
            realname = gecos[:comma]
840
 
        if not realname:
841
 
            realname = username
842
 
 
843
 
    except ImportError:
844
 
        import getpass
845
 
        try:
846
 
            realname = username = getpass.getuser().decode(bzrlib.user_encoding)
847
 
        except UnicodeDecodeError:
848
 
            raise errors.BzrError("Can't decode username as %s." % \
849
 
                    bzrlib.user_encoding)
850
 
 
851
 
    return realname, (username + '@' + socket.gethostname())
852
 
 
853
 
 
854
 
def extract_email_address(e):
855
 
    """Return just the address part of an email string.
856
 
    
857
 
    That is just the user@domain part, nothing else. 
858
 
    This part is required to contain only ascii characters.
859
 
    If it can't be extracted, raises an error.
860
 
    
861
 
    >>> extract_email_address('Jane Tester <jane@test.com>')
862
 
    "jane@test.com"
863
 
    """
864
 
    m = re.search(r'[\w+.-]+@[\w+.-]+', e)
865
 
    if not m:
866
 
        raise errors.NoEmailInUsername(e)
867
 
    return m.group(0)
868
 
 
869
 
 
870
 
class TreeConfig(IniBasedConfig):
871
 
    """Branch configuration data associated with its contents, not location"""
872
 
    def __init__(self, branch):
873
 
        self.branch = branch
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
 
 
880
 
    def _get_config(self):
881
 
        try:
882
 
            obj = ConfigObj(self.branch.control_files.get('branch.conf'),
883
 
                            encoding='utf-8')
884
 
        except errors.NoSuchFile:
885
 
            obj = ConfigObj(encoding='utf=8')
886
 
        return obj
887
 
 
888
 
    def get_option(self, name, section=None, default=None):
889
 
        self.branch.lock_read()
890
 
        try:
891
 
            obj = self._get_config()
892
 
            try:
893
 
                if section is not None:
894
 
                    obj = obj[section]
895
 
                result = obj[name]
896
 
            except KeyError:
897
 
                result = default
898
 
        finally:
899
 
            self.branch.unlock()
900
 
        return result
901
 
 
902
 
    def set_option(self, value, name, section=None):
903
 
        """Set a per-branch configuration option"""
904
 
        self.branch.lock_write()
905
 
        try:
906
 
            cfg_obj = self._get_config()
907
 
            if section is None:
908
 
                obj = cfg_obj
909
 
            else:
910
 
                try:
911
 
                    obj = cfg_obj[section]
912
 
                except KeyError:
913
 
                    cfg_obj[section] = {}
914
 
                    obj = cfg_obj[section]
915
 
            obj[name] = value
916
 
            out_file = StringIO()
917
 
            cfg_obj.write(out_file)
918
 
            out_file.seek(0)
919
 
            self.branch.control_files.put('branch.conf', out_file)
920
 
        finally:
921
 
            self.branch.unlock()