~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

[merge] win32 fixes (alexey)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007 Canonical Ltd
 
1
# Copyright (C) 2005 by Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
 
#            and others
4
3
#
5
4
# This program is free software; you can redistribute it and/or modify
6
5
# it under the terms of the GNU General Public License as published by
19
18
"""Configuration that affects the behaviour of Bazaar.
20
19
 
21
20
Currently this configuration resides in ~/.bazaar/bazaar.conf
22
 
and ~/.bazaar/locations.conf, which is written to by bzr.
 
21
and ~/.bazaar/branches.conf, which is written to by bzr.
23
22
 
24
23
In bazaar.conf the following options may be set:
25
24
[DEFAULT]
28
27
check_signatures=require|ignore|check-available(default)
29
28
create_signatures=always|never|when-required(default)
30
29
gpg_signing_command=name-of-program
31
 
log_format=name-of-format
32
30
 
33
 
in locations.conf, you specify the url of a branch and options for it.
 
31
in branches.conf, you specify the url of a branch and options for it.
34
32
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
 
33
set in both bazaar.conf and branches.conf are overriden by the branches.conf
36
34
setting.
37
35
[/home/robertc/source]
38
36
recurse=False|True(default)
39
37
email= as above
40
 
check_signatures= as above 
 
38
check_signatures= as abive 
41
39
create_signatures= as above.
42
40
 
43
41
explanation of options
50
48
create_signatures - this option controls whether bzr will always create 
51
49
                    gpg signatures, never create them, or create them if the
52
50
                    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
 
51
                    NB: This option is planned, but not implemented yet.
63
52
"""
64
53
 
 
54
 
 
55
import errno
65
56
import os
66
57
import sys
67
 
 
68
 
from bzrlib.lazy_import import lazy_import
69
 
lazy_import(globals(), """
70
 
import errno
71
58
from fnmatch import fnmatch
72
59
import re
73
 
from cStringIO import StringIO
74
60
 
75
61
import bzrlib
76
 
from bzrlib import (
77
 
    debug,
78
 
    errors,
79
 
    mail_client,
80
 
    osutils,
81
 
    symbol_versioning,
82
 
    trace,
83
 
    ui,
84
 
    urlutils,
85
 
    win32utils,
86
 
    )
 
62
import bzrlib.errors as errors
87
63
import bzrlib.util.configobj.configobj as configobj
88
 
""")
89
 
 
 
64
from StringIO import StringIO
90
65
 
91
66
CHECK_IF_POSSIBLE=0
92
67
CHECK_ALWAYS=1
93
68
CHECK_NEVER=2
94
69
 
95
70
 
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
71
class ConfigObj(configobj.ConfigObj):
126
72
 
127
73
    def get_bool(self, section, key):
128
 
        return self[section].as_bool(key)
 
74
        val = self[section][key].lower()
 
75
        if val in ('1', 'yes', 'true', 'on'):
 
76
            return True
 
77
        elif val in ('0', 'no', 'false', 'off'):
 
78
            return False
 
79
        else:
 
80
            raise ValueError("Value %r is not boolean" % val)
129
81
 
130
82
    def get_value(self, section, name):
131
83
        # Try [] for the old DEFAULT section.
144
96
        """Get the users pop up editor."""
145
97
        raise NotImplementedError
146
98
 
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
99
    def _get_signature_checking(self):
169
100
        """Template method to override signature checking policy."""
170
101
 
171
 
    def _get_signing_policy(self):
172
 
        """Template method to override signature creation policy."""
173
 
 
174
102
    def _get_user_option(self, option_name):
175
103
        """Template method to provide a user option."""
176
104
        return None
190
118
        """See gpg_signing_command()."""
191
119
        return None
192
120
 
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
121
    def __init__(self):
205
122
        super(Config, self).__init__()
206
123
 
224
141
    
225
142
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
226
143
        
227
 
        $BZR_EMAIL can be set to override this (as well as the
228
 
        deprecated $BZREMAIL), then
 
144
        $BZREMAIL can be set to override this, then
229
145
        the concrete policy type is checked, and finally
230
146
        $EMAIL is examined.
231
147
        If none is found, a reasonable default is (hopefully)
233
149
    
234
150
        TODO: Check it's reasonably well-formed.
