Show More
@@ -0,0 +1,36 | |||||
|
1 | # configuration related constants | |||
|
2 | ||||
|
3 | from __future__ import annotations | |||
|
4 | ||||
|
5 | from typing import ( | |||
|
6 | List, | |||
|
7 | Tuple, | |||
|
8 | Union, | |||
|
9 | ) | |||
|
10 | ||||
|
11 | # keep typing simple for now | |||
|
12 | ConfigLevelT = str | |||
|
13 | LEVEL_USER = 'user' # "user" is the default level and never passed explicitly | |||
|
14 | LEVEL_LOCAL = 'local' | |||
|
15 | LEVEL_GLOBAL = 'global' | |||
|
16 | LEVEL_SHARED = 'shared' | |||
|
17 | LEVEL_NON_SHARED = 'non_shared' | |||
|
18 | EDIT_LEVELS = ( | |||
|
19 | LEVEL_USER, | |||
|
20 | LEVEL_LOCAL, | |||
|
21 | LEVEL_GLOBAL, | |||
|
22 | LEVEL_SHARED, | |||
|
23 | LEVEL_NON_SHARED, | |||
|
24 | ) | |||
|
25 | ||||
|
26 | ConfigItemT = Tuple[bytes, bytes, bytes, bytes] | |||
|
27 | ResourceIDT = Tuple[bytes, bytes] | |||
|
28 | FileRCT = bytes | |||
|
29 | ComponentT = Tuple[ | |||
|
30 | bytes, | |||
|
31 | Union[ | |||
|
32 | List[ConfigItemT], | |||
|
33 | FileRCT, | |||
|
34 | ResourceIDT, | |||
|
35 | ], | |||
|
36 | ] |
@@ -1,201 +1,196 | |||||
1 | # Gather code related to command dealing with configuration. |
|
1 | # Gather code related to command dealing with configuration. | |
2 |
|
2 | |||
3 | from __future__ import annotations |
|
3 | from __future__ import annotations | |
4 |
|
4 | |||
5 | import os |
|
5 | import os | |
6 |
|
6 | |||
7 | from typing import Any, Collection, Dict, Optional |
|
7 | from typing import Any, Collection, Dict, Optional | |
8 |
|
8 | |||
9 | from ..i18n import _ |
|
9 | from ..i18n import _ | |
10 |
|
10 | |||
11 | from .. import ( |
|
11 | from .. import ( | |
12 | cmdutil, |
|
12 | cmdutil, | |
13 | error, |
|
13 | error, | |
14 | formatter, |
|
14 | formatter, | |
15 | pycompat, |
|
15 | pycompat, | |
16 | requirements, |
|
16 | requirements, | |
17 | ui as uimod, |
|
17 | ui as uimod, | |
18 | util, |
|
18 | util, | |
19 | vfs as vfsmod, |
|
19 | vfs as vfsmod, | |
20 | ) |
|
20 | ) | |
21 |
|
21 | |||
22 |
from . import |
|
22 | from . import ( | |
|
23 | ConfigLevelT, | |||
|
24 | EDIT_LEVELS, | |||
|
25 | LEVEL_GLOBAL, | |||
|
26 | LEVEL_LOCAL, | |||
|
27 | LEVEL_NON_SHARED, | |||
|
28 | LEVEL_SHARED, | |||
|
29 | LEVEL_USER, | |||
|
30 | rcutil, | |||
|
31 | ) | |||
23 |
|
32 | |||
24 | EDIT_FLAG = 'edit' |
|
33 | EDIT_FLAG = 'edit' | |
25 |
|
34 | |||
26 |
|
35 | |||
27 | # keep typing simple for now |
|
|||
28 | ConfigLevelT = str |
|
|||
29 | LEVEL_USER = 'user' # "user" is the default level and never passed explicitly |
|
|||
30 | LEVEL_LOCAL = 'local' |
|
|||
31 | LEVEL_GLOBAL = 'global' |
|
|||
32 | LEVEL_SHARED = 'shared' |
|
|||
33 | LEVEL_NON_SHARED = 'non_shared' |
|
|||
34 | EDIT_LEVELS = ( |
|
|||
35 | LEVEL_USER, |
|
|||
36 | LEVEL_LOCAL, |
|
|||
37 | LEVEL_GLOBAL, |
|
|||
38 | LEVEL_SHARED, |
|
|||
39 | LEVEL_NON_SHARED, |
|
|||
40 | ) |
|
|||
41 |
|
||||
42 |
|
||||
43 | def find_edit_level( |
|
36 | def find_edit_level( | |
44 | ui: uimod.ui, repo, opts: Dict[str, Any] |
|
37 | ui: uimod.ui, | |
|
38 | repo, | |||
|
39 | opts: Dict[str, Any], | |||
45 | ) -> Optional[ConfigLevelT]: |
|
40 | ) -> Optional[ConfigLevelT]: | |
46 | """return the level we should edit, if any. |
|
41 | """return the level we should edit, if any. | |
47 |
|
42 | |||
48 | Parse the command option to detect when an edit is requested, and if so the |
|
43 | Parse the command option to detect when an edit is requested, and if so the | |
49 | configuration level we should edit. |
|
44 | configuration level we should edit. | |
50 | """ |
|
45 | """ | |
51 | if opts.get(EDIT_FLAG) or any(opts.get(o) for o in EDIT_LEVELS): |
|
46 | if opts.get(EDIT_FLAG) or any(opts.get(o) for o in EDIT_LEVELS): | |
52 | cmdutil.check_at_most_one_arg(opts, *EDIT_LEVELS) |
|
47 | cmdutil.check_at_most_one_arg(opts, *EDIT_LEVELS) | |
53 | for level in EDIT_LEVELS: |
|
48 | for level in EDIT_LEVELS: | |
54 | if opts.get(level): |
|
49 | if opts.get(level): | |
55 | return level |
|
50 | return level | |
56 | return EDIT_LEVELS[0] |
|
51 | return EDIT_LEVELS[0] | |
57 | return None |
|
52 | return None | |
58 |
|
53 | |||
59 |
|
54 | |||
60 | def edit_config(ui: uimod.ui, repo, level: ConfigLevelT) -> None: |
|
55 | def edit_config(ui: uimod.ui, repo, level: ConfigLevelT) -> None: | |
61 | """let the user edit configuration file for the given level""" |
|
56 | """let the user edit configuration file for the given level""" | |
62 |
|
57 | |||
63 | if level == LEVEL_USER: |
|
58 | if level == LEVEL_USER: | |
64 | paths = rcutil.userrcpath() |
|
59 | paths = rcutil.userrcpath() | |
65 | elif level == LEVEL_GLOBAL: |
|
60 | elif level == LEVEL_GLOBAL: | |
66 | paths = rcutil.systemrcpath() |
|
61 | paths = rcutil.systemrcpath() | |
67 | elif level == LEVEL_LOCAL: |
|
62 | elif level == LEVEL_LOCAL: | |
68 | if not repo: |
|
63 | if not repo: | |
69 | raise error.InputError(_(b"can't use --local outside a repository")) |
|
64 | raise error.InputError(_(b"can't use --local outside a repository")) | |
70 | paths = [repo.vfs.join(b'hgrc')] |
|
65 | paths = [repo.vfs.join(b'hgrc')] | |
71 | elif level == LEVEL_NON_SHARED: |
|
66 | elif level == LEVEL_NON_SHARED: | |
72 | paths = [repo.vfs.join(b'hgrc-not-shared')] |
|
67 | paths = [repo.vfs.join(b'hgrc-not-shared')] | |
73 | elif level == LEVEL_SHARED: |
|
68 | elif level == LEVEL_SHARED: | |
74 | if not repo.shared(): |
|
69 | if not repo.shared(): | |
75 | raise error.InputError( |
|
70 | raise error.InputError( | |
76 | _(b"repository is not shared; can't use --shared") |
|
71 | _(b"repository is not shared; can't use --shared") | |
77 | ) |
|
72 | ) | |
78 | if requirements.SHARESAFE_REQUIREMENT not in repo.requirements: |
|
73 | if requirements.SHARESAFE_REQUIREMENT not in repo.requirements: | |
79 | raise error.InputError( |
|
74 | raise error.InputError( | |
80 | _( |
|
75 | _( | |
81 | b"share safe feature not enabled; " |
|
76 | b"share safe feature not enabled; " | |
82 | b"unable to edit shared source repository config" |
|
77 | b"unable to edit shared source repository config" | |
83 | ) |
|
78 | ) | |
84 | ) |
|
79 | ) | |
85 | paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')] |
|
80 | paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')] | |
86 | else: |
|
81 | else: | |
87 | msg = 'unknown config level: %s' % level |
|
82 | msg = 'unknown config level: %s' % level | |
88 | raise error.ProgrammingError(msg) |
|
83 | raise error.ProgrammingError(msg) | |
89 |
|
84 | |||
90 | for f in paths: |
|
85 | for f in paths: | |
91 | if os.path.exists(f): |
|
86 | if os.path.exists(f): | |
92 | break |
|
87 | break | |
93 | else: |
|
88 | else: | |
94 | if LEVEL_GLOBAL: |
|
89 | if LEVEL_GLOBAL: | |
95 | samplehgrc = uimod.samplehgrcs[b'global'] |
|
90 | samplehgrc = uimod.samplehgrcs[b'global'] | |
96 | elif LEVEL_LOCAL: |
|
91 | elif LEVEL_LOCAL: | |
97 | samplehgrc = uimod.samplehgrcs[b'local'] |
|
92 | samplehgrc = uimod.samplehgrcs[b'local'] | |
98 | else: |
|
93 | else: | |
99 | samplehgrc = uimod.samplehgrcs[b'user'] |
|
94 | samplehgrc = uimod.samplehgrcs[b'user'] | |
100 |
|
95 | |||
101 | f = paths[0] |
|
96 | f = paths[0] | |
102 | util.writefile(f, util.tonativeeol(samplehgrc)) |
|
97 | util.writefile(f, util.tonativeeol(samplehgrc)) | |
103 |
|
98 | |||
104 | editor = ui.geteditor() |
|
99 | editor = ui.geteditor() | |
105 | ui.system( |
|
100 | ui.system( | |
106 | b"%s \"%s\"" % (editor, f), |
|
101 | b"%s \"%s\"" % (editor, f), | |
107 | onerr=error.InputError, |
|
102 | onerr=error.InputError, | |
108 | errprefix=_(b"edit failed"), |
|
103 | errprefix=_(b"edit failed"), | |
109 | blockedtag=b'config_edit', |
|
104 | blockedtag=b'config_edit', | |
110 | ) |
|
105 | ) | |
111 |
|
106 | |||
112 |
|
107 | |||
113 | def show_component(ui: uimod.ui, repo) -> None: |
|
108 | def show_component(ui: uimod.ui, repo) -> None: | |
114 | """show the component used to build the config |
|
109 | """show the component used to build the config | |
115 |
|
110 | |||
116 | XXX this skip over various source and ignore the repository config, so it |
|
111 | XXX this skip over various source and ignore the repository config, so it | |
117 | XXX is probably useless old code. |
|
112 | XXX is probably useless old code. | |
118 | """ |
|
113 | """ | |
119 | for t, f in rcutil.rccomponents(): |
|
114 | for t, f in rcutil.rccomponents(): | |
120 | if t == b'path': |
|
115 | if t == b'path': | |
121 | ui.debug(b'read config from: %s\n' % f) |
|
116 | ui.debug(b'read config from: %s\n' % f) | |
122 | elif t == b'resource': |
|
117 | elif t == b'resource': | |
123 | ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1])) |
|
118 | ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1])) | |
124 | elif t == b'items': |
|
119 | elif t == b'items': | |
125 | # Don't print anything for 'items'. |
|
120 | # Don't print anything for 'items'. | |
126 | pass |
|
121 | pass | |
127 | else: |
|
122 | else: | |
128 | raise error.ProgrammingError(b'unknown rctype: %s' % t) |
|
123 | raise error.ProgrammingError(b'unknown rctype: %s' % t) | |
129 |
|
124 | |||
130 |
|
125 | |||
131 | def show_config( |
|
126 | def show_config( | |
132 | ui: uimod.ui, |
|
127 | ui: uimod.ui, | |
133 | repo, |
|
128 | repo, | |
134 | value_filters: Collection[bytes], |
|
129 | value_filters: Collection[bytes], | |
135 | formatter_options: dict, |
|
130 | formatter_options: dict, | |
136 | untrusted: bool = False, |
|
131 | untrusted: bool = False, | |
137 | all_known: bool = False, |
|
132 | all_known: bool = False, | |
138 | show_source: bool = False, |
|
133 | show_source: bool = False, | |
139 | ) -> bool: |
|
134 | ) -> bool: | |
140 | """Display config value to the user |
|
135 | """Display config value to the user | |
141 |
|
136 | |||
142 | The display is done using a dedicated `formatter` object. |
|
137 | The display is done using a dedicated `formatter` object. | |
143 |
|
138 | |||
144 |
|
139 | |||
145 | :value_filters: |
|
140 | :value_filters: | |
146 | if non-empty filter the display value according to these filters. If |
|
141 | if non-empty filter the display value according to these filters. If | |
147 | the filter does not match any value, the function return False. True |
|
142 | the filter does not match any value, the function return False. True | |
148 | otherwise. |
|
143 | otherwise. | |
149 |
|
144 | |||
150 | :formatter_option: |
|
145 | :formatter_option: | |
151 | options passed to the formatter |
|
146 | options passed to the formatter | |
152 |
|
147 | |||
153 | :untrusted: |
|
148 | :untrusted: | |
154 | When set, use untrusted value instead of ignoring them |
|
149 | When set, use untrusted value instead of ignoring them | |
155 |
|
150 | |||
156 | :all_known: |
|
151 | :all_known: | |
157 | Display all known config item, not just the one with an explicit value. |
|
152 | Display all known config item, not just the one with an explicit value. | |
158 |
|
153 | |||
159 | :show_source: |
|
154 | :show_source: | |
160 | Show where each value has been defined. |
|
155 | Show where each value has been defined. | |
161 | """ |
|
156 | """ | |
162 | fm = ui.formatter(b'config', formatter_options) |
|
157 | fm = ui.formatter(b'config', formatter_options) | |
163 | selsections = selentries = [] |
|
158 | selsections = selentries = [] | |
164 | filtered = False |
|
159 | filtered = False | |
165 | if value_filters: |
|
160 | if value_filters: | |
166 | selsections = [v for v in value_filters if b'.' not in v] |
|
161 | selsections = [v for v in value_filters if b'.' not in v] | |
167 | selentries = [v for v in value_filters if b'.' in v] |
|
162 | selentries = [v for v in value_filters if b'.' in v] | |
168 | filtered = True |
|
163 | filtered = True | |
169 | uniquesel = len(selentries) == 1 and not selsections |
|
164 | uniquesel = len(selentries) == 1 and not selsections | |
170 | selsections = set(selsections) |
|
165 | selsections = set(selsections) | |
171 | selentries = set(selentries) |
|
166 | selentries = set(selentries) | |
172 |
|
167 | |||
173 | matched = False |
|
168 | matched = False | |
174 | entries = ui.walkconfig(untrusted=untrusted, all_known=all_known) |
|
169 | entries = ui.walkconfig(untrusted=untrusted, all_known=all_known) | |
175 | for section, name, value in entries: |
|
170 | for section, name, value in entries: | |
176 | source = ui.configsource(section, name, untrusted) |
|
171 | source = ui.configsource(section, name, untrusted) | |
177 | value = pycompat.bytestr(value) |
|
172 | value = pycompat.bytestr(value) | |
178 | defaultvalue = ui.configdefault(section, name) |
|
173 | defaultvalue = ui.configdefault(section, name) | |
179 | if fm.isplain(): |
|
174 | if fm.isplain(): | |
180 | source = source or b'none' |
|
175 | source = source or b'none' | |
181 | value = value.replace(b'\n', b'\\n') |
|
176 | value = value.replace(b'\n', b'\\n') | |
182 | entryname = section + b'.' + name |
|
177 | entryname = section + b'.' + name | |
183 | if filtered and not (section in selsections or entryname in selentries): |
|
178 | if filtered and not (section in selsections or entryname in selentries): | |
184 | continue |
|
179 | continue | |
185 | fm.startitem() |
|
180 | fm.startitem() | |
186 | fm.condwrite(show_source, b'source', b'%s: ', source) |
|
181 | fm.condwrite(show_source, b'source', b'%s: ', source) | |
187 | if uniquesel: |
|
182 | if uniquesel: | |
188 | fm.data(name=entryname) |
|
183 | fm.data(name=entryname) | |
189 | fm.write(b'value', b'%s\n', value) |
|
184 | fm.write(b'value', b'%s\n', value) | |
190 | else: |
|
185 | else: | |
191 | fm.write(b'name value', b'%s=%s\n', entryname, value) |
|
186 | fm.write(b'name value', b'%s=%s\n', entryname, value) | |
192 | if formatter.isprintable(defaultvalue): |
|
187 | if formatter.isprintable(defaultvalue): | |
193 | fm.data(defaultvalue=defaultvalue) |
|
188 | fm.data(defaultvalue=defaultvalue) | |
194 | elif isinstance(defaultvalue, list) and all( |
|
189 | elif isinstance(defaultvalue, list) and all( | |
195 | formatter.isprintable(e) for e in defaultvalue |
|
190 | formatter.isprintable(e) for e in defaultvalue | |
196 | ): |
|
191 | ): | |
197 | fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value')) |
|
192 | fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value')) | |
198 | # TODO: no idea how to process unsupported defaultvalue types |
|
193 | # TODO: no idea how to process unsupported defaultvalue types | |
199 | matched = True |
|
194 | matched = True | |
200 | fm.end() |
|
195 | fm.end() | |
201 | return matched |
|
196 | return matched |
@@ -1,173 +1,165 | |||||
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 annotations |
|
8 | from __future__ import annotations | |
9 |
|
9 | |||
10 | import os |
|
10 | import os | |
11 |
|
11 | |||
12 | from typing import ( |
|
12 | from typing import ( | |
13 | Dict, |
|
13 | Dict, | |
14 | List, |
|
14 | List, | |
15 | Optional, |
|
15 | Optional, | |
16 | Tuple, |
|
|||
17 | Union, |
|
|||
18 | ) |
|
16 | ) | |
19 |
|
17 | |||
20 | from .. import ( |
|
18 | from .. import ( | |
|
19 | configuration as conf_mod, | |||
21 | encoding, |
|
20 | encoding, | |
22 | localrepo, |
|
21 | localrepo, | |
23 | pycompat, |
|
22 | pycompat, | |
24 | requirements as requirementsmod, |
|
23 | requirements as requirementsmod, | |
25 | util, |
|
24 | util, | |
26 | vfs, |
|
25 | vfs, | |
27 | ) |
|
26 | ) | |
28 |
|
27 | |||
29 | from ..utils import resourceutil |
|
28 | from ..utils import resourceutil | |
30 |
|
29 | |||
31 | if pycompat.iswindows: |
|
30 | if pycompat.iswindows: | |
32 | from .. import scmwindows as scmplatform |
|
31 | from .. import scmwindows as scmplatform | |
33 | else: |
|
32 | else: | |
34 | from .. import scmposix as scmplatform |
|
33 | from .. import scmposix as scmplatform | |
35 |
|
34 | |||
36 | fallbackpager = scmplatform.fallbackpager |
|
35 | fallbackpager = scmplatform.fallbackpager | |
37 | systemrcpath = scmplatform.systemrcpath |
|
36 | systemrcpath = scmplatform.systemrcpath | |
38 | userrcpath = scmplatform.userrcpath |
|
37 | userrcpath = scmplatform.userrcpath | |
39 |
|
38 | |||
40 | ConfigItemT = Tuple[bytes, bytes, bytes, bytes] |
|
39 | ComponentT = conf_mod.ComponentT | |
41 | ResourceIDT = Tuple[bytes, bytes] |
|
40 | ConfigItemT = conf_mod.ConfigItemT | |
42 | FileRCT = bytes |
|
41 | FileRCT = conf_mod.FileRCT | |
43 | ComponentT = Tuple[ |
|
42 | ResourceIDT = conf_mod.ResourceIDT | |
44 | bytes, |
|
|||
45 | Union[ |
|
|||
46 | List[ConfigItemT], |
|
|||
47 | FileRCT, |
|
|||
48 | ResourceIDT, |
|
|||
49 | ], |
|
|||
50 | ] |
|
|||
51 |
|
43 | |||
52 |
|
44 | |||
53 | def _expandrcpath(path: bytes) -> List[FileRCT]: |
|
45 | def _expandrcpath(path: bytes) -> List[FileRCT]: | |
54 | '''path could be a file or a directory. return a list of file paths''' |
|
46 | '''path could be a file or a directory. return a list of file paths''' | |
55 | p = util.expandpath(path) |
|
47 | p = util.expandpath(path) | |
56 | if os.path.isdir(p): |
|
48 | if os.path.isdir(p): | |
57 | join = os.path.join |
|
49 | join = os.path.join | |
58 | return sorted( |
|
50 | return sorted( | |
59 | join(p, f) for f, k in util.listdir(p) if f.endswith(b'.rc') |
|
51 | join(p, f) for f, k in util.listdir(p) if f.endswith(b'.rc') | |
60 | ) |
|
52 | ) | |
61 | return [p] |
|
53 | return [p] | |
62 |
|
54 | |||
63 |
|
55 | |||
64 | def envrcitems(env: Optional[Dict[bytes, bytes]] = None) -> List[ConfigItemT]: |
|
56 | def envrcitems(env: Optional[Dict[bytes, bytes]] = None) -> List[ConfigItemT]: | |
65 | """Return [(section, name, value, source)] config items. |
|
57 | """Return [(section, name, value, source)] config items. | |
66 |
|
58 | |||
67 | The config items are extracted from environment variables specified by env, |
|
59 | The config items are extracted from environment variables specified by env, | |
68 | used to override systemrc, but not userrc. |
|
60 | used to override systemrc, but not userrc. | |
69 |
|
61 | |||
70 | If env is not provided, encoding.environ will be used. |
|
62 | If env is not provided, encoding.environ will be used. | |
71 | """ |
|
63 | """ | |
72 | if env is None: |
|
64 | if env is None: | |
73 | env = encoding.environ |
|
65 | env = encoding.environ | |
74 | checklist = [ |
|
66 | checklist = [ | |
75 | (b'EDITOR', b'ui', b'editor'), |
|
67 | (b'EDITOR', b'ui', b'editor'), | |
76 | (b'VISUAL', b'ui', b'editor'), |
|
68 | (b'VISUAL', b'ui', b'editor'), | |
77 | (b'PAGER', b'pager', b'pager'), |
|
69 | (b'PAGER', b'pager', b'pager'), | |
78 | ] |
|
70 | ] | |
79 | result = [] |
|
71 | result = [] | |
80 | for envname, section, configname in checklist: |
|
72 | for envname, section, configname in checklist: | |
81 | if envname not in env: |
|
73 | if envname not in env: | |
82 | continue |
|
74 | continue | |
83 | result.append((section, configname, env[envname], b'$%s' % envname)) |
|
75 | result.append((section, configname, env[envname], b'$%s' % envname)) | |
84 | return result |
|
76 | return result | |
85 |
|
77 | |||
86 |
|
78 | |||
87 | def default_rc_resources() -> List[ResourceIDT]: |
|
79 | def default_rc_resources() -> List[ResourceIDT]: | |
88 | """return rc resource IDs in defaultrc""" |
|
80 | """return rc resource IDs in defaultrc""" | |
89 | rsrcs = resourceutil.contents(b'mercurial.defaultrc') |
|
81 | rsrcs = resourceutil.contents(b'mercurial.defaultrc') | |
90 | return [ |
|
82 | return [ | |
91 | (b'mercurial.defaultrc', r) |
|
83 | (b'mercurial.defaultrc', r) | |
92 | for r in sorted(rsrcs) |
|
84 | for r in sorted(rsrcs) | |
93 | if resourceutil.is_resource(b'mercurial.defaultrc', r) |
|
85 | if resourceutil.is_resource(b'mercurial.defaultrc', r) | |
94 | and r.endswith(b'.rc') |
|
86 | and r.endswith(b'.rc') | |
95 | ] |
|
87 | ] | |
96 |
|
88 | |||
97 |
|
89 | |||
98 | def rccomponents() -> List[ComponentT]: |
|
90 | def rccomponents() -> List[ComponentT]: | |
99 | """return an ordered [(type, obj)] about where to load configs. |
|
91 | """return an ordered [(type, obj)] about where to load configs. | |
100 |
|
92 | |||
101 | respect $HGRCPATH. if $HGRCPATH is empty, only .hg/hgrc of current repo is |
|
93 | respect $HGRCPATH. if $HGRCPATH is empty, only .hg/hgrc of current repo is | |
102 | used. if $HGRCPATH is not set, the platform default will be used. |
|
94 | used. if $HGRCPATH is not set, the platform default will be used. | |
103 |
|
95 | |||
104 | if a directory is provided, *.rc files under it will be used. |
|
96 | if a directory is provided, *.rc files under it will be used. | |
105 |
|
97 | |||
106 | type could be either 'path', 'items' or 'resource'. If type is 'path', |
|
98 | type could be either 'path', 'items' or 'resource'. If type is 'path', | |
107 | obj is a string, and is the config file path. if type is 'items', obj is a |
|
99 | obj is a string, and is the config file path. if type is 'items', obj is a | |
108 | list of (section, name, value, source) that should fill the config directly. |
|
100 | list of (section, name, value, source) that should fill the config directly. | |
109 | If type is 'resource', obj is a tuple of (package name, resource name). |
|
101 | If type is 'resource', obj is a tuple of (package name, resource name). | |
110 | """ |
|
102 | """ | |
111 | envrc = (b'items', envrcitems()) |
|
103 | envrc = (b'items', envrcitems()) | |
112 |
|
104 | |||
113 | if b'HGRCPATH' in encoding.environ: |
|
105 | if b'HGRCPATH' in encoding.environ: | |
114 | # assume HGRCPATH is all about user configs so environments can be |
|
106 | # assume HGRCPATH is all about user configs so environments can be | |
115 | # overridden. |
|
107 | # overridden. | |
116 | _rccomponents = [envrc] |
|
108 | _rccomponents = [envrc] | |
117 | for p in encoding.environ[b'HGRCPATH'].split(pycompat.ospathsep): |
|
109 | for p in encoding.environ[b'HGRCPATH'].split(pycompat.ospathsep): | |
118 | if not p: |
|
110 | if not p: | |
119 | continue |
|
111 | continue | |
120 | _rccomponents.extend((b'path', p) for p in _expandrcpath(p)) |
|
112 | _rccomponents.extend((b'path', p) for p in _expandrcpath(p)) | |
121 | else: |
|
113 | else: | |
122 | _rccomponents = [(b'resource', r) for r in default_rc_resources()] |
|
114 | _rccomponents = [(b'resource', r) for r in default_rc_resources()] | |
123 |
|
115 | |||
124 | normpaths = lambda paths: [ |
|
116 | normpaths = lambda paths: [ | |
125 | (b'path', os.path.normpath(p)) for p in paths |
|
117 | (b'path', os.path.normpath(p)) for p in paths | |
126 | ] |
|
118 | ] | |
127 | _rccomponents.extend(normpaths(systemrcpath())) |
|
119 | _rccomponents.extend(normpaths(systemrcpath())) | |
128 | _rccomponents.append(envrc) |
|
120 | _rccomponents.append(envrc) | |
129 | _rccomponents.extend(normpaths(userrcpath())) |
|
121 | _rccomponents.extend(normpaths(userrcpath())) | |
130 | return _rccomponents |
|
122 | return _rccomponents | |
131 |
|
123 | |||
132 |
|
124 | |||
133 | def _shared_source_component(path: bytes) -> List[FileRCT]: |
|
125 | def _shared_source_component(path: bytes) -> List[FileRCT]: | |
134 | """if the current repository is shared one, this tries to read |
|
126 | """if the current repository is shared one, this tries to read | |
135 | .hg/hgrc of shared source if we are in share-safe mode |
|
127 | .hg/hgrc of shared source if we are in share-safe mode | |
136 |
|
128 | |||
137 | This should be called before reading .hg/hgrc or the main repo |
|
129 | This should be called before reading .hg/hgrc or the main repo | |
138 | as that overrides config set in shared source""" |
|
130 | as that overrides config set in shared source""" | |
139 | try: |
|
131 | try: | |
140 | with open(os.path.join(path, b".hg", b"requires"), "rb") as fp: |
|
132 | with open(os.path.join(path, b".hg", b"requires"), "rb") as fp: | |
141 | requirements = set(fp.read().splitlines()) |
|
133 | requirements = set(fp.read().splitlines()) | |
142 | if not ( |
|
134 | if not ( | |
143 | requirementsmod.SHARESAFE_REQUIREMENT in requirements |
|
135 | requirementsmod.SHARESAFE_REQUIREMENT in requirements | |
144 | and requirementsmod.SHARED_REQUIREMENT in requirements |
|
136 | and requirementsmod.SHARED_REQUIREMENT in requirements | |
145 | ): |
|
137 | ): | |
146 | return [] |
|
138 | return [] | |
147 | hgvfs = vfs.vfs(os.path.join(path, b".hg")) |
|
139 | hgvfs = vfs.vfs(os.path.join(path, b".hg")) | |
148 | sharedvfs = localrepo._getsharedvfs(hgvfs, requirements) |
|
140 | sharedvfs = localrepo._getsharedvfs(hgvfs, requirements) | |
149 | return [sharedvfs.join(b"hgrc")] |
|
141 | return [sharedvfs.join(b"hgrc")] | |
150 | except IOError: |
|
142 | except IOError: | |
151 | pass |
|
143 | pass | |
152 | return [] |
|
144 | return [] | |
153 |
|
145 | |||
154 |
|
146 | |||
155 | def repo_components(repo_path: bytes) -> List[ComponentT]: |
|
147 | def repo_components(repo_path: bytes) -> List[ComponentT]: | |
156 | """return the list of config file to read for a repository""" |
|
148 | """return the list of config file to read for a repository""" | |
157 | components = [] |
|
149 | components = [] | |
158 | components.extend(_shared_source_component(repo_path)) |
|
150 | components.extend(_shared_source_component(repo_path)) | |
159 | components.append(os.path.join(repo_path, b".hg", b"hgrc")) |
|
151 | components.append(os.path.join(repo_path, b".hg", b"hgrc")) | |
160 | components.append(os.path.join(repo_path, b".hg", b"hgrc-not-shared")) |
|
152 | components.append(os.path.join(repo_path, b".hg", b"hgrc-not-shared")) | |
161 | return [(b'path', c) for c in components] |
|
153 | return [(b'path', c) for c in components] | |
162 |
|
154 | |||
163 |
|
155 | |||
164 | def defaultpagerenv() -> Dict[bytes, bytes]: |
|
156 | def defaultpagerenv() -> Dict[bytes, bytes]: | |
165 | """return a dict of default environment variables and their values, |
|
157 | """return a dict of default environment variables and their values, | |
166 | intended to be set before starting a pager. |
|
158 | intended to be set before starting a pager. | |
167 | """ |
|
159 | """ | |
168 | return {b'LESS': b'FRX', b'LV': b'-c'} |
|
160 | return {b'LESS': b'FRX', b'LV': b'-c'} | |
169 |
|
161 | |||
170 |
|
162 | |||
171 | def use_repo_hgrc() -> bool: |
|
163 | def use_repo_hgrc() -> bool: | |
172 | """True if repositories `.hg/hgrc` config should be read""" |
|
164 | """True if repositories `.hg/hgrc` config should be read""" | |
173 | return b'HGRCSKIPREPO' not in encoding.environ |
|
165 | return b'HGRCSKIPREPO' not in encoding.environ |
General Comments 0
You need to be logged in to leave comments.
Login now