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
19
"""Configuration that affects the behaviour of Breezy.
21
Currently this configuration resides in ~/.config/breezy/breezy.conf
22
and ~/.config/breezy/locations.conf, which is written to by brz.
24
If the first location doesn't exist, then brz falls back to reading
25
Bazaar configuration files in ~/.bazaar or ~/.config/bazaar.
27
In breezy.conf the following options may be set:
19
"""Configuration that affects the behaviour of Bazaar.
21
Currently this configuration resides in ~/.bazaar/bazaar.conf
22
and ~/.bazaar/locations.conf, which is written to by bzr.
24
In bazaar.conf the following options may be set:
29
26
editor=name-of-program
30
27
email=Your Name <your@email.address>
31
28
check_signatures=require|ignore|check-available(default)
32
29
create_signatures=always|never|when-required(default)
30
gpg_signing_command=name-of-program
33
31
log_format=name-of-format
34
32
validate_signatures_in_log=true|false(default)
35
33
acceptable_keys=pattern1,pattern2
153
class OptionExpansionLoop(errors.BzrError):
155
_fmt = 'Loop involving %(refs)r while expanding "%(string)s".'
157
def __init__(self, string, refs):
159
self.refs = '->'.join(refs)
162
class ExpandingUnknownOption(errors.BzrError):
164
_fmt = 'Option "%(name)s" is not defined while expanding "%(string)s".'
166
def __init__(self, name, string):
171
class IllegalOptionName(errors.BzrError):
173
_fmt = 'Option "%(name)s" is not allowed.'
175
def __init__(self, name):
179
class ConfigContentError(errors.BzrError):
181
_fmt = "Config file %(filename)s is not UTF-8 encoded\n"
183
def __init__(self, filename):
184
self.filename = filename
187
class ParseConfigError(errors.BzrError):
189
_fmt = "Error(s) parsing config file %(filename)s:\n%(errors)s"
191
def __init__(self, errors, filename):
192
self.filename = filename
193
self.errors = '\n'.join(e.msg for e in errors)
196
class ConfigOptionValueError(errors.BzrError):
198
_fmt = ('Bad value "%(value)s" for option "%(name)s".\n'
199
'See ``brz help %(name)s``')
201
def __init__(self, name, value):
202
errors.BzrError.__init__(self, name=name, value=value)
205
class NoEmailInUsername(errors.BzrError):
207
_fmt = "%(username)r does not seem to contain a reasonable email address"
209
def __init__(self, username):
210
self.username = username
213
class NoSuchConfig(errors.BzrError):
215
_fmt = ('The "%(config_id)s" configuration does not exist.')
217
def __init__(self, config_id):
218
errors.BzrError.__init__(self, config_id=config_id)
221
class NoSuchConfigOption(errors.BzrError):
223
_fmt = ('The "%(option_name)s" configuration option does not exist.')
225
def __init__(self, option_name):
226
errors.BzrError.__init__(self, option_name=option_name)
229
155
def signature_policy_from_unicode(signature_string):
230
156
"""Convert a string to a signing policy."""
231
157
if signature_string.lower() == 'check-available':
495
400
l = self.get_user_option(option_name, expand=expand)
496
if isinstance(l, str):
401
if isinstance(l, (str, unicode)):
497
402
# A single value, most probably the user forgot (or didn't care to
498
403
# add) the final ','
407
@deprecated_method(deprecated_in((2, 5, 0)))
408
def get_user_option_as_int_from_SI(self, option_name, default=None):
409
"""Get a generic option from a human readable size in SI units, e.g 10MB
411
Accepted suffixes are K,M,G. It is case-insensitive and may be followed
412
by a trailing b (i.e. Kb, MB). This is intended to be practical and not
415
:return Integer, expanded to its base-10 value if a proper SI unit is
416
found. If the option doesn't exist, or isn't a value in
417
SI units, return default (which defaults to None)
419
val = self.get_user_option(option_name)
420
if isinstance(val, list):
425
p = re.compile("^(\d+)([kmg])*b*$", re.IGNORECASE)
429
val = int(m.group(1))
430
if m.group(2) is not None:
431
if m.group(2).lower() == 'k':
433
elif m.group(2).lower() == 'm':
435
elif m.group(2).lower() == 'g':
438
ui.ui_factory.show_warning(gettext('Invalid config value for "{0}" '
439
' value {1!r} is not an SI unit.').format(
446
@deprecated_method(deprecated_in((2, 5, 0)))
447
def gpg_signing_command(self):
448
"""What program should be used to sign signatures?"""
449
result = self._gpg_signing_command()
454
def _gpg_signing_command(self):
455
"""See gpg_signing_command()."""
458
@deprecated_method(deprecated_in((2, 5, 0)))
459
def log_format(self):
460
"""What log format should be used"""
461
result = self._log_format()
502
466
def _log_format(self):
503
467
"""See log_format()."""
530
513
Something similar to 'Martin Pool <mbp@sourcefrog.net>'
532
$BRZ_EMAIL or $BZR_EMAIL can be set to override this, then
515
$BZR_EMAIL can be set to override this, then
533
516
the concrete policy type is checked, and finally
534
517
$EMAIL is examined.
535
If no username can be found, NoWhoami exception is raised.
518
If no username can be found, errors.NoWhoami exception is raised.
537
v = os.environ.get('BRZ_EMAIL') or os.environ.get('BZR_EMAIL')
520
v = os.environ.get('BZR_EMAIL')
522
return v.decode(osutils.get_user_encoding())
540
523
v = self._get_user_id()
543
return bedding.default_email()
526
return default_email()
528
def ensure_username(self):
529
"""Raise errors.NoWhoami if username is not set.
531
This method relies on the username() function raising the error.
535
@deprecated_method(deprecated_in((2, 5, 0)))
536
def signature_checking(self):
537
"""What is the current policy for signature checking?."""
538
policy = self._get_signature_checking()
539
if policy is not None:
541
return CHECK_IF_POSSIBLE
543
@deprecated_method(deprecated_in((2, 5, 0)))
544
def signing_policy(self):
545
"""What is the current policy for signature checking?."""
546
policy = self._get_signing_policy()
547
if policy is not None:
549
return SIGN_WHEN_REQUIRED
551
@deprecated_method(deprecated_in((2, 5, 0)))
552
def signature_needed(self):
553
"""Is a signature needed when committing ?."""
554
policy = self._get_signing_policy()
556
policy = self._get_signature_checking()
557
if policy is not None:
558
#this warning should go away once check_signatures is
559
#implemented (if not before)
560
trace.warning("Please use create_signatures,"
561
" not check_signatures to set signing policy.")
562
elif policy == SIGN_ALWAYS:
566
@deprecated_method(deprecated_in((2, 5, 0)))
567
def gpg_signing_key(self):
568
"""GPG user-id to sign commits"""
569
key = self.get_user_option('gpg_signing_key')
570
if key == "default" or key == None:
571
return self.user_email()
545
575
def get_alias(self, value):
546
576
return self._get_alias(value)
666
693
'Invoked when a config option is removed.'
667
694
' The signature is (config, name).',
671
696
OldConfigHooks = _OldConfigHooks()
674
699
class IniBasedConfig(Config):
675
700
"""A configuration policy that draws from ini files."""
677
def __init__(self, file_name=None):
702
def __init__(self, get_filename=symbol_versioning.DEPRECATED_PARAMETER,
678
704
"""Base class for configuration files using an ini-like syntax.
680
706
:param file_name: The configuration file path.
682
708
super(IniBasedConfig, self).__init__()
683
709
self.file_name = file_name
684
self.file_name = file_name
710
if symbol_versioning.deprecated_passed(get_filename):
711
symbol_versioning.warn(
712
'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
713
' Use file_name instead.',
716
if get_filename is not None:
717
self.file_name = get_filename()
719
self.file_name = file_name
685
720
self._content = None
686
721
self._parser = None
1201
1266
if policy_key in self._get_parser()[section]:
1202
1267
del self._get_parser()[section][policy_key]
1204
1270
def set_user_option(self, option, value, store=STORE_LOCATION):
1205
1271
"""Save option and its value in the configuration."""
1206
1272
if store not in [STORE_LOCATION,
1207
1273
STORE_LOCATION_NORECURSE,
1208
1274
STORE_LOCATION_APPENDPATH]:
1209
1275
raise ValueError('bad storage policy %r for %r' %
1211
with self.lock_write():
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)
1278
location = self.location
1279
if location.endswith('/'):
1280
location = location[:-1]
1281
parser = self._get_parser()
1282
if not location in parser and not location + '/' in parser:
1283
parser[location] = {}
1284
elif location + '/' in parser:
1285
location = location + '/'
1286
parser[location][option]=value
1287
# the allowed values of store match the config policies
1288
self._set_option_policy(location, option, store)
1289
self._write_config_file()
1290
for hook in OldConfigHooks['set']:
1291
hook(self, option, value)
1229
1294
class BranchConfig(Config):
1395
1465
return self._get_best_value('_acceptable_keys')
1468
def ensure_config_dir_exists(path=None):
1469
"""Make sure a configuration directory exists.
1470
This makes sure that the directory exists.
1471
On windows, since configuration directories are 2 levels deep,
1472
it makes sure both the directory and the parent directory exists.
1476
if not os.path.isdir(path):
1477
if sys.platform == 'win32':
1478
parent_dir = os.path.dirname(path)
1479
if not os.path.isdir(parent_dir):
1480
trace.mutter('creating config parent directory: %r', parent_dir)
1481
os.mkdir(parent_dir)
1482
trace.mutter('creating config directory: %r', path)
1484
osutils.copy_ownership_from_path(path)
1488
"""Return per-user configuration directory as unicode string
1490
By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
1491
and Linux. On Mac OS X and Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
1492
that will be used instead.
1494
TODO: Global option --config-dir to override this.
1496
base = osutils.path_from_environ('BZR_HOME')
1497
if sys.platform == 'win32':
1499
base = win32utils.get_appdata_location()
1501
base = win32utils.get_home_location()
1502
# GZ 2012-02-01: Really the two level subdirs only make sense inside
1503
# APPDATA, but hard to move. See bug 348640 for more.
1504
return osutils.pathjoin(base, 'bazaar', '2.0')
1506
xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
1508
xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
1509
xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
1510
if osutils.isdir(xdg_dir):
1512
"Using configuration in XDG directory %s." % xdg_dir)
1514
base = osutils._get_home_dir()
1515
return osutils.pathjoin(base, ".bazaar")
1518
def config_filename():
1519
"""Return per-user configuration ini file filename."""
1520
return osutils.pathjoin(config_dir(), 'bazaar.conf')
1523
def locations_config_filename():
1524
"""Return per-user configuration ini file filename."""
1525
return osutils.pathjoin(config_dir(), 'locations.conf')
1528
def authentication_config_filename():
1529
"""Return per-user authentication ini file filename."""
1530
return osutils.pathjoin(config_dir(), 'authentication.conf')
1533
def user_ignore_config_filename():
1534
"""Return the user default ignore filename"""
1535
return osutils.pathjoin(config_dir(), 'ignore')
1539
"""Return the directory name to store crash files.
1541
This doesn't implicitly create it.
1543
On Windows it's in the config directory; elsewhere it's /var/crash
1544
which may be monitored by apport. It can be overridden by
1547
if sys.platform == 'win32':
1548
return osutils.pathjoin(config_dir(), 'Crash')
1550
# XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
1552
return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
1555
def xdg_cache_dir():
1556
# See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
1557
# Possibly this should be different on Windows?
1558
e = os.environ.get('XDG_CACHE_HOME', None)
1562
return os.path.expanduser('~/.cache')
1565
def _get_default_mail_domain(mailname_file='/etc/mailname'):
1566
"""If possible, return the assumed default email domain.
1568
:returns: string mail domain, or None.
1570
if sys.platform == 'win32':
1571
# No implementation yet; patches welcome
1574
f = open(mailname_file)
1575
except (IOError, OSError), e:
1578
domain = f.readline().strip()
1584
def default_email():
1585
v = os.environ.get('BZR_EMAIL')
1587
return v.decode(osutils.get_user_encoding())
1588
v = os.environ.get('EMAIL')
1590
return v.decode(osutils.get_user_encoding())
1591
name, email = _auto_user_id()
1593
return u'%s <%s>' % (name, email)
1596
raise errors.NoWhoami()
1599
def _auto_user_id():
1600
"""Calculate automatic user identification.
1602
:returns: (realname, email), either of which may be None if they can't be
1605
Only used when none is set in the environment or the id file.
1607
This only returns an email address if we can be fairly sure the
1608
address is reasonable, ie if /etc/mailname is set on unix.
1610
This doesn't use the FQDN as the default domain because that may be
1611
slow, and it doesn't use the hostname alone because that's not normally
1612
a reasonable address.
1614
if sys.platform == 'win32':
1615
# No implementation to reliably determine Windows default mail
1616
# address; please add one.
1619
default_mail_domain = _get_default_mail_domain()
1620
if not default_mail_domain:
1626
w = pwd.getpwuid(uid)
1628
trace.mutter('no passwd entry for uid %d?' % uid)
1631
# we try utf-8 first, because on many variants (like Linux),
1632
# /etc/passwd "should" be in utf-8, and because it's unlikely to give
1633
# false positives. (many users will have their user encoding set to
1634
# latin-1, which cannot raise UnicodeError.)
1636
gecos = w.pw_gecos.decode('utf-8')
1638
except UnicodeError:
1640
encoding = osutils.get_user_encoding()
1641
gecos = w.pw_gecos.decode(encoding)
1642
except UnicodeError, e:
1643
trace.mutter("cannot decode passwd entry %s" % w)
1646
username = w.pw_name.decode(encoding)
1647
except UnicodeError, e:
1648
trace.mutter("cannot decode passwd entry %s" % w)
1651
comma = gecos.find(',')
1655
realname = gecos[:comma]
1657
return realname, (username + '@' + default_mail_domain)
1398
1660
def parse_username(username):
1399
1661
"""Parse e-mail username and return a (name, address) tuple."""
1400
1662
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1401
1663
if match is None:
1402
1664
return (username, '')
1403
return (match.group(1), match.group(2))
1666
return (match.group(1), match.group(2))
1406
1669
def extract_email_address(e):
1435
1697
return self._config._get_configobj()
1437
1699
def get_option(self, name, section=None, default=None):
1438
with self.branch.lock_read():
1700
self.branch.lock_read()
1439
1702
return self._config.get_option(name, section, default)
1704
self.branch.unlock()
1441
1706
def set_option(self, value, name, section=None):
1442
1707
"""Set a per-branch configuration option"""
1443
1708
# FIXME: We shouldn't need to lock explicitly here but rather rely on
1444
1709
# higher levels providing the right lock -- vila 20101004
1445
with self.branch.lock_write():
1710
self.branch.lock_write()
1446
1712
self._config.set_option(value, name, section)
1714
self.branch.unlock()
1448
1716
def remove_option(self, option_name, section_name=None):
1449
1717
# FIXME: We shouldn't need to lock explicitly here but rather rely on
1450
1718
# higher levels providing the right lock -- vila 20101004
1451
with self.branch.lock_write():
1719
self.branch.lock_write()
1452
1721
self._config.remove_option(option_name, section_name)
1455
_authentication_config_permission_errors = set()
1723
self.branch.unlock()
1458
1726
class AuthenticationConfig(object):
1483
1751
# Note: the encoding below declares that the file itself is utf-8
1484
1752
# encoded, but the values in the ConfigObj are always Unicode.
1485
1753
self._config = ConfigObj(self._input, encoding='utf-8')
1486
except configobj.ConfigObjError as e:
1487
raise ParseConfigError(e.errors, e.config.filename)
1754
except configobj.ConfigObjError, e:
1755
raise errors.ParseConfigError(e.errors, e.config.filename)
1488
1756
except UnicodeError:
1489
raise ConfigContentError(self._filename)
1757
raise errors.ConfigContentError(self._filename)
1490
1758
return self._config
1492
def _check_permissions(self):
1493
"""Check permission of auth file are user read/write able only."""
1495
st = os.stat(self._filename)
1496
except OSError as e:
1497
if e.errno != errno.ENOENT:
1498
trace.mutter('Unable to stat %r: %r', self._filename, e)
1500
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):
1504
if (self._filename not in _authentication_config_permission_errors and
1505
not GlobalConfig().suppress_warning(
1506
'insecure_permissions')):
1507
trace.warning("The file '%s' has insecure "
1508
"file permissions. Saved passwords may be accessible "
1509
"by other users.", self._filename)
1510
_authentication_config_permission_errors.add(self._filename)
1512
1760
def _save(self):
1513
1761
"""Save the config file, only tests should use it for now."""
1514
1762
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)
1763
ensure_config_dir_exists(conf_dir)
1764
f = file(self._filename, 'wb')
1518
f = os.fdopen(fd, 'wb')
1519
1766
self._get_config().write(f)
2507
2737
option_registry.register(
2508
2738
ListOption('debug_flags', default=[],
2509
help='Debug flags to activate.'))
2739
help='Debug flags to activate.'))
2510
2740
option_registry.register(
2511
2741
Option('default_format', default='2a',
2512
2742
help='Format used when creating branches.'))
2513
2743
option_registry.register(
2744
Option('dpush_strict', default=None,
2745
from_unicode=bool_from_store,
2747
The default value for ``dpush --strict``.
2749
If present, defines the ``--strict`` option default value for checking
2750
uncommitted changes before pushing into a different VCS without any
2751
custom bzr metadata.
2753
option_registry.register(
2514
2754
Option('editor',
2515
2755
help='The command called to launch an editor to enter a message.'))
2516
2756
option_registry.register(
2517
Option('email', override_from_env=['BRZ_EMAIL', 'BZR_EMAIL'],
2518
default=bedding.default_email, help='The users identity'))
2757
Option('email', override_from_env=['BZR_EMAIL'], default=default_email,
2758
help='The users identity'))
2759
option_registry.register(
2760
Option('gpg_signing_command',
2763
Program to use use for creating signatures.
2765
This should support at least the -u and --clearsign options.
2519
2767
option_registry.register(
2520
2768
Option('gpg_signing_key',
2610
2866
lost if the machine crashes. See also dirstate.fdatasync.
2612
2868
option_registry.register_lazy('smtp_server',
2613
'breezy.smtp_connection', 'smtp_server')
2869
'bzrlib.smtp_connection', 'smtp_server')
2614
2870
option_registry.register_lazy('smtp_password',
2615
'breezy.smtp_connection', 'smtp_password')
2871
'bzrlib.smtp_connection', 'smtp_password')
2616
2872
option_registry.register_lazy('smtp_username',
2617
'breezy.smtp_connection', 'smtp_username')
2873
'bzrlib.smtp_connection', 'smtp_username')
2618
2874
option_registry.register(
2619
2875
Option('selftest.timeout',
2621
from_unicode=int_from_store,
2622
help='Abort selftest if one test takes longer than this many seconds',
2877
from_unicode=int_from_store,
2878
help='Abort selftest if one test takes longer than this many seconds',
2625
2881
option_registry.register(
2626
2882
Option('send_strict', default=None,
2659
2911
help='''Where submissions from this branch are mailed to.'''))
2660
2912
option_registry.register(
2661
2913
ListOption('suppress_warnings',
2663
help="List of warning classes to suppress."))
2915
help="List of warning classes to suppress."))
2664
2916
option_registry.register(
2665
2917
Option('validate_signatures_in_log', default=False,
2666
2918
from_unicode=bool_from_store, invalid='warning',
2667
help='''Whether to validate signatures in brz log.'''))
2919
help='''Whether to validate signatures in bzr log.'''))
2668
2920
option_registry.register_lazy('ssl.ca_certs',
2669
'breezy.transport.http', 'opt_ssl_ca_certs')
2921
'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_ca_certs')
2671
2923
option_registry.register_lazy('ssl.cert_reqs',
2672
'breezy.transport.http', 'opt_ssl_cert_reqs')
2924
'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
2675
2927
class Section(object):