235
151
        """
236
 
        v = os.environ.get('BZR_EMAIL')
 
152
        v = os.environ.get('BZREMAIL')
237
153
        if v:
238
154
            return v.decode(bzrlib.user_encoding)
239
 
 
 
155
    
240
156
        v = self._get_user_id()
241
157
        if v:
242
158
            return v
243
 
 
 
159
        
244
160
        v = os.environ.get('EMAIL')
245
161
        if v:
246
162
            return v.decode(bzrlib.user_encoding)
258
174
            return policy
259
175
        return CHECK_IF_POSSIBLE
260
176
 
261
 
    def signing_policy(self):
262
 
        """What is the current policy for signature checking?."""
263
 
        policy = self._get_signing_policy()
264
 
        if policy is not None:
265
 
            return policy
266
 
        return SIGN_WHEN_REQUIRED
267
 
 
268
177
    def signature_needed(self):
269
178
        """Is a signature needed when committing ?."""
270
 
        policy = self._get_signing_policy()
271
 
        if policy is None:
272
 
            policy = self._get_signature_checking()
273
 
            if policy is not None:
274
 
                trace.warning("Please use create_signatures,"
275
 
                              " not check_signatures to set signing policy.")
276
 
            if policy == CHECK_ALWAYS:
277
 
                return True
278
 
        elif policy == SIGN_ALWAYS:
 
179
        policy = self._get_signature_checking()
 
180
        if policy == CHECK_ALWAYS:
279
181
            return True
280
182
        return False
281
183
 
282
 
    def get_alias(self, value):
283
 
        return self._get_alias(value)
284
 
 
285
 
    def _get_alias(self, value):
286
 
        pass
287
 
 
288
 
    def get_nickname(self):
289
 
        return self._get_nickname()
290
 
 
291
 
    def _get_nickname(self):
292
 
        return None
293
 
 
294
 
    def get_bzr_remote_path(self):
295
 
        try:
296
 
            return os.environ['BZR_REMOTE_PATH']
297
 
        except KeyError:
298
 
            path = self.get_user_option("bzr_remote_path")
299
 
            if path is None:
300
 
                path = 'bzr'
301
 
            return path
302
 
 
303
184
 
304
185
class IniBasedConfig(Config):
305
186
    """A configuration policy that draws from ini files."""
312
193
        else:
313
194
            input = file
314
195
        try:
315
 
            self._parser = ConfigObj(input, encoding='utf-8')
 
196
            self._parser = ConfigObj(input)
316
197
        except configobj.ConfigObjError, e:
317
198
            raise errors.ParseConfigError(e.errors, e.config.filename)
318
199
        return self._parser
319
200
 
320
 
    def _get_matching_sections(self):
321
 
        """Return an ordered list of (section_name, extra_path) pairs.
322
 
 
323
 
        If the section contains inherited configuration, extra_path is
324
 
        a string containing the additional path components.
325
 
        """
326
 
        section = self._get_section()
327
 
        if section is not None:
328
 
            return [(section, '')]
329
 
        else:
330
 
            return []
331
 
 
332
201
    def _get_section(self):
333
202
        """Override this to define the section used by the config."""
334
203
        return "DEFAULT"
335
204
 
336
 
    def _get_option_policy(self, section, option_name):
337
 
        """Return the policy for the given (section, option_name) pair."""
338
 
        return POLICY_NONE
339
 
 
340
205
    def _get_signature_checking(self):
341
206
        """See Config._get_signature_checking."""
342
207
        policy = self._get_user_option('check_signatures')
343
208
        if policy:
344
209
            return self._string_to_signature_policy(policy)
345
210
 
346
 
    def _get_signing_policy(self):
347
 
        """See Config._get_signing_policy"""
348
 
        policy = self._get_user_option('create_signatures')
349
 
        if policy:
350
 
            return self._string_to_signing_policy(policy)
351
 
 
352
211
    def _get_user_id(self):
353
212
        """Get the user id from the 'email' key in the current section."""
354
213
        return self._get_user_option('email')
355
214
 
356
215
    def _get_user_option(self, option_name):
357
216
        """See Config._get_user_option."""
358
 
        for (section, extra_path) in self._get_matching_sections():
359
 
            try:
360
 
                value = self._get_parser().get_value(section, option_name)
361
 
            except KeyError:
362
 
                continue
363
 
            policy = self._get_option_policy(section, option_name)
364
 
            if policy == POLICY_NONE:
365
 
                return value
366
 
            elif policy == POLICY_NORECURSE:
367
 
                # norecurse items only apply to the exact path
368
 
                if extra_path:
369
 
                    continue
370
 
                else:
371
 
                    return value
372
 
            elif policy == POLICY_APPENDPATH:
373
 
                if extra_path:
374
 
                    value = urlutils.join(value, extra_path)
375
 
                return value
376
 
            else:
377
 
                raise AssertionError('Unexpected config policy %r' % policy)
378
 
        else:
379
 
            return None
 
217
        try:
 
218
            return self._get_parser().get_value(self._get_section(),
 
219
                                                option_name)
 
220
        except KeyError:
 
221
            pass
380
222
 
381
223
    def _gpg_signing_command(self):
382
224
        """See Config.gpg_signing_command."""
383
225
        return self._get_user_option('gpg_signing_command')
384
226
 
385
 
    def _log_format(self):
386
 
        """See Config.log_format."""
387
 
        return self._get_user_option('log_format')
388
 
 
389
227
    def __init__(self, get_filename):
390
228
        super(IniBasedConfig, self).__init__()
391
229
        self._get_filename = get_filename
406
244
        raise errors.BzrError("Invalid signatures policy '%s'"
407
245
                              % signature_string)
408
246
 
409
 
    def _string_to_signing_policy(self, signature_string):
410
 
        """Convert a string to a signing policy."""
411
 
        if signature_string.lower() == 'when-required':
412
 
            return SIGN_WHEN_REQUIRED
413
 
        if signature_string.lower() == 'never':
414
 
            return SIGN_NEVER
415
 
        if signature_string.lower() == 'always':
416
 
            return SIGN_ALWAYS
417
 
        raise errors.BzrError("Invalid signing policy '%s'"
418
 
                              % signature_string)
419
 
 
420
 
    def _get_alias(self, value):
421
 
        try:
422
 
            return self._get_parser().get_value("ALIASES", 
423
 
                                                value)
424
 
        except KeyError:
425
 
            pass
426
 
 
427
 
    def _get_nickname(self):
428
 
        return self.get_user_option('nickname')
429
 
 
430
247
 
431
248
class GlobalConfig(IniBasedConfig):
432
249
    """The configuration that should be used for a specific location."""
437
254
    def __init__(self):
438
255
        super(GlobalConfig, self).__init__(config_filename)
439
256
 
440
 
    def set_user_option(self, option, value):
441
 
        """Save option and its value in the configuration."""
442
 
        # FIXME: RBC 20051029 This should refresh the parser and also take a
443
 
        # file lock on bazaar.conf.
444
 
        conf_dir = os.path.dirname(self._get_filename())
445
 
        ensure_config_dir_exists(conf_dir)
446
 
        if 'DEFAULT' not in self._get_parser():
447
 
            self._get_parser()['DEFAULT'] = {}
448
 
        self._get_parser()['DEFAULT'][option] = value
449
 
        f = open(self._get_filename(), 'wb')
450
 
        self._get_parser().write(f)
451
 
        f.close()
452
 
 
453
257
 
454
258
class LocationConfig(IniBasedConfig):
455
259
    """A configuration object that gives the policy for a location."""
456
260
 
457
261
    def __init__(self, location):
458
 
        name_generator = locations_config_filename
459
 
        if (not os.path.exists(name_generator()) and
460
 
                os.path.exists(branches_config_filename())):
461
 
            if sys.platform == 'win32':
462
 
                trace.warning('Please rename %s to %s'
463
 
                              % (branches_config_filename(),
464
 
                                 locations_config_filename()))
465
 
            else:
466
 
                trace.warning('Please rename ~/.bazaar/branches.conf'
467
 
                              ' to ~/.bazaar/locations.conf')
468
 
            name_generator = branches_config_filename
469
 
        super(LocationConfig, self).__init__(name_generator)
470
 
        # local file locations are looked up by local path, rather than
471
 
        # by file url. This is because the config file is a user
472
 
        # file, and we would rather not expose the user to file urls.
473
 
        if location.startswith('file://'):
474
 
            location = urlutils.local_path_from_url(location)
 
262
        super(LocationConfig, self).__init__(branches_config_filename)
 
263
        self._global_config = None
475
264
        self.location = location
476
265
 
477
 
    def _get_matching_sections(self):
478
 
        """Return an ordered list of section names matching this location."""
 
266
    def _get_global_config(self):
 
267
        if self._global_config is None:
 
268
            self._global_config = GlobalConfig()
 
269
        return self._global_config
 
270
 
 
271
    def _get_section(self):
 
272
        """Get the section we should look in for config items.
 
