/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Martin Pool
  • Date: 2007-09-24 06:42:21 UTC
  • mfrom: (2713.2.3 error-exitcode)
  • mto: This revision was merged to the branch mainline in revision 2874.
  • Revision ID: mbp@sourcefrog.net-20070924064221-nu12try0hbilenlj
Return exitcode 4 on internal error

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()