mercurial/config.py
author Nicolas Dumazet <nicdumz.commits@gmail.com>
Sun, 24 May 2009 18:43:05 +0900
changeset 8599 1f706b1b62f3
parent 8312 b87a50b7125c
child 9136 31177742f54a
child 9469 7f0f882af23d
permissions -rw-r--r--
inotify: server: refactor updatestatus() * Instead of one entry point, use two entry points, updatefile() and deletefile(), both internally calling the helper function _updatestatus * Do not rely on TypeError to detect the type of oldstatus: use isinstance * The call updatestatus(wpath, None) in deleted() was a bit particular: because no osstat and no newstatus was given, the newstatus was determined using the data stored internally. To replace this exact behavior with the new code, one would use: root, fn = self.split(wpath) d = self.dir(self.tree, root) self.filedeleted(wpath, d.get(fn)) This, however, duplicates code with _updatestatus(), which led us to an interesting question: why are we basing ourselves on repowatcher data to update the status, where everywhere else, we are comparing against dirsate? There is no reason to do this, which is why the new code is: self.filedeleted(wpath, self.repo.dirstate[wpath]) Incidentally, after this, the test for issue1371 passes again.

# 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
# GNU General Public License version 2, incorporated herein by reference.

from i18n import _
import error
import re, os

class sortdict(dict):
    'a simple sorted dictionary'
    def __init__(self, data=None):
        self._list = []
        if data:
            self.update(data)
    def copy(self):
        return sortdict(self)
    def __setitem__(self, key, val):
        if key in self:
            self._list.remove(key)
        self._list.append(key)
        dict.__setitem__(self, key, val)
    def __iter__(self):
        return self._list.__iter__()
    def update(self, src):
        for k in src:
            self[k] = src[k]
    def items(self):
        return [(k, self[k]) for k in self._list]
    def __delitem__(self, key):
        dict.__delitem__(self, key)
        self._list.remove(key)

class config(object):
    def __init__(self, data=None):
        self._data = {}
        self._source = {}
        if data:
            for k in data._data:
                self._data[k] = data[k].copy()
            self._source = data._source.copy()
    def copy(self):
        return config(self)
    def __contains__(self, section):
        return section in self._data
    def __getitem__(self, section):
        return self._data.get(section, {})
    def __iter__(self):
        for d in self.sections():
            yield d
    def update(self, src):
        for s in src:
            if s not in self:
                self._data[s] = sortdict()
            self._data[s].update(src._data[s])
        self._source.update(src._source)
    def get(self, section, item, default=None):
        return self._data.get(section, {}).get(item, default)
    def source(self, section, item):
        return self._source.get((section, item), "")
    def sections(self):
        return sorted(self._data.keys())
    def items(self, section):
        return self._data.get(section, {}).items()
    def set(self, section, item, value, source=""):
        if section not in self:
            self._data[section] = sortdict()
        self._data[section][item] = value
        self._source[(section, item)] = source

    def parse(self, src, data, sections=None, remap=None, include=None):
        sectionre = re.compile(r'\[([^\[]+)\]')
        itemre = re.compile(r'([^=\s][^=]*?)\s*=\s*(.*\S|)')
        contre = re.compile(r'\s+(\S.*\S)')
        emptyre = re.compile(r'(;|#|\s*$)')
        unsetre = re.compile(r'%unset\s+(\S+)')
        includere = re.compile(r'%include\s+(\S.*\S)')
        section = ""
        item = None
        line = 0
        cont = 0

        for l in data.splitlines(1):
            line += 1
            if cont:
                m = contre.match(l)
                if m:
                    if sections and section not in sections:
                        continue
                    v = self.get(section, item) + "\n" + m.group(1)
                    self.set(section, item, v, "%s:%d" % (src, line))
                    continue
                item = None
            m = includere.match(l)
            if m:
                inc = m.group(1)
                base = os.path.dirname(src)
                inc = os.path.normpath(os.path.join(base, inc))
                if include:
                    include(inc, remap=remap, sections=sections)
                continue
            if emptyre.match(l):
                continue
            m = sectionre.match(l)
            if m:
                section = m.group(1)
                if remap:
                    section = remap.get(section, section)
                if section not in self:
                    self._data[section] = sortdict()
                continue
            m = itemre.match(l)
            if m:
                item = m.group(1)
                cont = 1
                if sections and section not in sections:
                    continue
                self.set(section, item, m.group(2), "%s:%d" % (src, line))
                continue
            m = unsetre.match(l)
            if m:
                name = m.group(1)
                if sections and section not in sections:
                    continue
                if self.get(section, name) != None:
                    del self._data[section][name]
                continue

            raise error.ConfigError(_('config error at %s:%d: \'%s\'')
                                    % (src, line, l.rstrip()))

    def read(self, path, fp=None, sections=None, remap=None):
        if not fp:
            fp = open(path)
        self.parse(path, fp.read(), sections, remap, self.read)