273
 
 
274
        Returns None if none exists. 
 
275
        TODO: perhaps return a NullSection that thunks through to the 
 
276
              global config.
 
277
        """
479
278
        sections = self._get_parser()
480
279
        location_names = self.location.split('/')
481
280
        if self.location.endswith('/'):
482
281
            del location_names[-1]
483
282
        matches=[]
484
283
        for section in sections:
485
 
            # location is a local path if possible, so we need
486
 
            # to convert 'file://' urls to local paths if necessary.
487
 
            # This also avoids having file:///path be a more exact
488
 
            # match than '/path'.
489
 
            if section.startswith('file://'):
490
 
                section_path = urlutils.local_path_from_url(section)
491
 
            else:
492
 
                section_path = section
493
 
            section_names = section_path.split('/')
 
284
            section_names = section.split('/')
494
285
            if section.endswith('/'):
495
286
                del section_names[-1]
496
287
            names = zip(location_names, section_names)
505
296
            # if section is longer, no match.
506
297
            if len(section_names) > len(location_names):
507
298
                continue
508
 
            matches.append((len(section_names), section,
509
 
                            '/'.join(location_names[len(section_names):])))
 
299
            # if path is longer, and recurse is not true, no match
 
300
            if len(section_names) < len(location_names):
 
301
                try:
 
302
                    if not self._get_parser().get_bool(section, 'recurse'):
 
303
                        continue
 
304
                except KeyError:
 
305
                    pass
 
306
            matches.append((len(section_names), section))
 
307
        if not len(matches):
 
308
            return None
510
309
        matches.sort(reverse=True)
511
 
        sections = []
512
 
        for (length, section, extra_path) in matches:
513
 
            sections.append((section, extra_path))
514
 
            # should we stop looking for parent configs here?
515
 
            try:
516
 
                if self._get_parser()[section].as_bool('ignore_parents'):
517
 
                    break
518
 
            except KeyError:
519
 
                pass
520
 
        return sections
521
 
 
522
 
    def _get_option_policy(self, section, option_name):
523
 
        """Return the policy for the given (section, option_name) pair."""
524
 
        # check for the old 'recurse=False' flag
525
 
        try:
526
 
            recurse = self._get_parser()[section].as_bool('recurse')
527
 
        except KeyError:
528
 
            recurse = True
529
 
        if not recurse:
530
 
            return POLICY_NORECURSE
531
 
 
532
 
        policy_key = option_name + ':policy'
533
 
        try:
534
 
            policy_name = self._get_parser()[section][policy_key]
535
 
        except KeyError:
536
 
            policy_name = None
537
 
 
538
 
        return _policy_value[policy_name]
539
 
 
540
 
    def _set_option_policy(self, section, option_name, option_policy):
541
 
        """Set the policy for the given option name in the given section."""
542
 
        # The old recurse=False option affects all options in the
543
 
        # section.  To handle multiple policies in the section, we
544
 
        # need to convert it to a policy_norecurse key.
545
 
        try:
546
 
            recurse = self._get_parser()[section].as_bool('recurse')
547
 
        except KeyError:
548
 
            pass
549
 
        else:
550
 
            symbol_versioning.warn(
551
 
                'The recurse option is deprecated as of 0.14.  '
552
 
                'The section "%s" has been converted to use policies.'
553
 
                % section,
554
 
                DeprecationWarning)
555
 
            del self._get_parser()[section]['recurse']
556
 
            if not recurse:
557
 
                for key in self._get_parser()[section].keys():
558
 
                    if not key.endswith(':policy'):
559
 
                        self._get_parser()[section][key +
560
 
                                                    ':policy'] = 'norecurse'
561
 
 
562
 
        policy_key = option_name + ':policy'
563
 
        policy_name = _policy_name[option_policy]
564
 
        if policy_name is not None:
565
 
            self._get_parser()[section][policy_key] = policy_name
566
 
        else:
567
 
            if policy_key in self._get_parser()[section]:
568
 
                del self._get_parser()[section][policy_key]
569
 
 
570
 
    def set_user_option(self, option, value, store=STORE_LOCATION):
 
310
        return matches[0][1]
 
311
 
 
312
    def _gpg_signing_command(self):
 
313
        """See Config.gpg_signing_command."""
 
314
        command = super(LocationConfig, self)._gpg_signing_command()
 
315
        if command is not None:
 
316
            return command
 
317
        return self._get_global_config()._gpg_signing_command()
 
318
 
 
319
    def _get_user_id(self):
 
320
        user_id = super(LocationConfig, self)._get_user_id()
 
321
        if user_id is not None:
 
322
            return user_id
 
323
        return self._get_global_config()._get_user_id()
 
324
 
 
325
    def _get_user_option(self, option_name):
 
326
        """See Config._get_user_option."""
 
327
        option_value = super(LocationConfig, 
 
328
                             self)._get_user_option(option_name)
 
329
        if option_value is not None:
 
330
            return option_value
 
331
        return self._get_global_config()._get_user_option(option_name)
 
332
 
 
333
    def _get_signature_checking(self):
 
334
        """See Config._get_signature_checking."""
 
335
        check = super(LocationConfig, self)._get_signature_checking()
 
336
        if check is not None:
 
337
            return check
 
338
        return self._get_global_config()._get_signature_checking()
 
339
 
 
340
    def _post_commit(self):
 
341
        """See Config.post_commit."""
 
342
        hook = self._get_user_option('post_commit')
 
343
        if hook is not None:
 
344
            return hook
 
345
        return self._get_global_config()._post_commit()
 
346
 
 
347
    def set_user_option(self, option, value):
571
348
        """Save option and its value in the configuration."""
572
 
        assert store in [STORE_LOCATION,
573
 
                         STORE_LOCATION_NORECURSE,
574
 
                         STORE_LOCATION_APPENDPATH], 'bad storage policy'
575
349
        # FIXME: RBC 20051029 This should refresh the parser and also take a
576
 
        # file lock on locations.conf.
577
 
        conf_dir = os.path.dirname(self._get_filename())
578
 
        ensure_config_dir_exists(conf_dir)
 
350
        # file lock on branches.conf.
 
351
        if not os.path.isdir(os.path.dirname(self._get_filename())):
 
352
            os.mkdir(os.path.dirname(self._get_filename()))
579
353
        location = self.location
580
354
        if location.endswith('/'):
581
355
            location = location[:-1]
585
359
        elif location + '/' in self._get_parser():
586
360
            location = location + '/'
587
361
        self._get_parser()[location][option]=value
588
 
        # the allowed values of store match the config policies
589
 
        self._set_option_policy(location, option, store)
590
 
        self._get_parser().write(file(self._get_filename(), 'wb'))
 
362
        self._get_parser().write()
591
363
 
592
364
 
593
365
class BranchConfig(Config):
594
366
    """A configuration object giving the policy for a branch."""
595
367
 
596
 
    def _get_branch_data_config(self):
597
 
        if self._branch_data_config is None:
598
 
            self._branch_data_config = TreeConfig(self.branch)
599
 
        return self._branch_data_config
600
 
 
601
368
    def _get_location_config(self):
602
369
        if self._location_config is None:
603
370
            self._location_config = LocationConfig(self.branch.base)
604
371
        return self._location_config
605
372
 
606
 
    def _get_global_config(self):
607
 
        if self._global_config is None:
608
 
            self._global_config = GlobalConfig()
609
 
        return self._global_config
610
 
 
611
 
    def _get_best_value(self, option_name):
612
 
        """This returns a user option from local, tree or global config.
