/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 breezy/config.py

  • Committer: Jelmer Vernooij
  • Date: 2017-07-23 22:06:41 UTC
  • mfrom: (6738 trunk)
  • mto: This revision was merged to the branch mainline in revision 6739.
  • Revision ID: jelmer@jelmer.uk-20170723220641-69eczax9bmv8d6kk
Merge trunk, address review comments.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
# along with this program; if not, write to the Free Software
17
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 
19
 
"""Configuration that affects the behaviour of Breezy.
20
 
 
21
 
Currently this configuration resides in ~/.config/breezy/breezy.conf
22
 
and ~/.config/breezy/locations.conf, which is written to by brz.
23
 
 
24
 
If the first location doesn't exist, then brz falls back to reading
25
 
Bazaar configuration files in ~/.bazaar or ~/.config/bazaar.
26
 
 
27
 
In breezy.conf the following options may be set:
 
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 brz.
 
23
 
 
24
In bazaar.conf the following options may be set:
28
25
[DEFAULT]
29
26
editor=name-of-program
30
27
email=Your Name <your@email.address>
37
34
 
38
35
in locations.conf, you specify the url of a branch and options for it.
39
36
Wildcards may be used - * and ? as normal in shell completion. Options
40
 
set in both breezy.conf and locations.conf are overridden by the locations.conf
 
37
set in both bazaar.conf and locations.conf are overridden by the locations.conf
41
38
setting.
42
39
[/home/robertc/source]
43
40
recurse=False|True(default)
53
50
email - this option sets the user id brz will use when committing.
54
51
check_signatures - this option will control whether brz will require good gpg
55
52
                   signatures, ignore them, or check them if they are
56
 
                   present.  Currently it is unused except that
57
 
                   check_signatures turns on create_signatures.
 
53
                   present.  Currently it is unused except that check_signatures
 
54
                   turns on create_signatures.
58
55
create_signatures - this option controls whether brz will always create
59
56
                    gpg signatures or not on commits.  There is an unused
60
57
                    option which in future is expected to work if
65
62
acceptable_keys - comma separated list of key patterns acceptable for
66
63
                  verify-signatures command
67
64
 
68
 
In breezy.conf you can also define aliases in the ALIASES sections, example
 
65
In bazaar.conf you can also define aliases in the ALIASES sections, example
69
66
 
70
67
[ALIASES]
71
68
lastlog=log --line -r-10..-1
74
71
up=pull
75
72
"""
76
73
 
 
74
from __future__ import absolute_import
77
75
import os
78
76
import sys
79
77
 
80
78
import configobj
81
 
from io import BytesIO
82
79
 
83
80
import breezy
 
81
from .decorators import needs_write_lock
84
82
from .lazy_import import lazy_import
85
83
lazy_import(globals(), """
86
84
import base64
90
88
import stat
91
89
 
92
90
from breezy import (
93
 
    cmdline,
 
91
    atomicfile,
94
92
    controldir,
95
93
    debug,
96
94
    directory_service,
97
 
    lock,
 
95
    lazy_regex,
 
96
    library_state,
98
97
    lockdir,
99
98
    mergetools,
100
99
    osutils,
108
107
""")
109
108
from . import (
110
109
    commands,
111
 
    bedding,
112
110
    errors,
113
111
    hooks,
114
112
    lazy_regex,
115
113
    registry,
116
114
    )
117
 
 
118
 
 
119
 
CHECK_IF_POSSIBLE = 0
120
 
CHECK_ALWAYS = 1
121
 
CHECK_NEVER = 2
122
 
 
123
 
 
124
 
SIGN_WHEN_REQUIRED = 0
125
 
SIGN_ALWAYS = 1
126
 
SIGN_NEVER = 2
 
115
from .sixish import (
 
116
    binary_type,
 
117
    BytesIO,
 
118
    PY3,
 
119
    text_type,
 
120
    string_types,
 
121
    )
 
122
 
 
123
 
 
124
CHECK_IF_POSSIBLE=0
 
125
CHECK_ALWAYS=1
 
126
CHECK_NEVER=2
 
127
 
 
128
 
 
129
SIGN_WHEN_REQUIRED=0
 
130
SIGN_ALWAYS=1
 
131
SIGN_NEVER=2
127
132
 
128
133
 
129
134
POLICY_NONE = 0
226
231
        errors.BzrError.__init__(self, option_name=option_name)
227
232
 
228
233
 
 
234
class NoWhoami(errors.BzrError):
 
235
 
 
236
    _fmt = ('Unable to determine your name.\n'
 
237
        "Please, set your name with the 'whoami' command.\n"
 
238
        'E.g. brz whoami "Your Name <name@example.com>"')
 
239
 
 
240
 
229
241
def signature_policy_from_unicode(signature_string):
230
242
    """Convert a string to a signing policy."""
231
243
    if signature_string.lower() == 'check-available':
250
262
                     % signature_string)
251
263
 
252
264
 
 
265
def _has_decode_bug():
 
266
    """True if configobj will fail to decode to unicode on Python 2."""
 
267
    if sys.version_info > (3,):
 
268
        return False
 
269
    conf = configobj.ConfigObj()
 
270
    decode = getattr(conf, "_decode", None)
 
271
    if decode:
 
272
        result = decode(b"\xc2\xa7", "utf-8")
 
273
        if isinstance(result[0], str):
 
274
            return True
 
275
    return False
 
276
 
 
277
 
253
278
def _has_triplequote_bug():
254
279
    """True if triple quote logic is reversed, see lp:710410."""
255
280
    conf = configobj.ConfigObj()
267
292
                                        interpolation=False,
268
293
                                        **kwargs)
269
294
 
 
295
    if _has_decode_bug():
 
296
        def _decode(self, infile, encoding):
 
297
            if isinstance(infile, str) and encoding:
 
298
                return infile.decode(encoding).splitlines(True)
 
299
            return super(ConfigObj, self)._decode(infile, encoding)
 
300
 
270
301
    if _has_triplequote_bug():
271
302
        def _get_triple_quote(self, value):
272
303
            quot = super(ConfigObj, self)._get_triple_quote(value)
302
333
        cmd = self._get_change_editor()
303
334
        if cmd is None:
304
335
            return None
305
 
        cmd = cmd.replace('@old_path', '{old_path}')
306
 
        cmd = cmd.replace('@new_path', '{new_path}')
307
 
        cmd = cmdline.split(cmd)
308
 
        if '{old_path}' not in cmd:
309
 
            cmd.extend(['{old_path}', '{new_path}'])
310
336
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
311
337
                                             sys.stdout)
312
338
 
493
519
            otherwise.
494
520
        """
495
521
        l = self.get_user_option(option_name, expand=expand)
496
 
        if isinstance(l, str):
 
522
        if isinstance(l, string_types):
497
523
            # A single value, most probably the user forgot (or didn't care to
498
524
            # add) the final ','
499
525
            l = [l]
529
555
 
530
556
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
531
557
 
532
 
        $BRZ_EMAIL or $BZR_EMAIL can be set to override this, then
 
558
        $BRZ_EMAIL can be set to override this, then
533
559
        the concrete policy type is checked, and finally
534
560
        $EMAIL is examined.
535
561
        If no username can be found, NoWhoami exception is raised.
536
562
        """
537
 
        v = os.environ.get('BRZ_EMAIL') or os.environ.get('BZR_EMAIL')
 
563
        v = os.environ.get('BRZ_EMAIL')
538
564
        if v:
 
565
            if not PY3:
 
566
                v = v.decode(osutils.get_user_encoding())
539
567
            return v
540
568
        v = self._get_user_id()
541
569
        if v:
542
570
            return v
543
 
        return bedding.default_email()
 
571
        return default_email()
 
572
 
 
573
    def ensure_username(self):
 
574
        """Raise NoWhoami if username is not set.
 
575
 
 
576
        This method relies on the username() function raising the error.
 
577
        """
 
578
        self.username()
544
579
 
545
580
    def get_alias(self, value):
546
581
        return self._get_alias(value)
591
626
        # This should be done through the proposed config defaults mechanism
592
627
        # when it becomes available in the future.
