Mercurial > public > mercurial-scm > hg-stable
annotate mercurial/config.py @ 15919:69e792cf7851
config: have a way to backup and restore value in config
This is introduce to allow temporary overwriting of a config value while being
able to reinstall the old value once done. The main advantage over using
``config`` and ``setconfig`` is that backup and restore will properly restore
the lack of any config. Restoring the fact that there was no value is important
to allow config user to keep using meaniful default value.
A more naive approach will result in the following scenario::
Before:
config(section, item, my_default) --> my_default
temporal overwrite
old = config(section, item)
?
setconfig(section, item, old)
After
config(section, item, my_default) --> None
The first user of this feature should be mq to overwriting minimal phase of
future commit.
author | Pierre-Yves David <pierre-yves.david@logilab.fr> |
---|---|
date | Wed, 18 Jan 2012 16:52:26 +0100 |
parents | 5fb3cb7266e5 |
children | f350021ee32e |
rev | line source |
---|---|
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 | 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 | 8 from i18n import _ |
11224
f23f87462c18
config: expand hgrc %include paths
Chad Dombrova <chadrik@gmail.com>
parents:
10295
diff
changeset
|
9 import error, util |
14486
4e3eda05189b
config: ignore include errors for nonexistent files
Matt Mackall <mpm@selenic.com>
parents:
13664
diff
changeset
|
10 import re, os, errno |
8144 | 11 |
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 | 14 def __init__(self, data=None): |
15 self._list = [] | |
16 if data: | |
17 self.update(data) | |
18 def copy(self): | |
19 return sortdict(self) | |
20 def __setitem__(self, key, val): | |
21 if key in self: | |
22 self._list.remove(key) | |
23 self._list.append(key) | |
24 dict.__setitem__(self, key, val) | |
25 def __iter__(self): | |
26 return self._list.__iter__() | |
27 def update(self, src): | |
28 for k in src: | |
29 self[k] = src[k] | |
14696
5fb3cb7266e5
config.sortdict: override clear method
Sune Foldager <cryo@cyanite.org>
parents:
14659
diff
changeset
|
30 def clear(self): |
5fb3cb7266e5
config.sortdict: override clear method
Sune Foldager <cryo@cyanite.org>
parents:
14659
diff
changeset
|
31 dict.clear(self) |
5fb3cb7266e5
config.sortdict: override clear method
Sune Foldager <cryo@cyanite.org>
parents:
14659
diff
changeset
|
32 self._list = [] |
8144 | 33 def items(self): |
8222
d30a21594812
more whitespace cleanup and some other style nits
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
8198
diff
changeset
|
34 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
|
35 def __delitem__(self, key): |
9189afe1eba3
config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents:
8183
diff
changeset
|
36 dict.__delitem__(self, key) |
9189afe1eba3
config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents:
8183
diff
changeset
|
37 self._list.remove(key) |
8144 | 38 |
8186
6a0018cdb2fe
config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents:
8185
diff
changeset
|
39 class config(object): |
8144 | 40 def __init__(self, data=None): |
41 self._data = {} | |
8185
dc10a7a3f1d4
config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents:
8184
diff
changeset
|
42 self._source = {} |
8144 | 43 if data: |
44 for k in data._data: | |
45 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
|
46 self._source = data._source.copy() |
8144 | 47 def copy(self): |
48 return config(self) | |
49 def __contains__(self, section): | |
50 return section in self._data | |
8186
6a0018cdb2fe
config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents:
8185
diff
changeset
|
51 def __getitem__(self, section): |
6a0018cdb2fe
config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents:
8185
diff
changeset
|
52 return self._data.get(section, {}) |
6a0018cdb2fe
config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents:
8185
diff
changeset
|
53 def __iter__(self): |
6a0018cdb2fe
config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents:
8185
diff
changeset
|
54 for d in self.sections(): |
6a0018cdb2fe
config: add some helper methods
Matt Mackall <mpm@selenic.com>
parents:
8185
diff
changeset
|
55 yield d |
8193
94246e90081e
config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents:
8192
diff
changeset
|
56 def update(self, src): |
94246e90081e
config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents:
8192
diff
changeset
|
57 for s in src: |
8144 | 58 if s not in self: |
59 self._data[s] = sortdict() | |
8193
94246e90081e
config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents:
8192
diff
changeset
|
60 self._data[s].update(src._data[s]) |
94246e90081e
config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents:
8192
diff
changeset
|
61 self._source.update(src._source) |
8144 | 62 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
|
63 return self._data.get(section, {}).get(item, default) |
15919
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
64 |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
65 def backup(self, section, item): |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
66 """return a tuple allowing restore to reinstall a previous valuesi |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
67 |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
68 The main reason we need it is because it handle the "no data" case. |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
69 """ |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
70 try: |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
71 value = self._data[section][item] |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
72 source = self.source(section, item) |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
73 return (section, item, value, source) |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
74 except KeyError: |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
75 return (section, item) |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
76 |
8198
cf9accffd0b3
config: getsource -> source
Matt Mackall <mpm@selenic.com>
parents:
8193
diff
changeset
|
77 def source(self, section, item): |
8185
dc10a7a3f1d4
config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents:
8184
diff
changeset
|
78 return self._source.get((section, item), "") |
8144 | 79 def sections(self): |
80 return sorted(self._data.keys()) | |
81 def items(self, section): | |
8185
dc10a7a3f1d4
config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents:
8184
diff
changeset
|
82 return self._data.get(section, {}).items() |
8144 | 83 def set(self, section, item, value, source=""): |
84 if section not in self: | |
85 self._data[section] = sortdict() | |
8185
dc10a7a3f1d4
config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents:
8184
diff
changeset
|
86 self._data[section][item] = value |
dc10a7a3f1d4
config: split source data out into separate map
Matt Mackall <mpm@selenic.com>
parents:
8184
diff
changeset
|
87 self._source[(section, item)] = source |
8144 | 88 |
15919
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
89 def restore(self, data): |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
90 """restore data returned by self.backup""" |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
91 if len(data) == 4: |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
92 # restore old data |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
93 section, item, value, source = data |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
94 self._data[section][item] = value |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
95 self._source[(section, item)] = source |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
96 else: |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
97 # no data before, remove everything |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
98 section, item = data |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
99 if section in self._data: |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
100 del self._data[section][item] |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
101 self._source.pop((section, item), None) |
69e792cf7851
config: have a way to backup and restore value in config
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
14696
diff
changeset
|
102 |
8265
52c5be55af82
config: add parse interface
Matt Mackall <mpm@selenic.com>
parents:
8263
diff
changeset
|
103 def parse(self, src, data, sections=None, remap=None, include=None): |
8144 | 104 sectionre = re.compile(r'\[([^\[]+)\]') |
8263
41031699550a
config: allow spaces in key portion of items
Matt Mackall <mpm@selenic.com>
parents:
8229
diff
changeset
|
105 itemre = re.compile(r'([^=\s][^=]*?)\s*=\s*(.*\S|)') |
10295
44c923eeb81d
config: handle short continuations (issue1999)
Matt Mackall <mpm@selenic.com>
parents:
10263
diff
changeset
|
106 contre = re.compile(r'\s+(\S|\S.*\S)\s*$') |
14659
4392594746f6
config: undo change of empty line definition
Matt Mackall <mpm@selenic.com>
parents:
14642
diff
changeset
|
107 emptyre = re.compile(r'(;|#|\s*$)') |
14642
fdcdb221a922
config: handle comment lines in continuations (issue2854)
Matt Mackall <mpm@selenic.com>
parents:
14486
diff
changeset
|
108 commentre = re.compile(r'(;|#)') |
8192
5fd8e60a935d
config: deal with spaces at end of line more carefully
Matt Mackall <mpm@selenic.com>
parents:
8187
diff
changeset
|
109 unsetre = re.compile(r'%unset\s+(\S+)') |
10295
44c923eeb81d
config: handle short continuations (issue1999)
Matt Mackall <mpm@selenic.com>
parents:
10263
diff
changeset
|
110 includere = re.compile(r'%include\s+(\S|\S.*\S)\s*$') |
8144 | 111 section = "" |
112 item = None | |
113 line = 0 | |
9339
9be91129c96e
config: improve code readability
Andrey <py4fun@gmail.com>
parents:
9136
diff
changeset
|
114 cont = False |
8180 | 115 |
9136
31177742f54a
for calls expecting bool args, pass bool instead of int
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8312
diff
changeset
|
116 for l in data.splitlines(True): |
8144 | 117 line += 1 |
118 if cont: | |
14642
fdcdb221a922
config: handle comment lines in continuations (issue2854)
Matt Mackall <mpm@selenic.com>
parents:
14486
diff
changeset
|
119 if commentre.match(l): |
fdcdb221a922
config: handle comment lines in continuations (issue2854)
Matt Mackall <mpm@selenic.com>
parents:
14486
diff
changeset
|
120 continue |
8144 | 121 m = contre.match(l) |
122 if m: | |
8193
94246e90081e
config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents:
8192
diff
changeset
|
123 if sections and section not in sections: |
94246e90081e
config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents:
8192
diff
changeset
|
124 continue |
8144 | 125 v = self.get(section, item) + "\n" + m.group(1) |
8265
52c5be55af82
config: add parse interface
Matt Mackall <mpm@selenic.com>
parents:
8263
diff
changeset
|
126 self.set(section, item, v, "%s:%d" % (src, line)) |
8144 | 127 continue |
128 item = None | |
9469
7f0f882af23d
config: abort on indented non-continuation lines (issue1829)
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8312
diff
changeset
|
129 cont = False |
8183
2858ab754995
config: allow including other config files
Matt Mackall <mpm@selenic.com>
parents:
8180
diff
changeset
|
130 m = includere.match(l) |
2858ab754995
config: allow including other config files
Matt Mackall <mpm@selenic.com>
parents:
8180
diff
changeset
|
131 if m: |
11224
f23f87462c18
config: expand hgrc %include paths
Chad Dombrova <chadrik@gmail.com>
parents:
10295
diff
changeset
|
132 inc = util.expandpath(m.group(1)) |
8265
52c5be55af82
config: add parse interface
Matt Mackall <mpm@selenic.com>
parents:
8263
diff
changeset
|
133 base = os.path.dirname(src) |
8183
2858ab754995
config: allow including other config files
Matt Mackall <mpm@selenic.com>
parents:
8180
diff
changeset
|
134 inc = os.path.normpath(os.path.join(base, inc)) |
8265
52c5be55af82
config: add parse interface
Matt Mackall <mpm@selenic.com>
parents:
8263
diff
changeset
|
135 if include: |
10042
7cdd2a7db2c2
config: raise ConfigError on non-existing include files
Martin Geisler <mg@lazybytes.net>
parents:
9471
diff
changeset
|
136 try: |
7cdd2a7db2c2
config: raise ConfigError on non-existing include files
Martin Geisler <mg@lazybytes.net>
parents:
9471
diff
changeset
|
137 include(inc, remap=remap, sections=sections) |
7cdd2a7db2c2
config: raise ConfigError on non-existing include files
Martin Geisler <mg@lazybytes.net>
parents:
9471
diff
changeset
|
138 except IOError, inst: |
14486
4e3eda05189b
config: ignore include errors for nonexistent files
Matt Mackall <mpm@selenic.com>
parents:
13664
diff
changeset
|
139 if inst.errno != errno.ENOENT: |
4e3eda05189b
config: ignore include errors for nonexistent files
Matt Mackall <mpm@selenic.com>
parents:
13664
diff
changeset
|
140 raise error.ParseError(_("cannot include %s (%s)") |
4e3eda05189b
config: ignore include errors for nonexistent files
Matt Mackall <mpm@selenic.com>
parents:
13664
diff
changeset
|
141 % (inc, inst.strerror), |
4e3eda05189b
config: ignore include errors for nonexistent files
Matt Mackall <mpm@selenic.com>
parents:
13664
diff
changeset
|
142 "%s:%s" % (src, line)) |
8183
2858ab754995
config: allow including other config files
Matt Mackall <mpm@selenic.com>
parents:
8180
diff
changeset
|
143 continue |
8144 | 144 if emptyre.match(l): |
145 continue | |
146 m = sectionre.match(l) | |
147 if m: | |
148 section = m.group(1) | |
8298
9542f4c3fa1b
config: make remap actually work
Matt Mackall <mpm@selenic.com>
parents:
8265
diff
changeset
|
149 if remap: |
9542f4c3fa1b
config: make remap actually work
Matt Mackall <mpm@selenic.com>
parents:
8265
diff
changeset
|
150 section = remap.get(section, section) |
8144 | 151 if section not in self: |
152 self._data[section] = sortdict() | |
153 continue | |
154 m = itemre.match(l) | |
155 if m: | |
156 item = m.group(1) | |
9339
9be91129c96e
config: improve code readability
Andrey <py4fun@gmail.com>
parents:
9136
diff
changeset
|
157 cont = True |
8193
94246e90081e
config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents:
8192
diff
changeset
|
158 if sections and section not in sections: |
94246e90081e
config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents:
8192
diff
changeset
|
159 continue |
8265
52c5be55af82
config: add parse interface
Matt Mackall <mpm@selenic.com>
parents:
8263
diff
changeset
|
160 self.set(section, item, m.group(2), "%s:%d" % (src, line)) |
8144 | 161 continue |
8184
9189afe1eba3
config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents:
8183
diff
changeset
|
162 m = unsetre.match(l) |
9189afe1eba3
config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents:
8183
diff
changeset
|
163 if m: |
9189afe1eba3
config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents:
8183
diff
changeset
|
164 name = m.group(1) |
8193
94246e90081e
config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents:
8192
diff
changeset
|
165 if sections and section not in sections: |
94246e90081e
config: add section filter to read
Matt Mackall <mpm@selenic.com>
parents:
8192
diff
changeset
|
166 continue |
13031
3da456d0c885
code style: prefer 'is' and 'is not' tests with singletons
Martin Geisler <mg@aragost.com>
parents:
11292
diff
changeset
|
167 if self.get(section, name) is not None: |
8184
9189afe1eba3
config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents:
8183
diff
changeset
|
168 del self._data[section][name] |
9189afe1eba3
config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents:
8183
diff
changeset
|
169 continue |
9189afe1eba3
config: add %unset name support
Matt Mackall <mpm@selenic.com>
parents:
8183
diff
changeset
|
170 |
11288
2123aad24d56
error: add new ParseError for various parsing errors
Matt Mackall <mpm@selenic.com>
parents:
11224
diff
changeset
|
171 raise error.ParseError(l.rstrip(), ("%s:%s" % (src, line))) |
8265
52c5be55af82
config: add parse interface
Matt Mackall <mpm@selenic.com>
parents:
8263
diff
changeset
|
172 |
52c5be55af82
config: add parse interface
Matt Mackall <mpm@selenic.com>
parents:
8263
diff
changeset
|
173 def read(self, path, fp=None, sections=None, remap=None): |
52c5be55af82
config: add parse interface
Matt Mackall <mpm@selenic.com>
parents:
8263
diff
changeset
|
174 if not fp: |
13664
53db4e2026ab
config: use util.posixfile
Adrian Buehlmann <adrian@cadifra.com>
parents:
13031
diff
changeset
|
175 fp = util.posixfile(path) |
8265
52c5be55af82
config: add parse interface
Matt Mackall <mpm@selenic.com>
parents:
8263
diff
changeset
|
176 self.parse(path, fp.read(), sections, remap, self.read) |