613
 
 
614
 
        They are tried in that order.  Use get_safe_value if trusted values
615
 
        are necessary.
616
 
        """
617
 
        for source in self.option_sources:
618
 
            value = getattr(source(), option_name)()
619
 
            if value is not None:
620
 
                return value
621
 
        return None
622
 
 
623
 
    def _get_safe_value(self, option_name):
624
 
        """This variant of get_best_value never returns untrusted values.
625
 
        
626
 
        It does not return values from the branch data, because the branch may
627
 
        not be controlled by the user.
628
 
 
629
 
        We may wish to allow locations.conf to control whether branches are
630
 
        trusted in the future.
631
 
        """
632
 
        for source in (self._get_location_config, self._get_global_config):
633
 
            value = getattr(source(), option_name)()
634
 
            if value is not None:
635
 
                return value
636
 
        return None
637
 
 
638
373
    def _get_user_id(self):
639
374
        """Return the full user id for the branch.
640
375
    
642
377
        This is looked up in the email controlfile for the branch.
643
378
        """
644
379
        try:
645
 
            return (self.branch.control_files.get_utf8("email") 
 
380
            return (self.branch.controlfile("email", "r") 
646
381
                    .read()
647
382
                    .decode(bzrlib.user_encoding)
648
383
                    .rstrip("\r\n"))
649
384
        except errors.NoSuchFile, e:
650
385
            pass
651
386
        
652
 
        return self._get_best_value('_get_user_id')
 
387
        return self._get_location_config()._get_user_id()
653
388
 
654
389
    def _get_signature_checking(self):
655
390
        """See Config._get_signature_checking."""
656
 
        return self._get_best_value('_get_signature_checking')
657
 
 
658
 
    def _get_signing_policy(self):
659
 
        """See Config._get_signing_policy."""
660
 
        return self._get_best_value('_get_signing_policy')
 
391
        return self._get_location_config()._get_signature_checking()
661
392
 
662
393
    def _get_user_option(self, option_name):
663
394
        """See Config._get_user_option."""
664
 
        for source in self.option_sources:
665
 
            value = source()._get_user_option(option_name)
666
 
            if value is not None:
667
 
                return value
668
 
        return None
669
 
 
670
 
    def set_user_option(self, name, value, store=STORE_BRANCH,
671
 
        warn_masked=False):
672
 
        if store == STORE_BRANCH:
673
 
            self._get_branch_data_config().set_option(value, name)
674
 
        elif store == STORE_GLOBAL:
675
 
            self._get_global_config().set_user_option(name, value)
676
 
        else:
677
 
            self._get_location_config().set_user_option(name, value, store)
678
 
        if not warn_masked:
679
 
            return
680
 
        if store in (STORE_GLOBAL, STORE_BRANCH):
681
 
            mask_value = self._get_location_config().get_user_option(name)
682
 
            if mask_value is not None:
683
 
                trace.warning('Value "%s" is masked by "%s" from'
684
 
                              ' locations.conf', value, mask_value)
685
 
            else:
686
 
                if store == STORE_GLOBAL:
687
 
                    branch_config = self._get_branch_data_config()
688
 
                    mask_value = branch_config.get_user_option(name)
689
 
                    if mask_value is not None:
690
 
                        trace.warning('Value "%s" is masked by "%s" from'
691
 
                                      ' branch.conf', value, mask_value)
692
 
 
 
395
        return self._get_location_config()._get_user_option(option_name)
693
396
 
694
397
    def _gpg_signing_command(self):
695
398
        """See Config.gpg_signing_command."""
696
 
        return self._get_safe_value('_gpg_signing_command')
 
399
        return self._get_location_config()._gpg_signing_command()
697
400
        
698
401
    def __init__(self, branch):
699
402
        super(BranchConfig, self).__init__()
700
403
        self._location_config = None
701
 
        self._branch_data_config = None
702
 
        self._global_config = None
703
404
        self.branch = branch
704
 
        self.option_sources = (self._get_location_config, 
705
 
                               self._get_branch_data_config,
706
 
                               self._get_global_config)
707
405
 
708
406
    def _post_commit(self):
709
407
        """See Config.post_commit."""
710
 
        return self._get_safe_value('_post_commit')
711
 
 
712
 
    def _get_nickname(self):
713
 
        value = self._get_explicit_nickname()
714
 
        if value is not None:
715
 
            return value
716
 
        return urlutils.unescape(self.branch.base.split('/')[-2])
717
 
 
718
 
    def has_explicit_nickname(self):
719
 
        """Return true if a nickname has been explicitly assigned."""
720
 
        return self._get_explicit_nickname() is not None
721
 
 
722
 
    def _get_explicit_nickname(self):
723
 
        return self._get_best_value('_get_nickname')
724
 
 
725
 
    def _log_format(self):
726
 
        """See Config.log_format."""
727
 
        return self._get_best_value('_log_format')
728
 
 
729
 
 
730
 
def ensure_config_dir_exists(path=None):
731
 
    """Make sure a configuration directory exists.
