##// END OF EJS Templates
config: gather constant and type into the `__init__.py`...
marmoute -
r53322:3e79ca01 default
parent child Browse files
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 rcutil
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