593
628
        command_line = (self.get_user_option('bzr.mergetool.%s' % name,
594
 
                                             expand=False) or
595
 
                        mergetools.known_merge_tools.get(name, None))
 
629
                                             expand=False)
 
630
                        or mergetools.known_merge_tools.get(name, None))
596
631
        return command_line
597
632
 
598
633
 
628
663
                      'Invoked when a config option is removed.'
629
664
                      ' The signature is (stack, name).',
630
665
                      (2, 4))
631
 
 
632
 
 
633
666
ConfigHooks = _ConfigHooks()
634
667
 
635
668
 
643
676
        These are all empty initially, because by default nothing should get
644
677
        notified.
645
678
        """
646
 
        super(_OldConfigHooks, self).__init__(
647
 
            'breezy.config', 'OldConfigHooks')
 
679
        super(_OldConfigHooks, self).__init__('breezy.config', 'OldConfigHooks')
648
680
        self.add_hook('load',
649
681
                      'Invoked when a config store is loaded.'
650
682
                      ' The signature is (config).',
666
698
                      'Invoked when a config option is removed.'
667
699
                      ' The signature is (config, name).',
668
700
                      (2, 4))
669
 
 
670
 
 
671
701
OldConfigHooks = _OldConfigHooks()
672
702
 
673
703
 
689
719
    def from_string(cls, str_or_unicode, file_name=None, save=False):
690
720
        """Create a config object from a string.
691
721
 
692
 
        :param str_or_unicode: A string representing the file content. This
693
 
            will be utf-8 encoded.
 
722
        :param str_or_unicode: A string representing the file content. This will
 
723
            be utf-8 encoded.
694
724
 
695
725
        :param file_name: The configuration file path.
696
726
 
701
731
        return conf
702
732
 
703
733
    def _create_from_string(self, str_or_unicode, save):
704
 
        if isinstance(str_or_unicode, str):
705
 
            str_or_unicode = str_or_unicode.encode('utf-8')
706
 
        self._content = BytesIO(str_or_unicode)
 
734
        self._content = BytesIO(str_or_unicode.encode('utf-8'))
707
735
        # Some tests use in-memory configs, some other always need the config
708
736
        # file to exist on disk.
709
737
        if save:
785
813
            which sections should be searched. This is a list of (name,
786
814
            configobj) tuples.
787
815
        """
 
816
        opts = []
788
817
        if sections is None:
789
818
            parser = self._get_parser()
790
819
            sections = []
808
837
        return POLICY_NONE
809
838
 
810
839
    def _get_change_editor(self):
811
 
        return self.get_user_option('change_editor', expand=False)
 
840
        return self.get_user_option('change_editor')
812
841
 
813
842
    def _get_signature_checking(self):
814
843
        """See Config._get_signature_checking."""
902
931
    def _write_config_file(self):
903
932
        if self.file_name is None:
904
933
            raise AssertionError('We cannot save, self.file_name is None')
905
 
        from . import atomicfile
906
934
        conf_dir = os.path.dirname(self.file_name)
907
 
        bedding.ensure_config_dir_exists(conf_dir)
908
 
        with atomicfile.AtomicFile(self.file_name) as atomic_file:
909
 
            self._get_parser().write(atomic_file)
 
935
        ensure_config_dir_exists(conf_dir)
 
936
        atomic_file = atomicfile.AtomicFile(self.file_name)
 
937
        self._get_parser().write(atomic_file)
 
938
        atomic_file.commit()
 
939
        atomic_file.close()
910
940
        osutils.copy_ownership_from_path(self.file_name)
911
941
        for hook in OldConfigHooks['save']:
912
942
            hook(self)
918
948
    If several processes try to write the config file, the accesses need to be
919
949
    serialized.
920
950
 
921
 
    Daughter classes should use the self.lock_write() decorator method when
922
 
    they upate a config (they call, directly or indirectly, the
 
951
    Daughter classes should decorate all methods that update a config with the
 
952
    ``@needs_write_lock`` decorator (they call, directly or indirectly, the
923
953
    ``_write_config_file()`` method. These methods (typically ``set_option()``
924
954
    and variants must reload the config file from disk before calling
925
955
    ``_write_config_file()``), this can be achieved by calling the
964
994
 
965
995
        If the directory doesn't exist it is created.
966
996
        """
967
 
        bedding.ensure_config_dir_exists(self.dir)
968
 
        token = self._lock.lock_write(token)
969
 
        return lock.LogicalLockResult(self.unlock, token)
 
997
        ensure_config_dir_exists(self.dir)
 
998
        return self._lock.lock_write(token)
970
999
 
971
1000
    def unlock(self):
972
1001
        self._lock.unlock()
974
1003
    def break_lock(self):
975
1004
        self._lock.break_lock()
976
1005
 
 
1006
    @needs_write_lock
977
1007
    def remove_user_option(self, option_name, section_name=None):
978
 
        with self.lock_write():
979
 
            super(LockableConfig, self).remove_user_option(
980
 
                option_name, section_name)
 
1008
        super(LockableConfig, self).remove_user_option(option_name,
 
1009
                                                       section_name)
981
1010
 
982
1011
    def _write_config_file(self):
983
1012
        if self._lock is None or not self._lock.is_held:
984
1013
            # NB: if the following exception is raised it probably means a
985
 
            # missing call to lock_write() by one of the callers.
 
1014
            # missing @needs_write_lock decorator on one of the callers.
986
1015
            raise errors.ObjectNotLocked(self)
987
1016
        super(LockableConfig, self)._write_config_file()
988
1017
 
991
1020
    """The configuration that should be used for a specific location."""
992
1021
 
993
1022
    def __init__(self):
994
 
        super(GlobalConfig, self).__init__(file_name=bedding.config_path())
 
1023
        super(GlobalConfig, self).__init__(file_name=config_filename())
995
1024
 
996
1025
    def config_id(self):
997
 
        return 'breezy'
 
1026
        return 'bazaar'
998
1027
 
999
1028
    @classmethod
1000
1029
    def from_string(cls, str_or_unicode, save=False):
1009
1038
        conf._create_from_string(str_or_unicode, save)
1010
1039
        return conf
1011
1040
 
 
1041
    @needs_write_lock
1012
1042
    def set_user_option(self, option, value):
1013
1043
        """Save option and its value in the configuration."""
1014
 
        with self.lock_write():
1015
 
            self._set_option(option, value, 'DEFAULT')
 
1044
        self._set_option(option, value, 'DEFAULT')
1016
1045
 
1017
1046
    def get_aliases(self):
1018
1047
        """Return the aliases section."""
1021
1050
        else:
1022
1051
            return {}
1023
1052
 
 
1053
    @needs_write_lock
1024
1054
    def set_alias(self, alias_name, alias_command):
1025
1055
        """Save the alias in the configuration."""
1026
 
        with self.lock_write():
1027
 
            self._set_option(alias_name, alias_command, 'ALIASES')
 
1056
        self._set_option(alias_name, alias_command, 'ALIASES')
1028
1057
 
 
1058
    @needs_write_lock
1029
1059
    def unset_alias(self, alias_name):
1030
1060
        """Unset an existing alias."""
1031
 
        with self.lock_write():
1032
 
            self.reload()
1033
 
            aliases = self._get_parser().get('ALIASES')
1034
 
            if not aliases or alias_name not in aliases:
1035
 
                raise errors.NoSuchAlias(alias_name)
1036
 
            del aliases[alias_name]
1037
 
            self._write_config_file()
 
1061
        self.reload()
 
1062
        aliases = self._get_parser().get('ALIASES')
 
1063
        if not aliases or alias_name not in aliases:
 
1064
            raise errors.NoSuchAlias(alias_name)
 
1065
        del aliases[alias_name]
 
1066
        self._write_config_file()
1038
1067
 
1039
1068
    def _set_option(self, option, value, section):
1040
1069
        self.reload()
1053
1082
            # doesn't exist yet. So we force DEFAULT when yielding
1054
1083
            name = 'DEFAULT'
1055
1084
            if 'DEFAULT' not in parser:
1056
 
                parser['DEFAULT'] = {}
 