732
 
    This makes sure that the directory exists.
733
 
    On windows, since configuration directories are 2 levels deep,
734
 
    it makes sure both the directory and the parent directory exists.
735
 
    """
736
 
    if path is None:
737
 
        path = config_dir()
738
 
    if not os.path.isdir(path):
739
 
        if sys.platform == 'win32':
740
 
            parent_dir = os.path.dirname(path)
741
 
            if not os.path.isdir(parent_dir):
742
 
                trace.mutter('creating config parent directory: %r', parent_dir)
743
 
            os.mkdir(parent_dir)
744
 
        trace.mutter('creating config directory: %r', path)
745
 
        os.mkdir(path)
 
408
        return self._get_location_config()._post_commit()
746
409
 
747
410
 
748
411
def config_dir():
755
418
    base = os.environ.get('BZR_HOME', None)
756
419
    if sys.platform == 'win32':
757
420
        if base is None:
758
 
            base = win32utils.get_appdata_location_unicode()
 
421
            base = os.environ.get('APPDATA', None)
759
422
        if base is None:
760
423
            base = os.environ.get('HOME', None)
761
424
        if base is None:
762
 
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
763
 
        return osutils.pathjoin(base, 'bazaar', '2.0')
 
425
            raise BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
 
426
        return os.path.join(base, 'bazaar', '2.0')
764
427
    else:
765
428
        # cygwin, linux, and darwin all have a $HOME directory
766
429
        if base is None:
767
430
            base = os.path.expanduser("~")
768
 
        return osutils.pathjoin(base, ".bazaar")
 
431
        return os.path.join(base, ".bazaar")
769
432
 
770
433
 
771
434
def config_filename():
772
435
    """Return per-user configuration ini file filename."""
773
 
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
 
436
    return os.path.join(config_dir(), 'bazaar.conf')
774
437
 
775
438
 
776
439
def branches_config_filename():
777
440
    """Return per-user configuration ini file filename."""
778
 
    return osutils.pathjoin(config_dir(), 'branches.conf')
779
 
 
780
 
 
781
 
def locations_config_filename():
782
 
    """Return per-user configuration ini file filename."""
783
 
    return osutils.pathjoin(config_dir(), 'locations.conf')
784
 
 
785
 
 
786
 
def authentication_config_filename():
787
 
    """Return per-user authentication ini file filename."""
788
 
    return osutils.pathjoin(config_dir(), 'authentication.conf')
789
 
 
790
 
 
791
 
def user_ignore_config_filename():
792
 
    """Return the user default ignore filename"""
793
 
    return osutils.pathjoin(config_dir(), 'ignore')
 
441
    return os.path.join(config_dir(), 'branches.conf')
794
442
 
795
443
 
796
444
def _auto_user_id():
806
454
    """
