mercurial/config.py
author Christian Ebert <blacktrash@gmx.net>
Wed, 01 Dec 2010 10:51:49 +0100
branchstable
changeset 13069 6aff4f144ad3
parent 11292 037d910734de
child 13031 3da456d0c885
permissions -rw-r--r--
keyword: copy: when copied source is a symlink, follow it 1) hg cp symlink copy -> copy is a symlink. 2) cp symlink copy; hg cp -A symlink copy -> copy is a regular file. In the second case we have to follow the symlink to its target to find out whether we have to unexpand keywords in the copy. Add test covering the case where the copied link's target is ignored by keyword but has content which would match the regex for expanded keywords to check whether we indeed leave the destination alone.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
8229
ddf3d6656e7c config: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 8222
diff changeset
     1
# config.py - configuration parsing for Mercurial
ddf3d6656e7c config: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 8222
diff changeset
     2
#
ddf3d6656e7c config: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 8222
diff changeset
     3
#  Copyright 2009 Matt Mackall <mpm@selenic.com> and others
ddf3d6656e7c config: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 8222
diff changeset
     4
#
ddf3d6656e7c config: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 8222
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 10042
diff changeset
     6
# GNU General Public License version 2 or any later version.
8229
ddf3d6656e7c config: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 8222
diff changeset
     7
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     8
from i18n import _
11224
f23f87462c18 config: expand hgrc %include paths
Chad Dombrova <chadrik@gmail.com>
parents: 10295
diff changeset
     9
import error, util
8312
b87a50b7125c separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents: 8298
diff changeset
    10
import re, os
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    11
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    12
class sortdict(dict):
8184
9189afe1eba3 config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents: 8183
diff changeset
    13
    'a simple sorted dictionary'
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    14
    def __init__(self, data=None):
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    15
        self._list = []
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    16
        if data:
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    17
            self.update(data)
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    18
    def copy(self):
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    19
        return sortdict(self)
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    20
    def __setitem__(self, key, val):
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    21
        if key in self:
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    22
            self._list.remove(key)
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    23
        self._list.append(key)
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    24
        dict.__setitem__(self, key, val)
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    25
    def __iter__(self):
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    26
        return self._list.__iter__()
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    27
    def update(self, src):
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    28
        for k in src:
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    29
            self[k] = src[k]
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    30
    def items(self):
8222
d30a21594812 more whitespace cleanup and some other style nits
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8198
diff changeset
    31
        return [(k, self[k]) for k in self._list]
8184
9189afe1eba3 config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents: 8183
diff changeset
    32
    def __delitem__(self, key):
9189afe1eba3 config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents: 8183
diff changeset
    33
        dict.__delitem__(self, key)
9189afe1eba3 config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents: 8183
diff changeset
    34
        self._list.remove(key)
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    35
8186
6a0018cdb2fe config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents: 8185
diff changeset
    36
class config(object):
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    37
    def __init__(self, data=None):
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    38
        self._data = {}
8185
dc10a7a3f1d4 config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents: 8184
diff changeset
    39
        self._source = {}
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    40
        if data:
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    41
            for k in data._data:
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    42
                self._data[k] = data[k].copy()
8185
dc10a7a3f1d4 config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents: 8184
diff changeset
    43
            self._source = data._source.copy()
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    44
    def copy(self):
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    45
        return config(self)
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    46
    def __contains__(self, section):
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    47
        return section in self._data
8186
6a0018cdb2fe config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents: 8185
diff changeset
    48
    def __getitem__(self, section):
6a0018cdb2fe config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents: 8185
diff changeset
    49
        return self._data.get(section, {})
6a0018cdb2fe config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents: 8185
diff changeset
    50
    def __iter__(self):
6a0018cdb2fe config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents: 8185
diff changeset
    51
        for d in self.sections():
6a0018cdb2fe config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents: 8185
diff changeset
    52
            yield d
8193
94246e90081e config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents: 8192
diff changeset
    53
    def update(self, src):
94246e90081e config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents: 8192
diff changeset
    54
        for s in src:
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    55
            if s not in self:
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    56
                self._data[s] = sortdict()
8193
94246e90081e config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents: 8192
diff changeset
    57
            self._data[s].update(src._data[s])
94246e90081e config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents: 8192
diff changeset
    58
        self._source.update(src._source)
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    59
    def get(self, section, item, default=None):