1085
               parser['DEFAULT']= {}
1057
1086
        yield (name, parser[name], self.config_id())
1058
1087
 
 
1088
    @needs_write_lock
1059
1089
    def remove_user_option(self, option_name, section_name=None):
1060
1090
        if section_name is None:
1061
1091
            # We need to force the default section.
1062
1092
            section_name = 'DEFAULT'
1063
 
        with self.lock_write():
1064
 
            # We need to avoid the LockableConfig implementation or we'll lock
1065
 
            # twice
1066
 
            super(LockableConfig, self).remove_user_option(
1067
 
                option_name, section_name)
1068
 
 
 
1093
        # We need to avoid the LockableConfig implementation or we'll lock
 
1094
        # twice
 
1095
        super(LockableConfig, self).remove_user_option(option_name,
 
1096
                                                       section_name)
1069
1097
 
1070
1098
def _iter_for_location_by_parts(sections, location):
1071
1099
    """Keep only the sessions matching the specified location.
1123
1151
 
1124
1152
    def __init__(self, location):
1125
1153
        super(LocationConfig, self).__init__(
1126
 
            file_name=bedding.locations_config_path())
 
1154
            file_name=locations_config_filename())
1127
1155
        # local file locations are looked up by local path, rather than
1128
1156
        # by file url. This is because the config file is a user
1129
1157
        # file, and we would rather not expose the user to file urls.
1201
1229
            if policy_key in self._get_parser()[section]:
1202
1230
                del self._get_parser()[section][policy_key]
1203
1231
 
 
1232
    @needs_write_lock
1204
1233
    def set_user_option(self, option, value, store=STORE_LOCATION):
1205
1234
        """Save option and its value in the configuration."""
1206
1235
        if store not in [STORE_LOCATION,
1207
1236
                         STORE_LOCATION_NORECURSE,
1208
1237
                         STORE_LOCATION_APPENDPATH]:
1209
1238
            raise ValueError('bad storage policy %r for %r' %
1210
 
                             (store, option))
1211
 
        with self.lock_write():
1212
 
            self.reload()
1213
 
            location = self.location
1214
 
            if location.endswith('/'):
1215
 
                location = location[:-1]
1216
 
            parser = self._get_parser()
1217
 
            if location not in parser and not location + '/' in parser:
1218
 
                parser[location] = {}
1219
 
            elif location + '/' in parser:
1220
 
                location = location + '/'
1221
 
            parser[location][option] = value
1222
 
            # the allowed values of store match the config policies
1223
 
            self._set_option_policy(location, option, store)
1224
 
            self._write_config_file()
1225
 
            for hook in OldConfigHooks['set']:
1226
 
                hook(self, option, value)
 
1239
                (store, option))
 
1240
        self.reload()
 
1241
        location = self.location
 
1242
        if location.endswith('/'):
 
1243
            location = location[:-1]
 
1244
        parser = self._get_parser()
 
1245
        if not location in parser and not location + '/' in parser:
 
1246
            parser[location] = {}
 
1247
        elif location + '/' in parser:
 
1248
            location = location + '/'
 
1249
        parser[location][option]=value
 
1250
        # the allowed values of store match the config policies
 
1251
        self._set_option_policy(location, option, store)
 
1252
        self._write_config_file()
 
1253
        for hook in OldConfigHooks['set']:
 
1254
            hook(self, option, value)
1227
1255
 
1228
1256
 
1229
1257
class BranchConfig(Config):
1319
1347
                yield section
1320
1348
 
1321
1349
    def _get_options(self, sections=None):
 
1350
        opts = []
1322
1351
        # First the locations options
1323
1352
        for option in self._get_location_config()._get_options():
1324
1353
            yield option
1338
1367
            yield option
1339
1368
 
1340
1369
    def set_user_option(self, name, value, store=STORE_BRANCH,
1341
 
                        warn_masked=False):
 
1370
        warn_masked=False):
1342
1371
        if store == STORE_BRANCH:
1343
1372
            self._get_branch_data_config().set_option(value, name)
1344
1373
        elif store == STORE_GLOBAL:
1395
1424
        return self._get_best_value('_acceptable_keys')
1396
1425
 
1397
1426
 
 
1427
def ensure_config_dir_exists(path=None):
 
1428
    """Make sure a configuration directory exists.
 
1429
    This makes sure that the directory exists.
 
1430
    On windows, since configuration directories are 2 levels deep,
 
1431
    it makes sure both the directory and the parent directory exists.
 
1432
    """
 
1433
    if path is None:
 
1434
        path = config_dir()
 
1435
    if not os.path.isdir(path):
 
1436
        if sys.platform == 'win32':
 
1437
            parent_dir = os.path.dirname(path)
 
1438
            if not os.path.isdir(parent_dir):
 
1439
                trace.mutter('creating config parent directory: %r', parent_dir)
 
1440
                os.mkdir(parent_dir)
 
1441
        trace.mutter('creating config directory: %r', path)
 
1442
        os.mkdir(path)
 
1443
        osutils.copy_ownership_from_path(path)
 
1444
 
 
1445
 
 
1446
def bazaar_config_dir():
 
1447
    """Return per-user configuration directory as unicode string
 
1448
 
 
1449
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
 
1450
    and Linux.  On Mac OS X and Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
 
1451
    that will be used instead.
 
1452
 
 
1453
    TODO: Global option --config-dir to override this.
 
1454
    """
 
1455
    base = osutils.path_from_environ('BZR_HOME')
 
1456
    if sys.platform == 'win32':
 
1457
        if base is None:
 
1458
            base = win32utils.get_appdata_location()
 
1459
        if base is None:
 
1460
            base = win32utils.get_home_location()
 
1461
        # GZ 2012-02-01: Really the two level subdirs only make sense inside
 
1462
        #                APPDATA, but hard to move. See bug 348640 for more.
 
1463
        return osutils.pathjoin(base, 'bazaar', '2.0')
 
1464
    if base is None:
 
1465
        xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
 
1466
        if xdg_dir is None:
 
1467
            xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
 
1468
        xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
 
1469
        if osutils.isdir(xdg_dir):
 
1470
            trace.mutter(
 
1471
                "Using configuration in XDG directory %s." % xdg_dir)
 
1472
            return xdg_dir
 
1473
        base = osutils._get_home_dir()
 
1474
    return osutils.pathjoin(base, ".bazaar")
 
1475
 
 
1476
 
 
1477
def config_dir():
 
1478
    """Return per-user configuration directory as unicode string
 
1479
 
 
1480
    By default this is %APPDATA%/breezy on Windows, $XDG_CONFIG_HOME/breezy on
 
1481
    Mac OS X and Linux. If the breezy config directory doesn't exist but
 
1482
    the bazaar one (see bazaar_config_dir()) does, use that instead.
 
1483
 
 
1484
    TODO: Global option --config-dir to override this.
 
1485
    """
 
1486
    base = osutils.path_from_environ('BRZ_HOME')
 
1487
    if sys.platform == 'win32':
 
1488
        if base is None:
 
1489
            base = win32utils.get_appdata_location()
 
1490
        if base is None:
 
1491
            base = win32utils.get_home_location()
 
1492
        # GZ 2012-02-01: Really the two level subdirs only make sense inside
 
1493
        #                APPDATA, but hard to move. See bug 348640 for more.
 
1494
    if base is None:
 
1495
        base = osutils.path_from_environ('XDG_CONFIG_HOME')
 
1496
        if base is None:
 
1497
            base = osutils.pathjoin(osutils._get_home_dir(), ".config")
 
1498
    breezy_dir = osutils.pathjoin(base, 'breezy')
 
1499
    if osutils.isdir(breezy_dir):
 
1500
        return breezy_dir
 
1501
    # If the breezy directory doesn't exist, but the bazaar one does, use that:
 
1502
    bazaar_dir = bazaar_config_dir()
 
1503
    if osutils.isdir(bazaar_dir):
 
1504
        trace.mutter(
 
1505
            "Using Bazaar configuration directory (%s)", bazaar_dir)
 
1506
        return bazaar_dir
 
1507
    return breezy_dir
 
1508
 
 
1509
 
 
1510
def config_filename():
 
1511
    """Return per-user configuration ini file filename."""
 
1512
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
 
1513
 
 
1514
 
 
1515
def locations_config_filename():
 
1516
    """Return per-user configuration ini file filename."""
 
1517
    return osutils.pathjoin(config_dir(), 'locations.conf')
 
1518
 
 
1519
 
 
1520
def authentication_config_filename():
 
1521
    """Return per-user authentication ini file filename."""
 
1522
    return osutils.pathjoin(config_dir(), 'authentication.conf')
 
1523
 
 
1524
 
 
1525
def user_ignore_config_filename():
 
1526
    """Return the user default ignore filename"""
 
1527
    return osutils.pathjoin(config_dir(), 'ignore')
 
1528
 
 
1529
 
 
1530
def crash_dir():
 
1531
    """Return the directory name to store crash files.
 