807
455
    import socket
808
456
 
809
 
    if sys.platform == 'win32':
810
 
        name = win32utils.get_user_name_unicode()
811
 
        if name is None:
812
 
            raise errors.BzrError("Cannot autodetect user name.\n"
813
 
                                  "Please, set your name with command like:\n"
814
 
                                  'bzr whoami "Your Name <name@domain.com>"')
815
 
        host = win32utils.get_host_name_unicode()
816
 
        if host is None:
817
 
            host = socket.gethostname()
818
 
        return name, (name + '@' + host)
 
457
    # XXX: Any good way to get real user name on win32?
819
458
 
820
459
    try:
821
460
        import pwd
822
461
        uid = os.getuid()
823
462
        w = pwd.getpwuid(uid)
824
 
 
825
 
        # we try utf-8 first, because on many variants (like Linux),
826
 
        # /etc/passwd "should" be in utf-8, and because it's unlikely to give
827
 
        # false positives.  (many users will have their user encoding set to
828
 
        # latin-1, which cannot raise UnicodeError.)
829
 
        try:
830
 
            gecos = w.pw_gecos.decode('utf-8')
831
 
            encoding = 'utf-8'
832
 
        except UnicodeError:
833
 
            try:
834
 
                gecos = w.pw_gecos.decode(bzrlib.user_encoding)
835
 
                encoding = bzrlib.user_encoding
836
 
            except UnicodeError:
837
 
                raise errors.BzrCommandError('Unable to determine your name.  '
838
 
                   'Use "bzr whoami" to set it.')
839
 
        try:
840
 
            username = w.pw_name.decode(encoding)
841
 
        except UnicodeError:
842
 
            raise errors.BzrCommandError('Unable to determine your name.  '
843
 
                'Use "bzr whoami" to set it.')
844
 
 
 
463
        gecos = w.pw_gecos.decode(bzrlib.user_encoding)
 
464
        username = w.pw_name.decode(bzrlib.user_encoding)
845
465
        comma = gecos.find(',')
