##// END OF EJS Templates
dispatch: enforce bytes when converting boolean flags to config items...
dispatch: enforce bytes when converting boolean flags to config items This fixes --verbose on Python 3.

File last commit:

r31176:99c5843b default
r31305:dc9842a7 default
Show More
config.py
177 lines | 6.3 KiB | text/x-python | PythonLexer
Martin Geisler
config: add copyright and license header
r8229 # config.py - configuration parsing for Mercurial
#
# Copyright 2009 Matt Mackall <mpm@selenic.com> and others
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Martin Geisler
config: add copyright and license header
r8229
Gregory Szorc
config: use absolute_import
r25923 from __future__ import absolute_import
import errno
import os
from .i18n import _
from . import (
error,
util,
)
Matt Mackall
ui: introduce new config parser
r8144
Matt Mackall
config: add some helper methods
r8186 class config(object):
Jordi Gutiérrez Hermoso
config: give it an includepaths option for looking for config files...
r25095 def __init__(self, data=None, includepaths=[]):
Matt Mackall
ui: introduce new config parser
r8144 self._data = {}
Matt Mackall
config: split source data out into separate map
r8185 self._source = {}
FUJIWARA Katsunori
config: discard "%unset" values defined in the other files read in previously...
r19087 self._unset = []
Jordi Gutiérrez Hermoso
config: give it an includepaths option for looking for config files...
r25095 self._includepaths = includepaths
Matt Mackall
ui: introduce new config parser
r8144 if data:
for k in data._data:
self._data[k] = data[k].copy()
Matt Mackall
config: split source data out into separate map
r8185 self._source = data._source.copy()
Matt Mackall
ui: introduce new config parser
r8144 def copy(self):
return config(self)
def __contains__(self, section):
return section in self._data
Bryan O'Sullivan
config: add hasconfig method and supporting plumbing...
r27696 def hasitem(self, section, item):
return item in self._data.get(section, {})
Matt Mackall
config: add some helper methods
r8186 def __getitem__(self, section):
return self._data.get(section, {})
def __iter__(self):
for d in self.sections():
yield d
Matt Mackall
config: add section filter to read...
r8193 def update(self, src):
FUJIWARA Katsunori
config: discard "%unset" values defined in the other files read in previously...
r19087 for s, n in src._unset:
if s in self and n in self._data[s]:
del self._data[s][n]
del self._source[(s, n)]
Matt Mackall
config: add section filter to read...
r8193 for s in src:
Matt Mackall
ui: introduce new config parser
r8144 if s not in self:
Angel Ezquerra
config: move config.sortdict class into util...
r21813 self._data[s] = util.sortdict()
Matt Mackall
config: add section filter to read...
r8193 self._data[s].update(src._data[s])
self._source.update(src._source)
Matt Mackall
ui: introduce new config parser
r8144 def get(self, section, item, default=None):
Matt Mackall
config: split source data out into separate map
r8185 return self._data.get(section, {}).get(item, default)
Pierre-Yves David
config: have a way to backup and restore value in config...
r15919
def backup(self, section, item):
timeless@mozdev.org
spelling: value
r17527 """return a tuple allowing restore to reinstall a previous value
Pierre-Yves David
config: have a way to backup and restore value in config...
r15919
timeless@mozdev.org
grammar: it-handles
r17530 The main reason we need it is because it handles the "no data" case.
Pierre-Yves David
config: have a way to backup and restore value in config...
r15919 """
try:
value = self._data[section][item]
source = self.source(section, item)
return (section, item, value, source)
except KeyError:
return (section, item)
Matt Mackall
config: getsource -> source
r8198 def source(self, section, item):
Matt Mackall
config: split source data out into separate map
r8185 return self._source.get((section, item), "")
Matt Mackall
ui: introduce new config parser
r8144 def sections(self):
return sorted(self._data.keys())
def items(self, section):
Matt Mackall
config: split source data out into separate map
r8185 return self._data.get(section, {}).items()
Matt Mackall
ui: introduce new config parser
r8144 def set(self, section, item, value, source=""):
if section not in self:
Angel Ezquerra
config: move config.sortdict class into util...
r21813 self._data[section] = util.sortdict()
Matt Mackall
config: split source data out into separate map
r8185 self._data[section][item] = value
Mads Kiilerich
config: don't set source when no source is specified - don't overwrite with ''...
r20789 if source:
self._source[(section, item)] = source
Matt Mackall
ui: introduce new config parser
r8144
Pierre-Yves David
config: have a way to backup and restore value in config...
r15919 def restore(self, data):
"""restore data returned by self.backup"""
if len(data) == 4:
# restore old data
section, item, value, source = data
self._data[section][item] = value
self._source[(section, item)] = source
else:
# no data before, remove everything
section, item = data
if section in self._data:
Pierre-Yves David
config: fix restoreconfig of non existing config...
r22037 self._data[section].pop(item, None)
Pierre-Yves David
config: have a way to backup and restore value in config...
r15919 self._source.pop((section, item), None)
Matt Mackall
config: add parse interface
r8265 def parse(self, src, data, sections=None, remap=None, include=None):
Augie Fackler
config: mark parser regexes as bytes explicitly...
r30349 sectionre = util.re.compile(br'\[([^\[]+)\]')
itemre = util.re.compile(br'([^=\s][^=]*?)\s*=\s*(.*\S|)')
contre = util.re.compile(br'\s+(\S|\S.*\S)\s*$')
emptyre = util.re.compile(br'(;|#|\s*$)')
commentre = util.re.compile(br'(;|#)')
unsetre = util.re.compile(br'%unset\s+(\S+)')
includere = util.re.compile(br'%include\s+(\S|\S.*\S)\s*$')
Matt Mackall
ui: introduce new config parser
r8144 section = ""
item = None
line = 0
config: improve code readability
r9339 cont = False
Matt Mackall
hgweb: use config.config
r8180
Nicolas Dumazet
for calls expecting bool args, pass bool instead of int...
r9136 for l in data.splitlines(True):
Matt Mackall
ui: introduce new config parser
r8144 line += 1
Matt Mackall
config: discard UTF-8 BOM if found
r16348 if line == 1 and l.startswith('\xef\xbb\xbf'):
# Someone set us up the BOM
l = l[3:]
Matt Mackall
ui: introduce new config parser
r8144 if cont:
Matt Mackall
config: handle comment lines in continuations (issue2854)
r14642 if commentre.match(l):
continue
Matt Mackall
ui: introduce new config parser
r8144 m = contre.match(l)
if m:
Matt Mackall
config: add section filter to read...
r8193 if sections and section not in sections:
continue
Matt Mackall
ui: introduce new config parser
r8144 v = self.get(section, item) + "\n" + m.group(1)
Matt Mackall
config: add parse interface
r8265 self.set(section, item, v, "%s:%d" % (src, line))
Matt Mackall
ui: introduce new config parser
r8144 continue
item = None
Nicolas Dumazet
config: abort on indented non-continuation lines (issue1829)...
r9469 cont = False
Matt Mackall
config: allow including other config files
r8183 m = includere.match(l)
Jordi Gutiérrez Hermoso
config: give it an includepaths option for looking for config files...
r25095
if m and include:
expanded = util.expandpath(m.group(1))
includepaths = [os.path.dirname(src)] + self._includepaths
for base in includepaths:
inc = os.path.normpath(os.path.join(base, expanded))
Martin Geisler
config: raise ConfigError on non-existing include files...
r10042 try:
include(inc, remap=remap, sections=sections)
Jordi Gutiérrez Hermoso
config: give it an includepaths option for looking for config files...
r25095 break
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Matt Mackall
config: ignore include errors for nonexistent files
r14486 if inst.errno != errno.ENOENT:
raise error.ParseError(_("cannot include %s (%s)")
% (inc, inst.strerror),
"%s:%s" % (src, line))
Matt Mackall
config: allow including other config files
r8183 continue
Matt Mackall
ui: introduce new config parser
r8144 if emptyre.match(l):
continue
m = sectionre.match(l)
if m:
section = m.group(1)
Matt Mackall
config: make remap actually work
r8298 if remap:
section = remap.get(section, section)
Matt Mackall
ui: introduce new config parser
r8144 if section not in self:
Angel Ezquerra
config: move config.sortdict class into util...
r21813 self._data[section] = util.sortdict()
Matt Mackall
ui: introduce new config parser
r8144 continue
m = itemre.match(l)
if m:
item = m.group(1)
config: improve code readability
r9339 cont = True
Matt Mackall
config: add section filter to read...
r8193 if sections and section not in sections:
continue
Matt Mackall
config: add parse interface
r8265 self.set(section, item, m.group(2), "%s:%d" % (src, line))
Matt Mackall
ui: introduce new config parser
r8144 continue
Matt Mackall
config: add %unset name support
r8184 m = unsetre.match(l)
if m:
name = m.group(1)
Matt Mackall
config: add section filter to read...
r8193 if sections and section not in sections:
continue
Martin Geisler
code style: prefer 'is' and 'is not' tests with singletons
r13031 if self.get(section, name) is not None:
Matt Mackall
config: add %unset name support
r8184 del self._data[section][name]
FUJIWARA Katsunori
config: discard "%unset" values defined in the other files read in previously...
r19087 self._unset.append((section, name))
Matt Mackall
config: add %unset name support
r8184 continue
Matt Mackall
error: add new ParseError for various parsing errors
r11288 raise error.ParseError(l.rstrip(), ("%s:%s" % (src, line)))
Matt Mackall
config: add parse interface
r8265
def read(self, path, fp=None, sections=None, remap=None):
if not fp:
Augie Fackler
config: load included config files in binary mode...
r31154 fp = util.posixfile(path, 'rb')
Augie Fackler
config: add sanity assert that files are opened as binary...
r31176 assert getattr(fp, 'mode', r'rb') == r'rb', (
'config files must be opened in binary mode, got fp=%r mode=%r' % (
fp, fp.mode))
Augie Fackler
config: pass some optional args as keywords...
r31155 self.parse(path, fp.read(),
sections=sections, remap=remap, include=self.read)