1532
 
 
1533
    This doesn't implicitly create it.
 
1534
 
 
1535
    On Windows it's in the config directory; elsewhere it's /var/crash
 
1536
    which may be monitored by apport.  It can be overridden by
 
1537
    $APPORT_CRASH_DIR.
 
1538
    """
 
1539
    if sys.platform == 'win32':
 
1540
        return osutils.pathjoin(config_dir(), 'Crash')
 
1541
    else:
 
1542
        # XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
 
1543
        # 2010-01-31
 
1544
        return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
 
1545
 
 
1546
 
 
1547
def xdg_cache_dir():
 
1548
    # See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
 
1549
    # Possibly this should be different on Windows?
 
1550
    e = os.environ.get('XDG_CACHE_HOME', None)
 
1551
    if e:
 
1552
        return e
 
1553
    else:
 
1554
        return os.path.expanduser('~/.cache')
 
1555
 
 
1556
 
 
1557
def _get_default_mail_domain(mailname_file='/etc/mailname'):
 
1558
    """If possible, return the assumed default email domain.
 
1559
 
 
1560
    :returns: string mail domain, or None.
 
1561
    """
 
1562
    if sys.platform == 'win32':
 
1563
        # No implementation yet; patches welcome
 
1564
        return None
 
1565
    try:
 
1566
        f = open(mailname_file)
 
1567
    except (IOError, OSError) as e:
 
1568
        return None
 
1569
    try:
 
1570
        domain = f.readline().strip()
 
1571
        return domain
 
1572
    finally:
 
1573
        f.close()
 
1574
 
 
1575
 
 
1576
def default_email():
 
1577
    v = os.environ.get('BRZ_EMAIL')
 
1578
    if v:
 
1579
        if not PY3:
 
1580
            v = v.decode(osutils.get_user_encoding())
 
1581
        return v
 
1582
    v = os.environ.get('EMAIL')
 
1583
    if v:
 
1584
        if not PY3:
 
1585
            v = v.decode(osutils.get_user_encoding())
 
1586
        return v
 
1587
    name, email = _auto_user_id()
 
1588
    if name and email:
 
1589
        return u'%s <%s>' % (name, email)
 
1590
    elif email:
 
1591
        return email
 
1592
    raise NoWhoami()
 
1593
 
 
1594
 
 
1595
def _auto_user_id():
 
1596
    """Calculate automatic user identification.
 
1597
 
 
1598
    :returns: (realname, email), either of which may be None if they can't be
 
1599
    determined.
 
1600
 
 
1601
    Only used when none is set in the environment or the id file.
 
1602
 
 
1603
    This only returns an email address if we can be fairly sure the 
 
1604
    address is reasonable, ie if /etc/mailname is set on unix.
 
1605
 
 
1606
    This doesn't use the FQDN as the default domain because that may be 
 
1607
    slow, and it doesn't use the hostname alone because that's not normally 
 
1608
    a reasonable address.
 
1609
    """
 
1610
    if sys.platform == 'win32':
 
1611
        # No implementation to reliably determine Windows default mail
 
1612
        # address; please add one.
 
1613
        return None, None
 
1614
 
 
1615
    default_mail_domain = _get_default_mail_domain()
 
1616
    if not default_mail_domain:
 
1617
        return None, None
 
1618
 
 
1619
    import pwd
 
1620
    uid = os.getuid()
 
1621
    try:
 
1622
        w = pwd.getpwuid(uid)
 
1623
    except KeyError:
 
1624
        trace.mutter('no passwd entry for uid %d?' % uid)
 
1625
        return None, None
 
1626
 
 
1627
    # we try utf-8 first, because on many variants (like Linux),
 
1628
    # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
1629
    # false positives.  (many users will have their user encoding set to
 
1630
    # latin-1, which cannot raise UnicodeError.)
 
1631
    try:
 
1632
        gecos = w.pw_gecos.decode('utf-8')
 
1633
        encoding = 'utf-8'
 
1634
    except UnicodeError:
 
1635
        try:
 
1636
            encoding = osutils.get_user_encoding()
 
1637
            gecos = w.pw_gecos.decode(encoding)
 
1638
        except UnicodeError as e:
 
1639
            trace.mutter("cannot decode passwd entry %s" % w)
 
1640
            return None, None
 
1641
    try:
 
1642
        username = w.pw_name.decode(encoding)
 
1643
    except UnicodeError as e:
 
1644
        trace.mutter("cannot decode passwd entry %s" % w)
 
1645
        return None, None
 
1646
 
 
1647
    comma = gecos.find(',')
 
1648
    if comma == -1:
 
1649
        realname = gecos
 
1650
    else:
 
1651
        realname = gecos[:comma]
 
1652
 
 
1653
    return realname, (username + '@' + default_mail_domain)
 
1654
 
 
1655
 
1398
1656
def parse_username(username):
1399
1657
    """Parse e-mail username and return a (name, address) tuple."""
1400
1658
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1401
1659
    if match is None:
1402
1660
        return (username, '')
1403
 
    return (match.group(1), match.group(2))
 
1661
    else:
 
1662
        return (match.group(1), match.group(2))
1404
1663
 
1405
1664
 
1406
1665
def extract_email_address(e):
1422
1681
class TreeConfig(IniBasedConfig):
1423
1682
    """Branch configuration data associated with its contents, not location"""
1424
1683
 
1425
 
    # XXX: Really needs a better name, as this is not part of the tree!
1426
 
    # -- mbp 20080507
 
1684
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
1427
1685
 
1428
1686
    def __init__(self, branch):
1429
1687
        self._config = branch._get_config()
1435
1693
        return self._config._get_configobj()
1436
1694
 
1437
1695
    def get_option(self, name, section=None, default=None):
1438
 
        with self.branch.lock_read():
 
1696
        self.branch.lock_read()
 
1697
        try:
1439
1698
            return self._config.get_option(name, section, default)
 
1699
        finally:
 
1700
            self.branch.unlock()
1440
1701
 
1441
1702
    def set_option(self, value, name, section=None):
1442
1703
        """Set a per-branch configuration option"""
1443
1704
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
1444
1705
        # higher levels providing the right lock -- vila 20101004
1445
 
        with self.branch.lock_write():
 
1706
        self.branch.lock_write()
 
1707
        try:
1446
1708
            self._config.set_option(value, name, section)
 
1709
        finally:
 
1710
            self.branch.unlock()
1447
1711
 
1448
1712
    def remove_option(self, option_name, section_name=None):
1449
1713
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
1450
1714
        # higher levels providing the right lock -- vila 20101004
1451
 
        with self.branch.lock_write():
 
1715
        self.branch.lock_write()
 
1716
        try:
1452
1717
            self._config.remove_option(option_name, section_name)
 
1718
        finally:
 
1719
            self.branch.unlock()
1453
1720
 
1454
1721
 
1455
1722
_authentication_config_permission_errors = set()
1463
1730
    """
1464
1731
 
1465
1732
    def __init__(self, _file=None):
1466
 
        self._config = None  # The ConfigObj
 
1733
        self._config = None # The ConfigObj
1467
1734
        if _file is None:
1468
 
            self._input = self._filename = bedding.authentication_config_path()
 
1735
            self._filename = authentication_config_filename()
 
1736
            self._input = self._filename = authentication_config_filename()
