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