846
466
        if comma == -1:
847
467
            realname = gecos
852
472
 
853
473
    except ImportError:
854
474
        import getpass
855
 
        try:
856
 
            realname = username = getpass.getuser().decode(bzrlib.user_encoding)
857
 
        except UnicodeDecodeError:
858
 
            raise errors.BzrError("Can't decode username as %s." % \
859
 
                    bzrlib.user_encoding)
 
475
        realname = username = getpass.getuser().decode(bzrlib.user_encoding)
860
476
 
861
477
    return realname, (username + '@' + socket.gethostname())
862
478
 
873
489
    """
874
490
    m = re.search(r'[\w+.-]+@[\w+.-]+', e)
875
491
    if not m:
876
 
        raise errors.NoEmailInUsername(e)
 
492
        raise errors.BzrError("%r doesn't seem to contain "
 
493
                              "a reasonable email address" % e)
877
494
    return m.group(0)
878
495
 
879
 
 
880
 
class TreeConfig(IniBasedConfig):
 
496
class TreeConfig(object):
881
497
    """Branch configuration data associated with its contents, not location"""
882
 
 
883
498
    def __init__(self, branch):
884
499
        self.branch = branch
885
500
 
886
 
    def _get_parser(self, file=None):
887
 
        if file is not None:
888
 
            return IniBasedConfig._get_parser(file)
889
 
        return self._get_config()
890
 
 
891
501
    def _get_config(self):
892
502
        try:
893
 
            obj = ConfigObj(self.branch.control_files.get('branch.conf'),
894
 
                            encoding='utf-8')
 
503
            obj = ConfigObj(self.branch.controlfile('branch.conf',
 
504
                                                    'rb').readlines())
 
505
            obj.decode('UTF-8')
895
506
        except errors.NoSuchFile:
896
 
            obj = ConfigObj(encoding='utf=8')
 
507
            obj = ConfigObj()
897
508
        return obj
898
509
 
899
510
    def get_option(self, name, section=None, default=None):
902
513
            obj = self._get_config()
903
514
            try:
904
515
                if section is not None:
905
 
                    obj = obj[section]
 
516
                    obj[section]
906
517
                result = obj[name]
907
518
            except KeyError:
908
519
                result = default
924
535
                    cfg_obj[section] = {}
925
536
                    obj = cfg_obj[section]
926
537
            obj[name] = value
927
 
            out_file = StringIO()
928
 
            cfg_obj.write(out_file)
 
538
            cfg_obj.encode('UTF-8')
 
539
            out_file = StringIO(''.join([l+'\n' for l in cfg_obj.write()]))
929
540
            out_file.seek(0)
930
 
            self.branch.control_files.put('branch.conf', out_file)
 
541
            self.branch.put_controlfile('branch.conf', out_file, encode=False)
931
542
        finally:
932
543
            self.branch.unlock()
933
 
 
934
 
 
935
 
class AuthenticationConfig(object):
936
 
    """The authentication configuration file based on a ini file.
937
 
 
938
 
    Implements the authentication.conf file described in
939
 
    doc/developers/authentication-ring.txt.
940
 
    """
941
 
 
942
 
    def __init__(self, _file=None):
943
 
        self._config = None # The ConfigObj
944
 
        if _file is None:
945
 
            self._filename = authentication_config_filename()
946
 
            self._input = self._filename = authentication_config_filename()
947
 
        else:
948
 
            # Tests can provide a string as _file
949
 
            self._filename = None
950
 
            self._input = _file
951
 
 
952
 
    def _get_config(self):
953
 
        if self._config is not None:
954
 
            return self._config
955
 
        try:
956
 
            # FIXME: Should we validate something here ? Includes: empty
957
 
            # sections are useless, at least one of
958
 
            # user/password/password_encoding should be defined, etc.
959
 
 
960
 
            # Note: the encoding below declares that the file itself is utf-8
961
 
            # encoded, but the values in the ConfigObj are always Unicode.
962
 
            self._config = ConfigObj(self._input, encoding='utf-8')
963
 
        except configobj.ConfigObjError, e:
964
 
            raise errors.ParseConfigError(e.errors, e.config.filename)
965
 
        return self._config
966
 
 
967
 
    def _save(self):
968
 
        """Save the config file, only tests should use it for now."""
969
 
        conf_dir = os.path.dirname(self._filename)
970
 
        ensure_config_dir_exists(conf_dir)
971
 
        self._get_config().write(file(self._filename, 'wb'))
972
 
 
973
 
    def _set_option(self, section_name, option_name, value):
974
 
        """Set an authentication configuration option"""
975
 
        conf = self._get_config()
976
 
        section = conf.get(section_name)
977
 
        if section is None:
978
 
            conf[section] = {}
979
 
            section = conf[section]
980
 
        section[option_name] = value
981
 
        self._save()
982
 
 
983
 
    def get_credentials(self, scheme, host, port=None, user=None, path=None):
984
 
        """Returns the matching credentials from authentication.conf file.
985
 
 
986
 
        :param scheme: protocol
987
 
 
988
 
        :param host: the server address