1469
1737
            self._check_permissions()
1470
1738
        else:
1471
1739
            # Tests can provide a string as _file
1498
1766
                trace.mutter('Unable to stat %r: %r', self._filename, e)
1499
1767
            return
1500
1768
        mode = stat.S_IMODE(st.st_mode)
1501
 
        if ((stat.S_IXOTH | stat.S_IWOTH | stat.S_IROTH | stat.S_IXGRP
1502
 
             | stat.S_IWGRP | stat.S_IRGRP) & mode):
 
1769
        if ((stat.S_IXOTH | stat.S_IWOTH | stat.S_IROTH | stat.S_IXGRP |
 
1770
             stat.S_IWGRP | stat.S_IRGRP ) & mode):
1503
1771
            # Only warn once
1504
 
            if (self._filename not in _authentication_config_permission_errors and
1505
 
                not GlobalConfig().suppress_warning(
 
1772
            if (not self._filename in _authentication_config_permission_errors
 
1773
                and not GlobalConfig().suppress_warning(
1506
1774
                    'insecure_permissions')):
1507
1775
                trace.warning("The file '%s' has insecure "
1508
 
                              "file permissions. Saved passwords may be accessible "
1509
 
                              "by other users.", self._filename)
 
1776
                        "file permissions. Saved passwords may be accessible "
 
1777
                        "by other users.", self._filename)
1510
1778
                _authentication_config_permission_errors.add(self._filename)
1511
1779
 
1512
1780
    def _save(self):
1513
1781
        """Save the config file, only tests should use it for now."""
1514
1782
        conf_dir = os.path.dirname(self._filename)
1515
 
        bedding.ensure_config_dir_exists(conf_dir)
1516
 
        fd = os.open(self._filename, os.O_RDWR | os.O_CREAT, 0o600)
 
1783
        ensure_config_dir_exists(conf_dir)
 
1784
        fd = os.open(self._filename, os.O_RDWR|os.O_CREAT, 0o600)
1517
1785
        try:
1518
1786
            f = os.fdopen(fd, 'wb')
1519
1787
            self._get_config().write(f)
1564
1832
        credentials = None
1565
1833
        for auth_def_name, auth_def in self._get_config().iteritems():
1566
1834
            if not isinstance(auth_def, configobj.Section):
1567
 
                raise ValueError("%s defined outside a section" %
1568
 
                                 auth_def_name)
 
1835
                raise ValueError("%s defined outside a section" % auth_def_name)
1569
1836
 
1570
1837
            a_scheme, a_host, a_user, a_path = map(
1571
1838
                auth_def.get, ['scheme', 'host', 'user', 'path'])
1588
1855
            if a_scheme is not None and scheme != a_scheme:
1589
1856
                continue
1590
1857
            if a_host is not None:
1591
 
                if not (host == a_host or
1592
 
                        (a_host.startswith('.') and host.endswith(a_host))):
 
1858
                if not (host == a_host
 
1859
                        or (a_host.startswith('.') and host.endswith(a_host))):
1593
1860
                    continue
1594
1861
            if a_port is not None and port != a_port:
1595
1862
                continue
1596
 
            if (a_path is not None and path is not None and
1597
 
                    not path.startswith(a_path)):
 
1863
            if (a_path is not None and path is not None
 
1864
                and not path.startswith(a_path)):
1598
1865
                continue
1599
 
            if (a_user is not None and user is not None and
1600
 
                    a_user != user):
 
1866
            if (a_user is not None and user is not None
 
1867
                and a_user != user):
1601
1868
                # Never contradict the caller about the user to be used
1602
1869
                continue
1603
1870
            if a_user is None:
1664
1931
        if realm is not None:
1665
1932
            values['realm'] = realm
1666
1933
        config = self._get_config()
 
1934
        for_deletion = []
1667
1935
        for section, existing_values in config.iteritems():
1668
1936
            for key in ('scheme', 'host', 'port', 'path', 'realm'):
1669
1937
                if existing_values.get(key) != values.get(key):
1687
1955
 
1688
1956
        :param path: the absolute path on the server (optional)
1689
1957
 
1690
 
        :param ask: Ask the user if there is no explicitly configured username
 
1958
        :param ask: Ask the user if there is no explicitly configured username 
1691
1959
                    (optional)
1692
1960
 
1693
1961
        :param default: The username returned if none is defined (optional).
1737
2005
                                           realm)
1738
2006
        if credentials is not None:
1739
2007
            password = credentials['password']
1740
 
            if password is not None and scheme == 'ssh':
 
2008
            if password is not None and scheme is 'ssh':
1741
2009
                trace.warning('password ignored in section [%s],'
1742
2010
                              ' use an ssh agent instead'
1743
2011
                              % credentials['name'])
1748
2016
        if password is None:
1749
2017
            if prompt is None:
1750
2018
                # Create a default prompt suitable for most cases
1751
 
                prompt = (u'%s' %
1752
 
                          scheme.upper() + u' %(user)s@%(host)s password')
 
2019
                prompt = u'%s' % scheme.upper() + u' %(user)s@%(host)s password'
1753
2020
            # Special handling for optional fields in the prompt
1754
2021
            if port is not None:
1755
2022
                prompt_host = '%s:%d' % (host, port)
1824
2091
        :param override_existing: Raise KeyErorr if False and something has
1825
2092
                already been registered for that key. If True, ignore if there
1826
2093
                is an existing key (always register the new value).
1827
 
        :param fallback: Whether this credential store should be
 
2094
        :param fallback: Whether this credential store should be 
1828
2095
                used as fallback.
1829
2096
        """
1830
2097
        return super(CredentialStoreRegistry,
1844
2111
        :param override_existing: If True, replace the existing object
1845
2112
                with the new one. If False, if there is already something
1846
2113
                registered with the same key, raise a KeyError
1847
 
        :param fallback: Whether this credential store should be
 
2114
        :param fallback: Whether this credential store should be 
1848
2115
                used as fallback.
1849
2116
        """
