##// END OF EJS Templates
config: read configs from directories in lexicographical order...
Martin von Zweigbergk -
r42647:edbcf5b2 default
parent child Browse files
Show More
@@ -1,98 +1,99 b''
1 # rcutil.py - utilities about config paths, special config sections etc.
1 # rcutil.py - utilities about config paths, special config sections etc.
2 #
2 #
3 # Copyright Mercurial Contributors
3 # Copyright Mercurial Contributors
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 import os
11
11
12 from . import (
12 from . import (
13 encoding,
13 encoding,
14 pycompat,
14 pycompat,
15 util,
15 util,
16 )
16 )
17
17
18 if pycompat.iswindows:
18 if pycompat.iswindows:
19 from . import scmwindows as scmplatform
19 from . import scmwindows as scmplatform
20 else:
20 else:
21 from . import scmposix as scmplatform
21 from . import scmposix as scmplatform
22
22
23 fallbackpager = scmplatform.fallbackpager
23 fallbackpager = scmplatform.fallbackpager
24 systemrcpath = scmplatform.systemrcpath
24 systemrcpath = scmplatform.systemrcpath
25 userrcpath = scmplatform.userrcpath
25 userrcpath = scmplatform.userrcpath
26
26
27 def _expandrcpath(path):
27 def _expandrcpath(path):
28 '''path could be a file or a directory. return a list of file paths'''
28 '''path could be a file or a directory. return a list of file paths'''
29 p = util.expandpath(path)
29 p = util.expandpath(path)
30 if os.path.isdir(p):
30 if os.path.isdir(p):
31 join = os.path.join
31 join = os.path.join
32 return [join(p, f) for f, k in util.listdir(p) if f.endswith('.rc')]
32 return sorted(join(p, f) for f, k in util.listdir(p)
33 if f.endswith('.rc'))
33 return [p]
34 return [p]
34
35
35 def envrcitems(env=None):
36 def envrcitems(env=None):
36 '''Return [(section, name, value, source)] config items.
37 '''Return [(section, name, value, source)] config items.
37
38
38 The config items are extracted from environment variables specified by env,
39 The config items are extracted from environment variables specified by env,
39 used to override systemrc, but not userrc.
40 used to override systemrc, but not userrc.
40
41
41 If env is not provided, encoding.environ will be used.
42 If env is not provided, encoding.environ will be used.
42 '''
43 '''
43 if env is None:
44 if env is None:
44 env = encoding.environ
45 env = encoding.environ
45 checklist = [
46 checklist = [
46 ('EDITOR', 'ui', 'editor'),
47 ('EDITOR', 'ui', 'editor'),
47 ('VISUAL', 'ui', 'editor'),
48 ('VISUAL', 'ui', 'editor'),
48 ('PAGER', 'pager', 'pager'),
49 ('PAGER', 'pager', 'pager'),
49 ]
50 ]
50 result = []
51 result = []
51 for envname, section, configname in checklist:
52 for envname, section, configname in checklist:
52 if envname not in env:
53 if envname not in env:
53 continue
54 continue
54 result.append((section, configname, env[envname], '$%s' % envname))
55 result.append((section, configname, env[envname], '$%s' % envname))
55 return result
56 return result
56
57
57 def defaultrcpath():
58 def defaultrcpath():
58 '''return rc paths in default.d'''
59 '''return rc paths in default.d'''
59 path = []
60 path = []
60 defaultpath = os.path.join(util.datapath, 'default.d')
61 defaultpath = os.path.join(util.datapath, 'default.d')
61 if os.path.isdir(defaultpath):
62 if os.path.isdir(defaultpath):
62 path = _expandrcpath(defaultpath)
63 path = _expandrcpath(defaultpath)
63 return path
64 return path
64
65
65 def rccomponents():
66 def rccomponents():
66 '''return an ordered [(type, obj)] about where to load configs.
67 '''return an ordered [(type, obj)] about where to load configs.
67
68
68 respect $HGRCPATH. if $HGRCPATH is empty, only .hg/hgrc of current repo is
69 respect $HGRCPATH. if $HGRCPATH is empty, only .hg/hgrc of current repo is
69 used. if $HGRCPATH is not set, the platform default will be used.
70 used. if $HGRCPATH is not set, the platform default will be used.
70
71
71 if a directory is provided, *.rc files under it will be used.
72 if a directory is provided, *.rc files under it will be used.
72
73
73 type could be either 'path' or 'items', if type is 'path', obj is a string,
74 type could be either 'path' or 'items', if type is 'path', obj is a string,
74 and is the config file path. if type is 'items', obj is a list of (section,
75 and is the config file path. if type is 'items', obj is a list of (section,
75 name, value, source) that should fill the config directly.
76 name, value, source) that should fill the config directly.
76 '''
77 '''
77 envrc = ('items', envrcitems())
78 envrc = ('items', envrcitems())
78
79
79 if 'HGRCPATH' in encoding.environ:
80 if 'HGRCPATH' in encoding.environ:
80 # assume HGRCPATH is all about user configs so environments can be
81 # assume HGRCPATH is all about user configs so environments can be
81 # overridden.
82 # overridden.
82 _rccomponents = [envrc]
83 _rccomponents = [envrc]
83 for p in encoding.environ['HGRCPATH'].split(pycompat.ospathsep):
84 for p in encoding.environ['HGRCPATH'].split(pycompat.ospathsep):
84 if not p:
85 if not p:
85 continue
86 continue
86 _rccomponents.extend(('path', p) for p in _expandrcpath(p))
87 _rccomponents.extend(('path', p) for p in _expandrcpath(p))
87 else:
88 else:
88 normpaths = lambda paths: [('path', os.path.normpath(p)) for p in paths]
89 normpaths = lambda paths: [('path', os.path.normpath(p)) for p in paths]
89 _rccomponents = normpaths(defaultrcpath() + systemrcpath())
90 _rccomponents = normpaths(defaultrcpath() + systemrcpath())
90 _rccomponents.append(envrc)
91 _rccomponents.append(envrc)
91 _rccomponents.extend(normpaths(userrcpath()))
92 _rccomponents.extend(normpaths(userrcpath()))
92 return _rccomponents
93 return _rccomponents
93
94
94 def defaultpagerenv():
95 def defaultpagerenv():
95 '''return a dict of default environment variables and their values,
96 '''return a dict of default environment variables and their values,
96 intended to be set before starting a pager.
97 intended to be set before starting a pager.
97 '''
98 '''
98 return {'LESS': 'FRX', 'LV': '-c'}
99 return {'LESS': 'FRX', 'LV': '-c'}
@@ -1,213 +1,222 b''
1 hide outer repo
1 hide outer repo
2 $ hg init
2 $ hg init
3
3
4 Invalid syntax: no value
4 Invalid syntax: no value
5
5
6 $ cat > .hg/hgrc << EOF
6 $ cat > .hg/hgrc << EOF
7 > novaluekey
7 > novaluekey
8 > EOF
8 > EOF
9 $ hg showconfig
9 $ hg showconfig
10 hg: parse error at $TESTTMP/.hg/hgrc:1: novaluekey
10 hg: parse error at $TESTTMP/.hg/hgrc:1: novaluekey
11 [255]
11 [255]
12
12
13 Invalid syntax: no key
13 Invalid syntax: no key
14
14
15 $ cat > .hg/hgrc << EOF
15 $ cat > .hg/hgrc << EOF
16 > =nokeyvalue
16 > =nokeyvalue
17 > EOF
17 > EOF
18 $ hg showconfig
18 $ hg showconfig
19 hg: parse error at $TESTTMP/.hg/hgrc:1: =nokeyvalue
19 hg: parse error at $TESTTMP/.hg/hgrc:1: =nokeyvalue
20 [255]
20 [255]
21
21
22 Test hint about invalid syntax from leading white space
22 Test hint about invalid syntax from leading white space
23
23
24 $ cat > .hg/hgrc << EOF
24 $ cat > .hg/hgrc << EOF
25 > key=value
25 > key=value
26 > EOF
26 > EOF
27 $ hg showconfig
27 $ hg showconfig
28 hg: parse error at $TESTTMP/.hg/hgrc:1: key=value
28 hg: parse error at $TESTTMP/.hg/hgrc:1: key=value
29 unexpected leading whitespace
29 unexpected leading whitespace
30 [255]
30 [255]
31
31
32 $ cat > .hg/hgrc << EOF
32 $ cat > .hg/hgrc << EOF
33 > [section]
33 > [section]
34 > key=value
34 > key=value
35 > EOF
35 > EOF
36 $ hg showconfig
36 $ hg showconfig
37 hg: parse error at $TESTTMP/.hg/hgrc:1: [section]
37 hg: parse error at $TESTTMP/.hg/hgrc:1: [section]
38 unexpected leading whitespace
38 unexpected leading whitespace
39 [255]
39 [255]
40
40
41 Reset hgrc
41 Reset hgrc
42
42
43 $ echo > .hg/hgrc
43 $ echo > .hg/hgrc
44
44
45 Test case sensitive configuration
45 Test case sensitive configuration
46
46
47 $ cat <<EOF >> $HGRCPATH
47 $ cat <<EOF >> $HGRCPATH
48 > [Section]
48 > [Section]
49 > KeY = Case Sensitive
49 > KeY = Case Sensitive
50 > key = lower case
50 > key = lower case
51 > EOF
51 > EOF
52
52
53 $ hg showconfig Section
53 $ hg showconfig Section
54 Section.KeY=Case Sensitive
54 Section.KeY=Case Sensitive
55 Section.key=lower case
55 Section.key=lower case
56
56
57 $ hg showconfig Section -Tjson
57 $ hg showconfig Section -Tjson
58 [
58 [
59 {
59 {
60 "name": "Section.KeY",
60 "name": "Section.KeY",
61 "source": "*.hgrc:*", (glob)
61 "source": "*.hgrc:*", (glob)
62 "value": "Case Sensitive"
62 "value": "Case Sensitive"
63 },
63 },
64 {
64 {
65 "name": "Section.key",
65 "name": "Section.key",
66 "source": "*.hgrc:*", (glob)
66 "source": "*.hgrc:*", (glob)
67 "value": "lower case"
67 "value": "lower case"
68 }
68 }
69 ]
69 ]
70 $ hg showconfig Section.KeY -Tjson
70 $ hg showconfig Section.KeY -Tjson
71 [
71 [
72 {
72 {
73 "name": "Section.KeY",
73 "name": "Section.KeY",
74 "source": "*.hgrc:*", (glob)
74 "source": "*.hgrc:*", (glob)
75 "value": "Case Sensitive"
75 "value": "Case Sensitive"
76 }
76 }
77 ]
77 ]
78 $ hg showconfig -Tjson | tail -7
78 $ hg showconfig -Tjson | tail -7
79 },
79 },
80 {
80 {
81 "name": "*", (glob)
81 "name": "*", (glob)
82 "source": "*", (glob)
82 "source": "*", (glob)
83 "value": "*" (glob)
83 "value": "*" (glob)
84 }
84 }
85 ]
85 ]
86
86
87 Test empty config source:
87 Test empty config source:
88
88
89 $ cat <<EOF > emptysource.py
89 $ cat <<EOF > emptysource.py
90 > def reposetup(ui, repo):
90 > def reposetup(ui, repo):
91 > ui.setconfig(b'empty', b'source', b'value')
91 > ui.setconfig(b'empty', b'source', b'value')
92 > EOF
92 > EOF
93 $ cp .hg/hgrc .hg/hgrc.orig
93 $ cp .hg/hgrc .hg/hgrc.orig
94 $ cat <<EOF >> .hg/hgrc
94 $ cat <<EOF >> .hg/hgrc
95 > [extensions]
95 > [extensions]
96 > emptysource = `pwd`/emptysource.py
96 > emptysource = `pwd`/emptysource.py
97 > EOF
97 > EOF
98
98
99 $ hg config --debug empty.source
99 $ hg config --debug empty.source
100 read config from: * (glob)
100 read config from: * (glob)
101 none: value
101 none: value
102 $ hg config empty.source -Tjson
102 $ hg config empty.source -Tjson
103 [
103 [
104 {
104 {
105 "name": "empty.source",
105 "name": "empty.source",
106 "source": "",
106 "source": "",
107 "value": "value"
107 "value": "value"
108 }
108 }
109 ]
109 ]
110
110
111 $ cp .hg/hgrc.orig .hg/hgrc
111 $ cp .hg/hgrc.orig .hg/hgrc
112
112
113 Test "%unset"
113 Test "%unset"
114
114
115 $ cat >> $HGRCPATH <<EOF
115 $ cat >> $HGRCPATH <<EOF
116 > [unsettest]
116 > [unsettest]
117 > local-hgrcpath = should be unset (HGRCPATH)
117 > local-hgrcpath = should be unset (HGRCPATH)
118 > %unset local-hgrcpath
118 > %unset local-hgrcpath
119 >
119 >
120 > global = should be unset (HGRCPATH)
120 > global = should be unset (HGRCPATH)
121 >
121 >
122 > both = should be unset (HGRCPATH)
122 > both = should be unset (HGRCPATH)
123 >
123 >
124 > set-after-unset = should be unset (HGRCPATH)
124 > set-after-unset = should be unset (HGRCPATH)
125 > EOF
125 > EOF
126
126
127 $ cat >> .hg/hgrc <<EOF
127 $ cat >> .hg/hgrc <<EOF
128 > [unsettest]
128 > [unsettest]
129 > local-hgrc = should be unset (.hg/hgrc)
129 > local-hgrc = should be unset (.hg/hgrc)
130 > %unset local-hgrc
130 > %unset local-hgrc
131 >
131 >
132 > %unset global
132 > %unset global
133 >
133 >
134 > both = should be unset (.hg/hgrc)
134 > both = should be unset (.hg/hgrc)
135 > %unset both
135 > %unset both
136 >
136 >
137 > set-after-unset = should be unset (.hg/hgrc)
137 > set-after-unset = should be unset (.hg/hgrc)
138 > %unset set-after-unset
138 > %unset set-after-unset
139 > set-after-unset = should be set (.hg/hgrc)
139 > set-after-unset = should be set (.hg/hgrc)
140 > EOF
140 > EOF
141
141
142 $ hg showconfig unsettest
142 $ hg showconfig unsettest
143 unsettest.set-after-unset=should be set (.hg/hgrc)
143 unsettest.set-after-unset=should be set (.hg/hgrc)
144
144
145 Test exit code when no config matches
145 Test exit code when no config matches
146
146
147 $ hg config Section.idontexist
147 $ hg config Section.idontexist
148 [1]
148 [1]
149
149
150 sub-options in [paths] aren't expanded
150 sub-options in [paths] aren't expanded
151
151
152 $ cat > .hg/hgrc << EOF
152 $ cat > .hg/hgrc << EOF
153 > [paths]
153 > [paths]
154 > foo = ~/foo
154 > foo = ~/foo
155 > foo:suboption = ~/foo
155 > foo:suboption = ~/foo
156 > EOF
156 > EOF
157
157
158 $ hg showconfig paths
158 $ hg showconfig paths
159 paths.foo:suboption=~/foo
159 paths.foo:suboption=~/foo
160 paths.foo=$TESTTMP/foo
160 paths.foo=$TESTTMP/foo
161
161
162 edit failure
162 edit failure
163
163
164 $ HGEDITOR=false hg config --edit
164 $ HGEDITOR=false hg config --edit
165 abort: edit failed: false exited with status 1
165 abort: edit failed: false exited with status 1
166 [255]
166 [255]
167
167
168 config affected by environment variables
168 config affected by environment variables
169
169
170 $ EDITOR=e1 VISUAL=e2 hg config --debug | grep 'ui\.editor'
170 $ EDITOR=e1 VISUAL=e2 hg config --debug | grep 'ui\.editor'
171 $VISUAL: ui.editor=e2
171 $VISUAL: ui.editor=e2
172
172
173 $ VISUAL=e2 hg config --debug --config ui.editor=e3 | grep 'ui\.editor'
173 $ VISUAL=e2 hg config --debug --config ui.editor=e3 | grep 'ui\.editor'
174 --config: ui.editor=e3
174 --config: ui.editor=e3
175
175
176 $ PAGER=p1 hg config --debug | grep 'pager\.pager'
176 $ PAGER=p1 hg config --debug | grep 'pager\.pager'
177 $PAGER: pager.pager=p1
177 $PAGER: pager.pager=p1
178
178
179 $ PAGER=p1 hg config --debug --config pager.pager=p2 | grep 'pager\.pager'
179 $ PAGER=p1 hg config --debug --config pager.pager=p2 | grep 'pager\.pager'
180 --config: pager.pager=p2
180 --config: pager.pager=p2
181
181
182 verify that aliases are evaluated as well
182 verify that aliases are evaluated as well
183
183
184 $ hg init aliastest
184 $ hg init aliastest
185 $ cd aliastest
185 $ cd aliastest
186 $ cat > .hg/hgrc << EOF
186 $ cat > .hg/hgrc << EOF
187 > [ui]
187 > [ui]
188 > user = repo user
188 > user = repo user
189 > EOF
189 > EOF
190 $ touch index
190 $ touch index
191 $ unset HGUSER
191 $ unset HGUSER
192 $ hg ci -Am test
192 $ hg ci -Am test
193 adding index
193 adding index
194 $ hg log --template '{author}\n'
194 $ hg log --template '{author}\n'
195 repo user
195 repo user
196 $ cd ..
196 $ cd ..
197
197
198 alias has lower priority
198 alias has lower priority
199
199
200 $ hg init aliaspriority
200 $ hg init aliaspriority
201 $ cd aliaspriority
201 $ cd aliaspriority
202 $ cat > .hg/hgrc << EOF
202 $ cat > .hg/hgrc << EOF
203 > [ui]
203 > [ui]
204 > user = alias user
204 > user = alias user
205 > username = repo user
205 > username = repo user
206 > EOF
206 > EOF
207 $ touch index
207 $ touch index
208 $ unset HGUSER
208 $ unset HGUSER
209 $ hg ci -Am test
209 $ hg ci -Am test
210 adding index
210 adding index
211 $ hg log --template '{author}\n'
211 $ hg log --template '{author}\n'
212 repo user
212 repo user
213 $ cd ..
213 $ cd ..
214
215 configs should be read in lexicographical order
216
217 $ mkdir configs
218 $ for i in `$TESTDIR/seq.py 10 99`; do
219 > printf "[section]\nkey=$i" > configs/$i.rc
220 > done
221 $ HGRCPATH=configs hg config section.key
222 99
General Comments 0
You need to be logged in to leave comments. Login now