989
 
 
990
 
        :param port: the associated port (optional)
991
 
 
992
 
        :param user: login (optional)
993
 
 
994
 
        :param path: the absolute path on the server (optional)
995
 
 
996
 
        :return: A dict containing the matching credentials or None.
997
 
           This includes:
998
 
           - name: the section name of the credentials in the
999
 
             authentication.conf file,
1000
 
           - user: can't de different from the provided user if any,
1001
 
           - password: the decoded password, could be None if the credential
1002
 
             defines only the user
1003
 
           - verify_certificates: https specific, True if the server
1004
 
             certificate should be verified, False otherwise.
1005
 
        """
1006
 
        credentials = None
1007
 
        for auth_def_name, auth_def in self._get_config().items():
1008
 
            a_scheme, a_host, a_user, a_path = map(
1009
 
                auth_def.get, ['scheme', 'host', 'user', 'path'])
1010
 
 
1011
 
            try:
1012
 
                a_port = auth_def.as_int('port')
1013
 
            except KeyError:
1014
 
                a_port = None
1015
 
            except ValueError:
1016
 
                raise ValueError("'port' not numeric in %s" % auth_def_name)
1017
 
            try:
1018
 
                a_verify_certificates = auth_def.as_bool('verify_certificates')
1019
 
            except KeyError:
1020
 
                a_verify_certificates = True
1021
 
            except ValueError:
1022
 
                raise ValueError(
1023
 
                    "'verify_certificates' not boolean in %s" % auth_def_name)
1024
 
 
1025
 
            # Attempt matching
1026
 
            if a_scheme is not None and scheme != a_scheme:
1027
 
                continue
1028
 
            if a_host is not None:
1029
 
                if not (host == a_host
1030
 
                        or (a_host.startswith('.') and host.endswith(a_host))):
1031
 
                    continue
1032
 
            if a_port is not None and port != a_port:
1033
 
                continue
1034
 
            if (a_path is not None and path is not None
1035
 
                and not path.startswith(a_path)):
1036
 
                continue
1037
 
            if (a_user is not None and user is not None
1038
 
                and a_user != user):
1039
 
                # Never contradict the caller about the user to be used
1040
 
                continue
1041
 
            if a_user is None:
1042
 
                # Can't find a user
1043
 
                continue
1044
 
            credentials = dict(name=auth_def_name,
1045
 
                               user=a_user, password=auth_def['password'],
1046
 
                               verify_certificates=a_verify_certificates)
1047
 
            self.decode_password(credentials,
1048
 
                                 auth_def.get('password_encoding', None))
1049
 
            if 'auth' in debug.debug_flags:
1050
 
                trace.mutter("Using authentication section: %r", auth_def_name)
1051
 
            break
1052
 
 
1053
 
        return credentials
1054
 
 
1055
 
    def get_user(self, scheme, host, port=None,
1056
 
                 realm=None, path=None, prompt=None):
1057
 
        """Get a user from authentication file.
1058
 
 
1059
 
        :param scheme: protocol
1060
 
 
1061
 
        :param host: the server address
1062
 
 
1063
 
        :param port: the associated port (optional)
1064
 
 
1065
 
        :param realm: the realm sent by the server (optional)
1066
 
 
1067
 
        :param path: the absolute path on the server (optional)
1068
 
 
1069
 
        :return: The found user.
1070
 
        """
1071
 
        credentials = self.get_credentials(scheme, host, port, user=None,
1072
 
                                           path=path)
1073
 
        if credentials is not None:
1074
 
            user = credentials['user']
1075
 
        else:
1076
 
            user = None
1077
 
        return user
1078
 
 
1079
 
    def get_password(self, scheme, host, user, port=None,
1080
 
                     realm=None, path=None, prompt=None):
1081
 
        """Get a password from authentication file or prompt the user for one.
1082
 
 
1083
 
        :param scheme: protocol
1084
 
 
1085
 
        :param host: the server address
1086
 
 
1087
 
        :param port: the associated port (optional)
1088
 
 
1089
 
        :param user: login
1090
 
 
1091
 
        :param realm: the realm sent by the server (optional)
1092
 
 
1093
 
        :param path: the absolute path on the server (optional)
1094
 
 
1095
 
        :return: The found password or the one entered by the user.
1096
 
        """
1097
 
        credentials = self.get_credentials(scheme, host, port, user, path)
1098
 
        if credentials is not None:
1099
 
            password = credentials['password']
1100
 
        else:
1101
 
            password = None
1102
 
        # Prompt user only if we could't find a password
1103
 
        if password is None:
1104
 
            if prompt is None:
1105
 
                # Create a default prompt suitable for most of the cases
1106
 
                prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1107
 
            # Special handling for optional fields in the prompt
1108
 
            if port is not None:
1109
 
                prompt_host = '%s:%d' % (host, port)
1110
 
            else:
1111
 
                prompt_host = host
1112
 
            password = ui.ui_factory.get_password(prompt,
1113
 
                                                  host=prompt_host, user=user)
1114
 
        return password
1115
 
 
1116
 
    def decode_password(self, credentials, encoding):
1117
 
        return credentials