1850
2117
        return super(CredentialStoreRegistry, self).register_lazy(
1871
2138
        raise NotImplementedError(self.get_credentials)
1872
2139
 
1873
2140
 
 
2141
 
1874
2142
class PlainTextCredentialStore(CredentialStore):
1875
2143
    __doc__ = """Plain text credential store for the authentication.conf file"""
1876
2144
 
1891
2159
        """See CredentialStore.decode_password."""
1892
2160
        # GZ 2012-07-28: Will raise binascii.Error if password is not base64,
1893
2161
        #                should probably propogate as something more useful.
1894
 
        return base64.standard_b64decode(credentials['password'])
1895
 
 
 
2162
        return base64.decodestring(credentials['password'])
1896
2163
 
1897
2164
credential_store_registry.register('base64', Base64CredentialStore,
1898
2165
                                   help=Base64CredentialStore.__doc__)
2003
2270
            return f
2004
2271
        except errors.NoSuchFile:
2005
2272
            return BytesIO()
2006
 
        except errors.PermissionDenied:
2007
 
            trace.warning(
2008
 
                "Permission denied while trying to open "
2009
 
                "configuration file %s.",
2010
 
                urlutils.unescape_for_display(
2011
 
                    urlutils.join(self._transport.base, self._filename),
2012
 
                    "utf-8"))
 
2273
        except errors.PermissionDenied as e:
 
2274
            trace.warning("Permission denied while trying to open "
 
2275
                "configuration file %s.", urlutils.unescape_for_display(
 
2276
                urlutils.join(self._transport.base, self._filename), "utf-8"))
2013
2277
            return BytesIO()
2014
2278
 
2015
2279
    def _external_url(self):
2101
2365
                raise AssertionError(
2102
2366
                    'Only empty lists are supported as default values')
2103
2367
            self.default = u','
2104
 
        elif isinstance(default, (bytes, str, bool, int, float)):
 
2368
        elif isinstance(default, (binary_type, text_type, bool, int, float)):
2105
2369
            # Rely on python to convert strings, booleans and integers
2106
2370
            self.default = u'%s' % (default,)
2107
2371
        elif callable(default):
2147
2411
        for var in self.override_from_env:
2148
2412
            try:
2149
2413
                # If the env variable is defined, its value takes precedence
2150
 
                value = os.environ[var]
 
2414
                value = os.environ[var].decode(osutils.get_user_encoding())
2151
2415
                break
2152
2416
            except KeyError:
2153
2417
                continue
2159
2423
            try:
2160
2424
                # If the env variable is defined, its value is the default one
2161
2425
                value = os.environ[var]
 
2426
                if not PY3:
 
2427
                    value = value.decode(osutils.get_user_encoding())
2162
2428
                break
2163
2429
            except KeyError:
2164
2430
                continue
2166
2432
            # Otherwise, fallback to the value defined at registration
2167
2433
            if callable(self.default):
2168
2434
                value = self.default()
2169
 
                if not isinstance(value, str):
 
2435
                if not isinstance(value, text_type):
2170
2436
                    raise AssertionError(
2171
2437
                        "Callable default value for '%s' should be unicode"
2172
2438
                        % (self.name))
2198
2464
 
2199
2465
_unit_suffixes = dict(K=10**3, M=10**6, G=10**9)
2200
2466
 
2201
 
 
2202
2467
def int_SI_from_store(unicode_str):
2203
2468
    """Convert a human readable size in SI units, e.g 10MB into an integer.
2204
2469
 
2206
2471
    by a trailing b (i.e. Kb, MB). This is intended to be practical and not
2207
2472
    pedantic.
2208
2473
 
2209
 
    :return Integer, expanded to its base-10 value if a proper SI unit is
 
2474
    :return Integer, expanded to its base-10 value if a proper SI unit is 
2210
2475
        found, None otherwise.
2211
2476
    """
2212
 
    regexp = "^(\\d+)(([" + ''.join(_unit_suffixes) + "])b?)?$"
 
2477
    regexp = "^(\d+)(([" + ''.join(_unit_suffixes) + "])b?)?$"
2213
2478
    p = re.compile(regexp, re.IGNORECASE)
2214
2479
    m = p.match(unicode_str)
2215
2480
    val = None
2220
2485
            try:
2221
2486
                coeff = _unit_suffixes[unit.upper()]
2222
2487
            except KeyError:
2223
 
                raise ValueError(
2224
 
                    gettext('{0} is not an SI unit.').format(unit))
 
2488
                raise ValueError(gettext('{0} is not an SI unit.').format(unit))
2225
2489
            val *= coeff
2226
2490
    return val
2227
2491
 
2251
2515
            invalid=invalid, unquote=False)
2252
2516
 
2253
2517
    def from_unicode(self, unicode_str):
2254
 
        if not isinstance(unicode_str, str):
 
2518
        if not isinstance(unicode_str, string_types):
2255
2519
            raise TypeError
2256
2520
        # Now inject our string directly as unicode. All callers got their
2257
2521
        # value from configobj, so values that need to be quoted are already
2259
2523
        _list_converter_config.reset()
2260
2524
        _list_converter_config._parse([u"list=%s" % (unicode_str,)])
2261
2525
        maybe_list = _list_converter_config['list']
2262
 
        if isinstance(maybe_list, str):
 
2526
        if isinstance(maybe_list, string_types):
2263
2527
            if maybe_list:
2264
2528
                # A single value, most probably the user forgot (or didn't care
2265
2529
                # to add) the final ','
2284
2548
        can take quoting into account.
2285
2549
        """
2286
2550
        super(RegistryOption, self).__init__(
2287
 
            name, default=lambda: registry.default_key,
 
2551
            name, default=lambda: unicode(registry.default_key),
2288
2552
            default_from_env=default_from_env,
2289
2553
            from_unicode=self.from_unicode, help=help,
2290
2554
            invalid=invalid, unquote=False)
2291
2555
        self.registry = registry
2292
2556
 
2293
2557
    def from_unicode(self, unicode_str):
2294
 
        if not isinstance(unicode_str, str):
 
2558
        if not isinstance(unicode_str, string_types):
2295
2559
            raise TypeError
2296
2560
        try:
2297
2561
            return self.registry.get(unicode_str)
2299
2563
            raise ValueError(
2300
2564
                "Invalid value %s for %s."
2301
2565
                "See help for a list of possible values." % (unicode_str,
2302
 
                                                             self.name))
 
2566
                    self.name))
2303
2567
 
2304
2568
    @property
2305
2569
    def help(self):
2309
2573
        return "".join(ret)
2310
2574
 
2311
2575
 
2312
 
_option_ref_re = lazy_regex.lazy_compile('({[^\\d\\W](?:\\.\\w|-\\w|\\w)*})')
 
2576
_option_ref_re = lazy_regex.lazy_compile('({[^\d\W](?:\.\w|-\w|\w)*})')
2313
2577
"""Describes an expandable option reference.
2314
2578
 
2315
2579
We want to match the most embedded reference first.
2318
2582
for '{bar{baz}}' we will get '{baz}'
2319
2583
"""
2320
2584
 
2321
 
 
2322
2585
def iter_option_refs(string):
2323
2586
    # Split isolate refs so every other chunk is a ref
2324
2587
    is_ref = False
2325
 
    for chunk in _option_ref_re.split(string):
 
2588
    for chunk  in _option_ref_re.split(string):
2326
2589
        yield is_ref, chunk
2327
2590
        is_ref = not is_ref
2328
2591
 
2359
2622
 
2360
2623
        :param module_name: the python path to the module. Such as 'os.path'.
2361
2624
 
2362
 
        :param member_name: the member of the module to return.  If empty or
 
2625
        :param member_name: the member of the module to return.  If empty or 
2363
2626
                None, get() will return the module itself.
2364
2627
        """
2365
2628
        self._check_option_name(key)
2391
2654
'''))
2392
2655
option_registry.register(
2393
2656
    ListOption('acceptable_keys',
2394
 
               default=None,
2395
 
               help="""\
 
2657
           default=None,
 
2658
           help="""\
2396
2659
List of GPG key patterns which are acceptable for verification.
2397
2660
"""))
2398
2661
option_registry.register(
2428
2691
See also: bound.
2429
2692
"""))
2430
2693
option_registry.register(
2431
 
    Option('branch.fetch_tags', default=False, from_unicode=bool_from_store,
 
2694
    Option('branch.fetch_tags', default=False,  from_unicode=bool_from_store,
2432
2695
           help="""\
2433
2696
Whether revisions associated with tags should be fetched.
2434
2697
"""))
2435
2698
option_registry.register_lazy(
2436
 
    'transform.orphan_policy', 'breezy.transform', 'opt_transform_orphan')
 
2699
    'bzr.transform.orphan_policy', 'breezy.transform', 'opt_transform_orphan')
2437
2700
option_registry.register(
2438
2701
    Option('bzr.workingtree.worth_saving_limit', default=10,
2439
 
           from_unicode=int_from_store, invalid='warning',
 
2702
           from_unicode=int_from_store,  invalid='warning',
2440
2703
           help='''\
2441
2704
How many changes before saving the dirstate.
2442
2705
 
2456
2719
bug tracker was specified.
2457
2720
'''))
2458
2721
option_registry.register(
2459
 
    Option('calculate_revnos', default=True,
2460
 
           from_unicode=bool_from_store,
2461
 
           help='''\
2462
 
Calculate revision numbers if they are not known.
2463
 
 
2464
 
Always show revision numbers, even for branch formats that don't store them
2465
 
natively (such as Git). Calculating the revision number requires traversing
2466
 
the left hand ancestry of the branch and can be slow on very large branches.
2467
 
'''))
2468
 
option_registry.register(
2469
2722
    Option('check_signatures', default=CHECK_IF_POSSIBLE,
2470
2723
           from_unicode=signature_policy_from_unicode,
2471
2724
           help='''\
2506
2759
'''))
2507
2760
option_registry.register(
2508
2761
    ListOption('debug_flags', default=[],
2509
 
               help='Debug flags to activate.'))
 
2762
           help='Debug flags to activate.'))
2510
2763
option_registry.register(
2511
2764
    Option('default_format', default='2a',
2512
2765
           help='Format used when creating branches.'))
2513
2766
option_registry.register(
 
2767
    Option('dpush_strict', default=None,
 
2768
           from_unicode=bool_from_store,
 
2769
           help='''\
 