8185
dc10a7a3f1d4 config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents: 8184
diff changeset
    60
        return self._data.get(section, {}).get(item, default)
8198
cf9accffd0b3 config: getsource -> source
Matt Mackall <mpm@selenic.com>
parents: 8193
diff changeset
    61
    def source(self, section, item):
8185
dc10a7a3f1d4 config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents: 8184
diff changeset
    62
        return self._source.get((section, item), "")
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    63
    def sections(self):
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    64
        return sorted(self._data.keys())
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    65
    def items(self, section):
8185
dc10a7a3f1d4 config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents: 8184
diff changeset
    66
        return self._data.get(section, {}).items()
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    67
    def set(self, section, item, value, source=""):
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    68
        if section not in self:
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    69
            self._data[section] = sortdict()
8185
dc10a7a3f1d4 config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents: 8184
diff changeset
    70
        self._data[section][item] = value
dc10a7a3f1d4 config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents: 8184
diff changeset
    71
        self._source[(section, item)] = source
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    72
8265
52c5be55af82 config: add parse interface
Matt Mackall <mpm@selenic.com>
parents: 8263
diff changeset
    73
    def parse(self, src, data, sections=None, remap=None, include=None):
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    74
        sectionre = re.compile(r'\[([^\[]+)\]')
8263
41031699550a config: allow spaces in key portion of items
Matt Mackall <mpm@selenic.com>
parents: 8229
diff changeset
    75
        itemre = re.compile(r'([^=\s][^=]*?)\s*=\s*(.*\S|)')
10295
44c923eeb81d config: handle short continuations (issue1999)
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    76
        contre = re.compile(r'\s+(\S|\S.*\S)\s*$')
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    77
        emptyre = re.compile(r'(;|#|\s*$)')
8192
5fd8e60a935d config: deal with spaces at end of line more carefully
Matt Mackall <mpm@selenic.com>
parents: 8187
diff changeset
    78
        unsetre = re.compile(r'%unset\s+(\S+)')
10295
44c923eeb81d config: handle short continuations (issue1999)
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    79
        includere = re.compile(r'%include\s+(\S|\S.*\S)\s*$')
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    80
        section = ""
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    81
        item = None
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    82
        line = 0
9339
9be91129c96e config: improve code readability
Andrey <py4fun@gmail.com>
parents: 9136
diff changeset
    83
        cont = False
8180
6fc30fe7f3e7 hgweb: use config.config
Matt Mackall <mpm@selenic.com>
parents: 8144
diff changeset
    84
9136
31177742f54a for calls expecting bool args, pass bool instead of int
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 8312
diff changeset
    85
        for l in data.splitlines(True):
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    86
            line += 1
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    87
            if cont:
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    88
                m = contre.match(l)
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    89
                if m:
8193
94246e90081e config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents: 8192
diff changeset
    90
                    if sections and section not in sections:
94246e90081e config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents: 8192
diff changeset
    91
                        continue
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    92
                    v = self.get(section, item) + "\n" + m.group(1)
8265
52c5be55af82 config: add parse interface
Matt Mackall <mpm@selenic.com>
parents: 8263
diff changeset
    93
                    self.set(section, item, v, "%s:%d" % (src, line))
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    94
                    continue
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    95
                item = None
9469
7f0f882af23d config: abort on indented non-continuation lines (issue1829)
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 8312
diff changeset
    96
                cont = False
8183
2858ab754995 config: allow including other config files
Matt Mackall <mpm@selenic.com>
parents: 8180
diff changeset
    97
            m = includere.match(l)
2858ab754995 config: allow including other config files
Matt Mackall <mpm@selenic.com>
parents: 8180
diff changeset
    98
            if m:
11224
f23f87462c18 config: expand hgrc %include paths
Chad Dombrova <chadrik@gmail.com>
parents: 10295
diff changeset
    99
                inc = util.expandpath(m.group(1))
8265
52c5be55af82 config: add parse interface
Matt Mackall <mpm@selenic.com>
parents: 8263
diff changeset
   100
                base = os.path.dirname(src)
8183
2858ab754995 config: allow including other config files
Matt Mackall <mpm@selenic.com>
parents: 8180
diff changeset
   101
                inc = os.path.normpath(os.path.join(base, inc))
8265
52c5be55af82 config: add parse interface
Matt Mackall <mpm@selenic.com>
parents: 8263
diff changeset
   102
                if include:
10042
7cdd2a7db2c2 config: raise ConfigError on non-existing include files
Martin Geisler <mg@lazybytes.net>
parents: 9471
diff changeset
   103
                    try:
7cdd2a7db2c2 config: raise ConfigError on non-existing include files
Martin Geisler <mg@lazybytes.net>
parents: 9471
diff changeset
   104
                        include(inc, remap=remap, sections=sections)
7cdd2a7db2c2 config: raise ConfigError on non-existing include files
Martin Geisler <mg@lazybytes.net>
parents: 9471
diff changeset
   105
                    except IOError, inst:
11292
037d910734de error: fix up test-hgrc
Matt Mackall <mpm@selenic.com>
parents: 11288
diff changeset
   106
                        raise error.ParseError(_("cannot include %s (%s)")
037d910734de error: fix up test-hgrc
Matt Mackall <mpm@selenic.com>
parents: 11288
diff changeset
   107
                                               % (inc, inst.strerror),
037d910734de error: fix up test-hgrc
Matt Mackall <mpm@selenic.com>
parents: 11288
diff changeset
   108
                                               "%s:%s" % (src, line))
8183
2858ab754995 config: allow including other config files
Matt Mackall <mpm@selenic.com>
parents: 8180
diff changeset
   109
                continue
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   110
            if emptyre.match(l):
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   111
                continue
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   112
            m = sectionre.match(l)
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   113
            if m:
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   114
                section = m.group(1)
8298
9542f4c3fa1b config: make remap actually work
Matt Mackall <mpm@selenic.com>
parents: 8265
diff changeset
   115
                if remap:
9542f4c3fa1b config: make remap actually work
Matt Mackall <mpm@selenic.com>
parents: 8265
diff changeset
   116
                    section = remap.get(section, section)
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   117
                if section not in self:
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   118
                    self._data[section] = sortdict()
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   119
                continue
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   120
            m = itemre.match(l)
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   121
            if m:
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   122
                item = m.group(1)
9339
9be91129c96e config: improve code readability
Andrey <py4fun@gmail.com>
parents: 9136
diff changeset
   123
                cont = True
8193
94246e90081e config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents: 8192
diff changeset
   124
                if sections and section not in sections:
94246e90081e config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents: 8192
diff changeset
   125
                    continue
8265
52c5be55af82 config: add parse interface
Matt Mackall <mpm@selenic.com>
parents: 8263
diff changeset
   126
                self.set(section, item, m.group(2), "%s:%d" % (src, line))
8144
fca54469480e ui: introduce new config parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   127
                continue
8184
9189afe1eba3 config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents: 8183
diff changeset
   128
            m = unsetre.match(l)
9189afe1eba3 config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents: 8183
diff changeset
   129
            if m:
9189afe1eba3 config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents: 8183
diff changeset
   130
                name = m.group(1)
8193
94246e90081e config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents: 8192
diff changeset
   131
                if sections and section not in sections:
94246e90081e config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents: 8192
diff changeset
   132
                    continue
8184
9189afe1eba3 config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents: 8183
diff changeset
   133
                if self.get(section, name) != None:
9189afe1eba3 config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents: 8183
diff changeset
   134
                    del self._data[section][name]
9189afe1eba3 config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents: 8183
diff changeset
   135
                continue
9189afe1eba3 config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents: 8183
diff changeset
   136
11288
2123aad24d56 error: add new ParseError for various parsing errors
Matt Mackall <mpm@selenic.com>
parents: 11224
diff changeset
   137
            raise error.ParseError(l.rstrip(), ("%s:%s" % (src, line)))
8265
52c5be55af82 config: add parse interface
Matt Mackall <mpm@selenic.com>
parents: 8263
diff changeset
   138
52c5be55af82 config: add parse interface
Matt Mackall <mpm@selenic.com>
parents: 8263
diff changeset
   139
    def read(self, path, fp=None, sections=None, remap=None):
52c5be55af82 config: add parse interface
Matt Mackall <mpm@selenic.com>
parents: 8263
diff changeset
   140
        if not fp:
52c5be55af82 config: add parse interface
Matt Mackall <mpm@selenic.com>
parents: 8263
diff changeset
   141
            fp = open(path)
52c5be55af82 config: add parse interface
Matt Mackall <mpm@selenic.com>
parents: 8263
diff changeset
   142
        self.parse(path, fp.read(), sections, remap, self.read)