/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: 2019-06-03 23:48:08 UTC
  • mfrom: (7316 work)
  • mto: This revision was merged to the branch mainline in revision 7328.
  • Revision ID: jelmer@jelmer.uk-20190603234808-15yk5c7054tj8e2b
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
91
91
 
92
92
from breezy import (
93
93
    atomicfile,
94
 
    cmdline,
95
94
    controldir,
96
95
    debug,
97
96
    directory_service,
109
108
""")
110
109
from . import (
111
110
    commands,
112
 
    bedding,
113
111
    errors,
114
112
    hooks,
115
113
    lazy_regex,
234
232
        errors.BzrError.__init__(self, option_name=option_name)
235
233
 
236
234
 
 
235
class NoWhoami(errors.BzrError):
 
236
 
 
237
    _fmt = ('Unable to determine your name.\n'
 
238
            "Please, set your name with the 'whoami' command.\n"
 
239
            'E.g. brz whoami "Your Name <name@example.com>"')
 
240
 
 
241
 
237
242
def signature_policy_from_unicode(signature_string):
238
243
    """Convert a string to a signing policy."""
239
244
    if signature_string.lower() == 'check-available':
260
265
 
261
266
def _has_decode_bug():
262
267
    """True if configobj will fail to decode to unicode on Python 2."""
263
 
    if PY3:
 
268
    if sys.version_info > (3,):
264
269
        return False
265
270
    conf = configobj.ConfigObj()
266
271
    decode = getattr(conf, "_decode", None)
329
334
        cmd = self._get_change_editor()
330
335
        if cmd is None:
331
336
            return None
332
 
        cmd = cmd.replace('@old_path', '{old_path}')
333
 
        cmd = cmd.replace('@new_path', '{new_path}')
334
 
        cmd = cmdline.split(cmd)
335
 
        if '{old_path}' not in cmd:
336
 
            cmd.extend(['{old_path}', '{new_path}'])
337
337
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
338
338
                                             sys.stdout)
339
339
 
556
556
 
557
557
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
558
558
 
559
 
        $BRZ_EMAIL or $BZR_EMAIL can be set to override this, then
 
559
        $BRZ_EMAIL can be set to override this, then
560
560
        the concrete policy type is checked, and finally
561
561
        $EMAIL is examined.
562
562
        If no username can be found, NoWhoami exception is raised.
563
563
        """
564
 
        v = os.environ.get('BRZ_EMAIL') or os.environ.get('BZR_EMAIL')
 
564
        v = os.environ.get('BRZ_EMAIL')
565
565
        if v:
566
566
            if not PY3:
567
567
                v = v.decode(osutils.get_user_encoding())
569
569
        v = self._get_user_id()
570
570
        if v:
571
571
            return v
572
 
        return bedding.default_email()
 
572
        return default_email()
 
573
 
 
574
    def ensure_username(self):
 
575
        """Raise NoWhoami if username is not set.
 
576
 
 
577
        This method relies on the username() function raising the error.
 
578
        """
 
579
        self.username()
573
580
 
574
581
    def get_alias(self, value):
575
582
        return self._get_alias(value)
837
844
        return POLICY_NONE
838
845
 
839
846
    def _get_change_editor(self):
840
 
        return self.get_user_option('change_editor', expand=False)
 
847
        return self.get_user_option('change_editor')
841
848
 
842
849
    def _get_signature_checking(self):
843
850
        """See Config._get_signature_checking."""
932
939
        if self.file_name is None:
933
940
            raise AssertionError('We cannot save, self.file_name is None')
934
941
        conf_dir = os.path.dirname(self.file_name)
935
 
        bedding.ensure_config_dir_exists(conf_dir)
 
942
        ensure_config_dir_exists(conf_dir)
936
943
        with atomicfile.AtomicFile(self.file_name) as atomic_file:
937
944
            self._get_parser().write(atomic_file)
938
945
        osutils.copy_ownership_from_path(self.file_name)
992
999
 
993
1000
        If the directory doesn't exist it is created.
994
1001
        """
995
 
        bedding.ensure_config_dir_exists(self.dir)
 
1002
        ensure_config_dir_exists(self.dir)
996
1003
        token = self._lock.lock_write(token)
997
1004
        return lock.LogicalLockResult(self.unlock, token)
998
1005
 
1019
1026
    """The configuration that should be used for a specific location."""
1020
1027
 
1021
1028
    def __init__(self):
1022
 
        super(GlobalConfig, self).__init__(file_name=bedding.config_path())
 
1029
        super(GlobalConfig, self).__init__(file_name=config_filename())
1023
1030
 
1024
1031
    def config_id(self):
1025
1032
        return 'breezy'
1151
1158
 
1152
1159
    def __init__(self, location):
1153
1160
        super(LocationConfig, self).__init__(
1154
 
            file_name=bedding.locations_config_path())
 
1161
            file_name=locations_config_filename())
1155
1162
        # local file locations are looked up by local path, rather than
1156
1163
        # by file url. This is because the config file is a user
1157
1164
        # file, and we would rather not expose the user to file urls.
1423
1430
        return self._get_best_value('_acceptable_keys')
1424
1431
 
1425
1432
 
 
1433
def ensure_config_dir_exists(path=None):
 
1434
    """Make sure a configuration directory exists.
 
1435
    This makes sure that the directory exists.
 
1436
    On windows, since configuration directories are 2 levels deep,
 
1437
    it makes sure both the directory and the parent directory exists.
 
1438
    """
 
1439
    if path is None:
 
1440
        path = config_dir()
 
1441
    if not os.path.isdir(path):
 
1442
        if sys.platform == 'win32':
 
1443
            parent_dir = os.path.dirname(path)
 
1444
            if not os.path.isdir(parent_dir):
 
1445
                trace.mutter(
 
1446
                    'creating config parent directory: %r', parent_dir)
 
1447
                os.mkdir(parent_dir)
 
1448
        trace.mutter('creating config directory: %r', path)
 
1449
        os.mkdir(path)
 
1450
        osutils.copy_ownership_from_path(path)
 
1451
 
 
1452
 
 
1453
def bazaar_config_dir():
 
1454
    """Return per-user configuration directory as unicode string
 
1455
 
 
1456
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
 
1457
    and Linux.  On Mac OS X and Linux, if there is a $XDG_CONFIG_HOME/bazaar
 
1458
    directory, that will be used instead
 
1459
 
 
1460
    TODO: Global option --config-dir to override this.
 
1461
    """
 
1462
    base = osutils.path_from_environ('BZR_HOME')
 
1463
    if sys.platform == 'win32':
 
1464
        if base is None:
 
1465
            base = win32utils.get_appdata_location()
 
1466
        if base is None:
 
1467
            base = win32utils.get_home_location()
 
1468
        return osutils.pathjoin(base, 'bazaar', '2.0')
 
1469
    if base is None:
 
1470
        xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
 
1471
        if xdg_dir is None:
 
1472
            xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
 
1473
        xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
 
1474
        if osutils.isdir(xdg_dir):
 
1475
            trace.mutter(
 
1476
                "Using configuration in XDG directory %s." % xdg_dir)
 
1477
            return xdg_dir
 
1478
        base = osutils._get_home_dir()
 
1479
    return osutils.pathjoin(base, ".bazaar")
 
1480
 
 
1481
 
 
1482
def _config_dir():
 
1483
    """Return per-user configuration directory as unicode string
 
1484
 
 
1485
    By default this is %APPDATA%/breezy on Windows, $XDG_CONFIG_HOME/breezy on
 
1486
    Mac OS X and Linux. If the breezy config directory doesn't exist but
 
1487
    the bazaar one (see bazaar_config_dir()) does, use that instead.
 
1488
    """
 
1489
    # TODO: Global option --config-dir to override this.
 
1490
    base = osutils.path_from_environ('BRZ_HOME')
 
1491
    if sys.platform == 'win32':
 
1492
        if base is None:
 
1493
            base = win32utils.get_appdata_location()
 
1494
        if base is None:
 
1495
            base = win32utils.get_home_location()
 
1496
    if base is None:
 
1497
        base = osutils.path_from_environ('XDG_CONFIG_HOME')
 
1498
        if base is None:
 
1499
            base = osutils.pathjoin(osutils._get_home_dir(), ".config")
 
1500
    breezy_dir = osutils.pathjoin(base, 'breezy')
 
1501
    if osutils.isdir(breezy_dir):
 
1502
        return (breezy_dir, 'breezy')
 
1503
    # If the breezy directory doesn't exist, but the bazaar one does, use that:
 
1504
    bazaar_dir = bazaar_config_dir()
 
1505
    if osutils.isdir(bazaar_dir):
 
1506
        trace.mutter(
 
1507
            "Using Bazaar configuration directory (%s)", bazaar_dir)
 
1508
        return (bazaar_dir, 'bazaar')
 
1509
    return (breezy_dir, 'breezy')
 
1510
 
 
1511
 
 
1512
def config_dir():
 
1513
    """Return per-user configuration directory as unicode string
 
1514
 
 
1515
    By default this is %APPDATA%/breezy on Windows, $XDG_CONFIG_HOME/breezy on
 
1516
    Mac OS X and Linux. If the breezy config directory doesn't exist but
 
1517
    the bazaar one (see bazaar_config_dir()) does, use that instead.
 
1518
    """
 
1519
    return _config_dir()[0]
 
1520
 
 
1521
 
 
1522
def config_filename():
 
1523
    """Return per-user configuration ini file filename."""
 
1524
    path, kind = _config_dir()
 
1525
    if kind == 'bazaar':
 
1526
        return osutils.pathjoin(path, 'bazaar.conf')
 
1527
    else:
 
1528
        return osutils.pathjoin(path, 'breezy.conf')
 
1529
 
 
1530
 
 
1531
def locations_config_filename():
 
1532
    """Return per-user configuration ini file filename."""
 
1533
    return osutils.pathjoin(config_dir(), 'locations.conf')
 
1534
 
 
1535
 
 
1536
def authentication_config_filename():
 
1537
    """Return per-user authentication ini file filename."""
 
1538
    return osutils.pathjoin(config_dir(), 'authentication.conf')
 
1539
 
 
1540
 
 
1541
def user_ignore_config_filename():
 
1542
    """Return the user default ignore filename"""
 
1543
    return osutils.pathjoin(config_dir(), 'ignore')
 
1544
 
 
1545
 
 
1546
def crash_dir():
 
1547
    """Return the directory name to store crash files.
 
1548
 
 
1549
    This doesn't implicitly create it.
 
1550
 
 
1551
    On Windows it's in the config directory; elsewhere it's /var/crash
 
1552
    which may be monitored by apport.  It can be overridden by
 
1553
    $APPORT_CRASH_DIR.
 
1554
    """
 
1555
    if sys.platform == 'win32':
 
1556
        return osutils.pathjoin(config_dir(), 'Crash')
 
1557
    else:
 
1558
        # XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
 
1559
        # 2010-01-31
 
1560
        return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
 
1561
 
 
1562
 
 
1563
def xdg_cache_dir():
 
1564
    # See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
 
1565
    # Possibly this should be different on Windows?
 
1566
    e = os.environ.get('XDG_CACHE_HOME', None)
 
1567
    if e:
 
1568
        return e
 
1569
    else:
 
1570
        return os.path.expanduser('~/.cache')
 
1571
 
 
1572
 
 
1573
def _get_default_mail_domain(mailname_file='/etc/mailname'):
 
1574
    """If possible, return the assumed default email domain.
 
1575
 
 
1576
    :returns: string mail domain, or None.
 
1577
    """
 
1578
    if sys.platform == 'win32':
 
1579
        # No implementation yet; patches welcome
 
1580
        return None
 
1581
    try:
 
1582
        f = open(mailname_file)
 
1583
    except (IOError, OSError):
 
1584
        return None
 
1585
    try:
 
1586
        domain = f.readline().strip()
 
1587
        return domain
 
1588
    finally:
 
1589
        f.close()
 
1590
 
 
1591
 
 
1592
def default_email():
 
1593
    v = os.environ.get('BRZ_EMAIL')
 
1594
    if v:
 
1595
        if not PY3:
 
1596
            v = v.decode(osutils.get_user_encoding())
 
1597
        return v
 
1598
    v = os.environ.get('EMAIL')
 
1599
    if v:
 
1600
        if not PY3:
 
1601
            v = v.decode(osutils.get_user_encoding())
 
1602
        return v
 
1603
    name, email = _auto_user_id()
 
1604
    if name and email:
 
1605
        return u'%s <%s>' % (name, email)
 
1606
    elif email:
 
1607
        return email
 
1608
    raise NoWhoami()
 
1609
 
 
1610
 
 
1611
def _auto_user_id():
 
1612
    """Calculate automatic user identification.
 
1613
 
 
1614
    :returns: (realname, email), either of which may be None if they can't be
 
1615
    determined.
 
1616
 
 
1617
    Only used when none is set in the environment or the id file.
 
1618
 
 
1619
    This only returns an email address if we can be fairly sure the
 
1620
    address is reasonable, ie if /etc/mailname is set on unix.
 
1621
 
 
1622
    This doesn't use the FQDN as the default domain because that may be
 
1623
    slow, and it doesn't use the hostname alone because that's not normally
 
1624
    a reasonable address.
 
1625
    """
 
1626
    if sys.platform == 'win32':
 
1627
        # No implementation to reliably determine Windows default mail
 
1628
        # address; please add one.
 
1629
        return None, None
 
1630
 
 
1631
    default_mail_domain = _get_default_mail_domain()
 
1632
    if not default_mail_domain:
 
1633
        return None, None
 
1634
 
 
1635
    import pwd
 
1636
    uid = os.getuid()
 
1637
    try:
 
1638
        w = pwd.getpwuid(uid)
 
1639
    except KeyError:
 
1640
        trace.mutter('no passwd entry for uid %d?' % uid)
 
1641
        return None, None
 
1642
 
 
1643
    # we try utf-8 first, because on many variants (like Linux),
 
1644
    # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
1645
    # false positives.  (many users will have their user encoding set to
 
1646
    # latin-1, which cannot raise UnicodeError.)
 
1647
    gecos = w.pw_gecos
 
1648
    if isinstance(gecos, bytes):
 
1649
        try:
 
1650
            gecos = gecos.decode('utf-8')
 
1651
            encoding = 'utf-8'
 
1652
        except UnicodeError:
 
1653
            try:
 
1654
                encoding = osutils.get_user_encoding()
 
1655
                gecos = gecos.decode(encoding)
 
1656
            except UnicodeError:
 
1657
                trace.mutter("cannot decode passwd entry %s" % w)
 
1658
                return None, None
 
1659
 
 
1660
    username = w.pw_name
 
1661
    if isinstance(username, bytes):
 
1662
        try:
 
1663
            username = username.decode(encoding)
 
1664
        except UnicodeError:
 
1665
            trace.mutter("cannot decode passwd entry %s" % w)
 
1666
            return None, None
 
1667
 
 
1668
    comma = gecos.find(',')
 
1669
    if comma == -1:
 
1670
        realname = gecos
 
1671
    else:
 
1672
        realname = gecos[:comma]
 
1673
 
 
1674
    return realname, (username + '@' + default_mail_domain)
 
1675
 
 
1676
 
1426
1677
def parse_username(username):
1427
1678
    """Parse e-mail username and return a (name, address) tuple."""
1428
1679
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1429
1680
    if match is None:
1430
1681
        return (username, '')
1431
 
    return (match.group(1), match.group(2))
 
1682
    else:
 
1683
        return (match.group(1), match.group(2))
1432
1684
 
1433
1685
 
1434
1686
def extract_email_address(e):
1493
1745
    def __init__(self, _file=None):
1494
1746
        self._config = None  # The ConfigObj
1495
1747
        if _file is None:
1496
 
            self._input = self._filename = bedding.authentication_config_path()
 
1748
            self._filename = authentication_config_filename()
 
1749
            self._input = self._filename = authentication_config_filename()
1497
1750
            self._check_permissions()
1498
1751
        else:
1499
1752
            # Tests can provide a string as _file
1540
1793
    def _save(self):
1541
1794
        """Save the config file, only tests should use it for now."""
1542
1795
        conf_dir = os.path.dirname(self._filename)
1543
 
        bedding.ensure_config_dir_exists(conf_dir)
 
1796
        ensure_config_dir_exists(conf_dir)
1544
1797
        fd = os.open(self._filename, os.O_RDWR | os.O_CREAT, 0o600)
1545
1798
        try:
1546
1799
            f = os.fdopen(fd, 'wb')
2488
2741
bug tracker was specified.
2489
2742
'''))
2490
2743
option_registry.register(
2491
 
    Option('calculate_revnos', default=True,
2492
 
           from_unicode=bool_from_store,
2493
 
           help='''\
2494
 
Calculate revision numbers if they are not known.
2495
 
 
2496
 
Always show revision numbers, even for branch formats that don't store them
2497
 
natively (such as Git). Calculating the revision number requires traversing
2498
 
the left hand ancestry of the branch and can be slow on very large branches.
2499
 
'''))
2500
 
option_registry.register(
2501
2744
    Option('check_signatures', default=CHECK_IF_POSSIBLE,
2502
2745
           from_unicode=signature_policy_from_unicode,
2503
2746
           help='''\
2546
2789
    Option('editor',
2547
2790
           help='The command called to launch an editor to enter a message.'))
2548
2791
option_registry.register(
2549
 
    Option('email', override_from_env=['BRZ_EMAIL', 'BZR_EMAIL'],
2550
 
           default=bedding.default_email, help='The users identity'))
 
2792
    Option('email', override_from_env=['BRZ_EMAIL'], default=default_email,
 
2793
           help='The users identity'))
2551
2794
option_registry.register(
2552
2795
    Option('gpg_signing_key',
2553
2796
           default=None,
2560
2803
    Option('language',
2561
2804
           help='Language to translate messages into.'))
2562
2805
option_registry.register(
2563
 
    Option('locks.steal_dead', default=True, from_unicode=bool_from_store,
 
2806
    Option('locks.steal_dead', default=False, from_unicode=bool_from_store,
2564
2807
           help='''\
2565
2808
Steal locks that appears to be dead.
2566
2809
 
2670
2913
           help="If we wait for a new request from a client for more than"
2671
2914
                " X seconds, consider the client idle, and hangup."))
2672
2915
option_registry.register(
2673
 
    Option('ssh',
2674
 
           default=None, override_from_env=['BRZ_SSH'],
2675
 
           help='SSH vendor to use.'))
2676
 
option_registry.register(
2677
2916
    Option('stacked_on_location',
2678
2917
           default=None,
2679
2918
           help="""The location where this branch is stacked on."""))
3199
3438
    """
3200
3439
 
3201
3440
    def __init__(self, possible_transports=None):
3202
 
        path, kind = bedding._config_dir()
 
3441
        (path, kind) = _config_dir()
3203
3442
        t = transport.get_transport_from_path(
3204
3443
            path, possible_transports=possible_transports)
3205
 
        super(GlobalStore, self).__init__(t, kind + '.conf')
 
3444
        filename = {'bazaar': 'bazaar.conf', 'breezy': 'breezy.conf'}[kind]
 
3445
        super(GlobalStore, self).__init__(t, filename)
3206
3446
        self.id = 'breezy'
3207
3447
 
3208
3448
 
3214
3454
 
3215
3455
    def __init__(self, possible_transports=None):
3216
3456
        t = transport.get_transport_from_path(
3217
 
            bedding.config_dir(), possible_transports=possible_transports)
 
3457
            config_dir(), possible_transports=possible_transports)
3218
3458
        super(LocationStore, self).__init__(t, 'locations.conf')
3219
3459
        self.id = 'locations'
3220
3460