2770
The default value for ``dpush --strict``.
 
2771
 
 
2772
If present, defines the ``--strict`` option default value for checking
 
2773
uncommitted changes before pushing into a different VCS without any
 
2774
custom bzr metadata.
 
2775
'''))
 
2776
option_registry.register(
2514
2777
    Option('editor',
2515
2778
           help='The command called to launch an editor to enter a message.'))
2516
2779
option_registry.register(
2517
 
    Option('email', override_from_env=['BRZ_EMAIL', 'BZR_EMAIL'],
2518
 
           default=bedding.default_email, help='The users identity'))
 
2780
    Option('email', override_from_env=['BRZ_EMAIL'], default=default_email,
 
2781
           help='The users identity'))
2519
2782
option_registry.register(
2520
2783
    Option('gpg_signing_key',
2521
2784
           default=None,
2528
2791
    Option('language',
2529
2792
           help='Language to translate messages into.'))
2530
2793
option_registry.register(
2531
 
    Option('locks.steal_dead', default=True, from_unicode=bool_from_store,
 
2794
    Option('locks.steal_dead', default=False, from_unicode=bool_from_store,
2532
2795
           help='''\
2533
2796
Steal locks that appears to be dead.
2534
2797
 
2541
2804
'''))
2542
2805
option_registry.register(
2543
2806
    Option('log_format', default='long',
2544
 
           help='''\
 
2807
           help= '''\
2545
2808
Log format to use when displaying revisions.
2546
2809
 
2547
2810
Standard log formats are ``long``, ``short`` and ``line``. Additional formats
2548
2811
may be provided by plugins.
2549
2812
'''))
2550
2813
option_registry.register_lazy('mail_client', 'breezy.mail_client',
2551
 
                              'opt_mail_client')
 
2814
    'opt_mail_client')
2552
2815
option_registry.register(
2553
2816
    Option('output_encoding',
2554
 
           help='Unicode encoding for output'
 
2817
           help= 'Unicode encoding for output'
2555
2818
           ' (terminal encoding if not specified).'))
2556
2819
option_registry.register(
2557
2820
    Option('parent_location',
2610
2873
lost if the machine crashes.  See also dirstate.fdatasync.
2611
2874
'''))
2612
2875
option_registry.register_lazy('smtp_server',
2613
 
                              'breezy.smtp_connection', 'smtp_server')
 
2876
    'breezy.smtp_connection', 'smtp_server')
2614
2877
option_registry.register_lazy('smtp_password',
2615
 
                              'breezy.smtp_connection', 'smtp_password')
 
2878
    'breezy.smtp_connection', 'smtp_password')
2616
2879
option_registry.register_lazy('smtp_username',
2617
 
                              'breezy.smtp_connection', 'smtp_username')
 
2880
    'breezy.smtp_connection', 'smtp_username')
2618
2881
option_registry.register(
2619
2882
    Option('selftest.timeout',
2620
 
           default='600',
2621
 
           from_unicode=int_from_store,
2622
 
           help='Abort selftest if one test takes longer than this many seconds',
2623
 
           ))
 
2883
        default='600',
 
2884
        from_unicode=int_from_store,
 
2885
        help='Abort selftest if one test takes longer than this many seconds',
 
2886
        ))
2624
2887
 
2625
2888
option_registry.register(
2626
2889
    Option('send_strict', default=None,
2638
2901
           help="If we wait for a new request from a client for more than"
2639
2902
                " X seconds, consider the client idle, and hangup."))
2640
2903
option_registry.register(
2641
 
    Option('ssh',
2642
 
           default=None, override_from_env=['BRZ_SSH'],
2643
 
           help='SSH vendor to use.'))
2644
 
option_registry.register(
2645
2904
    Option('stacked_on_location',
2646
2905
           default=None,
2647
2906
           help="""The location where this branch is stacked on."""))
2659
2918
           help='''Where submissions from this branch are mailed to.'''))
2660
2919
option_registry.register(
2661
2920
    ListOption('suppress_warnings',
2662
 
               default=[],
2663
 
               help="List of warning classes to suppress."))
 
2921
           default=[],
 
2922
           help="List of warning classes to suppress."))
2664
2923
option_registry.register(
2665
2924
    Option('validate_signatures_in_log', default=False,
2666
2925
           from_unicode=bool_from_store, invalid='warning',
2667
2926
           help='''Whether to validate signatures in brz log.'''))
2668
2927
option_registry.register_lazy('ssl.ca_certs',
2669
 
                              'breezy.transport.http', 'opt_ssl_ca_certs')
 
2928
    'breezy.transport.http._urllib2_wrappers', 'opt_ssl_ca_certs')
2670
2929
 
2671
2930
option_registry.register_lazy('ssl.cert_reqs',
2672
 
                              'breezy.transport.http', 'opt_ssl_cert_reqs')
 
2931
    'breezy.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
2673
2932
 
2674
2933
 
2675
2934
class Section(object):
2758
3017
                # Someone changed the value since we get it from the persistent
2759
3018
                # storage.
2760
3019
                trace.warning(gettext(
2761
 
                    "Option {0} in section {1} of {2} was changed"
2762
 
                    " from {3} to {4}. The {5} value will be saved.".format(
2763
 
                        k, self.id, store.external_url(), expected,
2764
 
                        reloaded, actual)))
 
3020
                        "Option {0} in section {1} of {2} was changed"
 
3021
                        " from {3} to {4}. The {5} value will be saved.".format(
 
3022
                            k, self.id, store.external_url(), expected,
 
3023
                            reloaded, actual)))
2765
3024
        # No need to keep track of these changes
2766
3025
        self.reset_changes()
2767
3026
 
2902
3161
            try:
2903
3162
                name, value = over.split('=', 1)
2904
3163
            except ValueError:
2905
 
                raise errors.CommandError(
 
3164
                raise errors.BzrCommandError(
2906
3165
                    gettext("Invalid '%s', should be of the form 'name=value'")
2907
3166
                    % (over,))
2908
3167
            self.options[name] = value
2913
3172
        return 'cmdline'
2914
3173
 
2915
3174
    def get_sections(self):
2916
 
        yield self, self.readonly_section_class(None, self.options)
 
3175
        yield self,  self.readonly_section_class(None, self.options)
2917
3176
 
2918
3177
 
2919
3178
class IniFileStore(Store):
2930
3189
        self._config_obj = None
2931
3190
 
2932
3191
    def is_loaded(self):
2933
 
        return self._config_obj is not None
 
3192
        return self._config_obj != None
2934
3193
 
2935
3194
    def unload(self):
2936
3195
        self._config_obj = None
3050
3309
            self._config_obj.list_values = False
3051
3310
 
3052
3311
    def unquote(self, value):
3053
 
        if value and isinstance(value, str):
 
3312
        if value and isinstance(value, string_types):
3054
3313
            # _unquote doesn't handle None nor empty strings nor anything that
3055
3314
            # is not a string, really.
3056
3315
            value = self._config_obj._unquote(value)
3134
3393
        # ensure_config_dir_exists does. It should if the transport is local
3135
3394
        # -- vila 2011-04-06
3136
3395
        self.transport.create_prefix()
3137
 
        token = self._lock.lock_write(token)
3138
 
        return lock.LogicalLockResult(self.unlock, token)
 
3396
        return self._lock.lock_write(token)
3139
3397
 
3140
3398
    def unlock(self):
3141
3399
        self._lock.unlock()
3143
3401
    def break_lock(self):
3144
3402
        self._lock.break_lock()
3145
3403
 
 
3404
    @needs_write_lock
3146
3405
    def save(self):
3147
 
        with self.lock_write():
3148
 
            # We need to be able to override the undecorated implementation
3149
 
            self.save_without_locking()
 
3406
        # We need to be able to override the undecorated implementation
 
3407
        self.save_without_locking()
3150
3408
 
3151
3409
    def save_without_locking(self):
3152
3410
        super(LockableIniFileStore, self).save()
3153
3411
 
3154
3412
 
3155
 
# FIXME: global, breezy, shouldn't that be 'user' instead or even
 
3413
# FIXME: global, bazaar, shouldn't that be 'user' instead or even
3156
3414
# 'user_defaults' as opposed to 'user_overrides', 'system_defaults'
3157
3415
# (/etc/bzr/bazaar.conf) and 'system_overrides' ? -- vila 2011-04-05
3158
3416
 
3167
3425
    """
3168
3426
 
3169
3427
    def __init__(self, possible_transports=None):
3170
 
        path, kind = bedding._config_dir()
3171
3428
        t = transport.get_transport_from_path(
3172
 
            path, possible_transports=possible_transports)
3173
 
        super(GlobalStore, self).__init__(t, kind + '.conf')
3174
 
        self.id = 'breezy'
 
3429
            config_dir(), possible_transports=possible_transports)
 
3430
        super(GlobalStore, self).__init__(t, 'bazaar.conf')
 
3431
        self.id = 'bazaar'
3175
3432
 
3176
3433
 
3177
3434
class LocationStore(LockableIniFileStore):
3182
3439
 
3183
3440
    def __init__(self, possible_transports=None):
3184
3441
        t = transport.get_transport_from_path(
3185
 
            bedding.config_dir(), possible_transports=possible_transports)
 
3442
            config_dir(), possible_transports=possible_transports)
3186
3443
        super(LocationStore, self).__init__(t, 'locations.conf')
3187
3444
        self.id = 'locations'
3188
3445
 
3204
3461
 
3205
3462
    def __init__(self, bzrdir):
3206
3463
        super(ControlStore, self).__init__(bzrdir.transport,
3207
 
                                           'control.conf',
 
3464
                                          'control.conf',
3208
3465
                                           lock_dir_name='branch_lock')
3209
3466
        self.id = 'control'
3210
3467
 
3321
3578
                # the location is already a local path or URL, convert the
3322
3579
                # section id to the same format
3323
3580
                section_path = urlutils.local_path_from_url(section_path)
3324
 
            if (self.location.startswith(section_path) or
3325
 
                    fnmatch.fnmatch(self.location, section_path)):
 
3581
            if (self.location.startswith(section_path)
 
3582
                or fnmatch.fnmatch(self.location, section_path)):
3326
3583
                section_parts = section_path.rstrip('/').split('/')
3327
3584
                extra_path = '/'.join(location_parts[len(section_parts):])
3328
3585
                yield store, LocationSection(section, extra_path)
3401
3658
_shared_stores = {}
3402
3659
_shared_stores_at_exit_installed = False
3403
3660
 
3404
 
 
3405
3661
class Stack(object):
3406
3662
    """A stack of configurations where an option can be defined"""
3407
3663
 
3453
3709
        """
3454
3710
        # FIXME: No caching of options nor sections yet -- vila 20110503
3455
3711
        value = None
3456
 
        found_store = None  # Where the option value has been found
 
3712
        found_store = None # Where the option value has been found
3457
3713
        # If the option is registered, it may provide additional info about
3458
3714
        # value handling
3459
3715
        try:
3467
3723
            # None or ends up being None during expansion or conversion.
3468
3724
            if val is not None:
3469
3725
                if expand:
3470
 
                    if isinstance(val, str):
 
3726
                    if isinstance(val, string_types):
3471
3727
                        val = self._expand_options_in_string(val)
3472
3728
                    else:
3473
3729
                        trace.warning('Cannot expand "%s":'
3595
3851
        return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
3596
3852
 
3597
3853
    def _get_overrides(self):
3598
 
        if breezy._global_state is not None:
3599
 
            # TODO(jelmer): Urgh, this is circular so we can't call breezy.get_global_state()
3600
 
            return breezy._global_state.cmdline_overrides.get_sections()
 
3854
        # FIXME: Hack around library_state.initialize never called
 
3855
        if breezy.global_state is not None:
 
3856
            return breezy.global_state.cmdline_overrides.get_sections()
3601
3857
        return []
3602
3858
 
3603
3859
    def get_shared_store(self, store, state=None):
3614
3870
            otherwise.
3615
3871
        """
3616
3872
        if state is None:
3617
 
            # TODO(jelmer): Urgh, this is circular so we can't call breezy.get_global_state()
3618
 
            state = breezy._global_state
 
3873
            state = breezy.global_state
3619
3874
        if state is None:
3620
3875
            global _shared_stores_at_exit_installed
3621
3876
            stores = _shared_stores
3622
 
 
3623
3877
            def save_config_changes():
3624
3878
                for k, store in stores.items():
3625
3879
                    store.save_changes()
3784
4038
    def unlock(self):
3785
4039
        return self.branch.unlock()
3786
4040
 
 
4041
    @needs_write_lock
3787
4042
    def set(self, name, value):
3788
 
        with self.lock_write():
3789
 
            super(BranchStack, self).set(name, value)
3790
 
            # Unlocking the branch will trigger a store.save_changes() so the
3791
 
            # last unlock saves all the changes.
 
4043
        super(BranchStack, self).set(name, value)
 
4044
        # Unlocking the branch will trigger a store.save_changes() so the last
 
4045
        # unlock saves all the changes.
3792
4046
 
 
4047
    @needs_write_lock
3793
4048
    def remove(self, name):
3794
 
        with self.lock_write():
3795
 
            super(BranchStack, self).remove(name)
3796
 
            # Unlocking the branch will trigger a store.save_changes() so the
3797
 
            # last unlock saves all the changes.
 
4049
        super(BranchStack, self).remove(name)
 
4050
        # Unlocking the branch will trigger a store.save_changes() so the last
 
4051
        # unlock saves all the changes.
3798
4052
 
3799
4053
 
3800
4054
class RemoteControlStack(Stack):
3832
4086
    def unlock(self):
3833
4087
        return self.branch.unlock()
3834
4088
 
 
4089
    @needs_write_lock
3835
4090
    def set(self, name, value):
3836
 
        with self.lock_write():
3837
 
            super(BranchOnlyStack, self).set(name, value)
3838
 
            # Force a write to persistent storage
3839
 
            self.store.save_changes()
 
4091
        super(BranchOnlyStack, self).set(name, value)
 
4092
        # Force a write to persistent storage
 
4093
        self.store.save_changes()
3840
4094
 
 
4095
    @needs_write_lock
3841
4096
    def remove(self, name):
3842
 
        with self.lock_write():
3843
 
            super(BranchOnlyStack, self).remove(name)
3844
 
            # Force a write to persistent storage
3845
 
            self.store.save_changes()
 
4097
        super(BranchOnlyStack, self).remove(name)
 
4098
        # Force a write to persistent storage
 
4099
        self.store.save_changes()
3846
4100
 
3847
4101
 
3848
4102
class cmd_config(commands.Command):
3874
4128
        # http://pad.lv/788991 -- vila 20101115
3875
4129
        commands.Option('scope', help='Reduce the scope to the specified'
3876
4130
                        ' configuration file.',
3877
 
                        type=str),
 
4131
                        type=text_type),
3878
4132
        commands.Option('all',
3879
 
                        help='Display all the defined values for the matching options.',
3880
 
                        ),
 
4133
            help='Display all the defined values for the matching options.',
 
4134
            ),
3881
4135
        commands.Option('remove', help='Remove the option from'
3882
4136
                        ' the configuration file.'),
3883
4137
        ]
3930
4184
        # reduced to the plugin-specific store), related to
3931
4185
        # http://pad.lv/788991 -- vila 2011-11-15
3932
4186
        if scope is not None:
3933
 
            if scope == 'breezy':
 
4187
            if scope == 'bazaar':
3934
4188
                return GlobalStack()
3935
4189
            elif scope == 'locations':
3936
4190
                return LocationStack(directory)
4003
4257
 
4004
4258
    def _remove_config_option(self, name, directory, scope):
4005
4259
        if name is None:
4006
 
            raise errors.CommandError(
 
4260
            raise errors.BzrCommandError(
4007
4261
                '--remove expects an option to remove.')
4008
4262
        conf = self._get_stack(directory, scope, write_access=True)
4009
4263
        try: