##// END OF EJS Templates
dispatch: add HGPLAIN=+strictflags to restrict early parsing of global options...
Yuya Nishihara -
r35180:c9740b69 stable
parent child Browse files
Show More
@@ -220,8 +220,17 b' def _loadnewui(srcui, args):'
220 220 newui._csystem = srcui._csystem
221 221
222 222 # command line args
223 args = args[:]
224 dispatch._parseconfig(newui, dispatch._earlygetopt(['--config'], args))
223 options = {}
224 if srcui.plain('strictflags'):
225 options.update(dispatch._earlyparseopts(args))
226 else:
227 args = args[:]
228 options['config'] = dispatch._earlygetopt(['--config'], args)
229 cwds = dispatch._earlygetopt(['--cwd'], args)
230 options['cwd'] = cwds and cwds[-1] or ''
231 rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args)
232 options['repository'] = rpath and rpath[-1] or ''
233 dispatch._parseconfig(newui, options['config'])
225 234
226 235 # stolen from tortoisehg.util.copydynamicconfig()
227 236 for section, name, value in srcui.walkconfig():
@@ -232,10 +241,9 b' def _loadnewui(srcui, args):'
232 241 newui.setconfig(section, name, value, source)
233 242
234 243 # load wd and repo config, copied from dispatch.py
235 cwds = dispatch._earlygetopt(['--cwd'], args)
236 cwd = cwds and os.path.realpath(cwds[-1]) or None
237 rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args)
238 rpath = rpath and rpath[-1] or ''
244 cwd = options['cwd']
245 cwd = cwd and os.path.realpath(cwd) or None
246 rpath = options['repository']
239 247 path, newlui = dispatch._getlocal(newui, rpath, wd=cwd)
240 248
241 249 return (newui, newlui)
@@ -150,6 +150,8 b' def dispatch(req):'
150 150 try:
151 151 if not req.ui:
152 152 req.ui = uimod.ui.load()
153 if req.ui.plain('strictflags'):
154 req.earlyoptions.update(_earlyparseopts(req.args))
153 155 if _earlyreqoptbool(req, 'traceback', ['--traceback']):
154 156 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
155 157
@@ -644,6 +646,12 b' def _parseconfig(ui, config):'
644 646
645 647 return configs
646 648
649 def _earlyparseopts(args):
650 options = {}
651 fancyopts.fancyopts(args, commands.globalopts, options,
652 gnu=False, early=True)
653 return options
654
647 655 def _earlygetopt(aliases, args, strip=True):
648 656 """Return list of values for an option (or aliases).
649 657
@@ -732,12 +740,16 b' def _earlygetopt(aliases, args, strip=Tr'
732 740
733 741 def _earlyreqopt(req, name, aliases):
734 742 """Peek a list option without using a full options table"""
743 if req.ui.plain('strictflags'):
744 return req.earlyoptions[name]
735 745 values = _earlygetopt(aliases, req.args, strip=False)
736 746 req.earlyoptions[name] = values
737 747 return values
738 748
739 749 def _earlyreqoptstr(req, name, aliases):
740 750 """Peek a string option without using a full options table"""
751 if req.ui.plain('strictflags'):
752 return req.earlyoptions[name]
741 753 value = (_earlygetopt(aliases, req.args, strip=False) or [''])[-1]
742 754 req.earlyoptions[name] = value
743 755 return value
@@ -745,13 +757,15 b' def _earlyreqoptstr(req, name, aliases):'
745 757 def _earlyreqoptbool(req, name, aliases):
746 758 """Peek a boolean option without using a full options table
747 759
748 >>> req = request([b'x', b'--debugger'])
760 >>> req = request([b'x', b'--debugger'], uimod.ui())
749 761 >>> _earlyreqoptbool(req, b'debugger', [b'--debugger'])
750 762 True
751 763
752 >>> req = request([b'x', b'--', b'--debugger'])
764 >>> req = request([b'x', b'--', b'--debugger'], uimod.ui())
753 765 >>> _earlyreqoptbool(req, b'debugger', [b'--debugger'])
754 766 """
767 if req.ui.plain('strictflags'):
768 return req.earlyoptions[name]
755 769 try:
756 770 argcount = req.args.index("--")
757 771 except ValueError:
@@ -56,9 +56,17 b' HGPLAIN'
56 56 localization. This can be useful when scripting against Mercurial
57 57 in the face of existing user configuration.
58 58
59 In addition to the features disabled by ``HGPLAIN=``, the following
60 values can be specified to adjust behavior:
61
62 ``+strictflags``
63 Restrict parsing of command line flags.
64
59 65 Equivalent options set via command line flags or environment
60 66 variables are not overridden.
61 67
68 See :hg:`help scripting` for details.
69
62 70 HGPLAINEXCEPT
63 71 This is a comma-separated list of features to preserve when
64 72 HGPLAIN is enabled. Currently the following values are supported:
@@ -74,6 +74,32 b' HGRCPATH'
74 74 like the username and extensions that may be required to interface
75 75 with a repository.
76 76
77 Command-line Flags
78 ==================
79
80 Mercurial's default command-line parser is designed for humans, and is not
81 robust against malicious input. For instance, you can start a debugger by
82 passing ``--debugger`` as an option value::
83
84 $ REV=--debugger sh -c 'hg log -r "$REV"'
85
86 This happens because several command-line flags need to be scanned without
87 using a concrete command table, which may be modified while loading repository
88 settings and extensions.
89
90 Since Mercurial 4.4.2, the parsing of such flags may be restricted by setting
91 ``HGPLAIN=+strictflags``. When this feature is enabled, all early options
92 (e.g. ``-R/--repository``, ``--cwd``, ``--config``) must be specified first
93 amongst the other global options, and cannot be injected to an arbitrary
94 location::
95
96 $ HGPLAIN=+strictflags hg -R "$REPO" log -r "$REV"
97
98 In earlier Mercurial versions where ``+strictflags`` isn't available, you
99 can mitigate the issue by concatenating an option value with its flag::
100
101 $ hg log -r"$REV" --keyword="$KEYWORD"
102
77 103 Consuming Command Output
78 104 ========================
79 105
@@ -761,6 +761,7 b' class ui(object):'
761 761
762 762 The return value can either be
763 763 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
764 - False if feature is disabled by default and not included in HGPLAIN
764 765 - True otherwise
765 766 '''
766 767 if ('HGPLAIN' not in encoding.environ and
@@ -768,6 +769,9 b' class ui(object):'
768 769 return False
769 770 exceptions = encoding.environ.get('HGPLAINEXCEPT',
770 771 '').strip().split(',')
772 # TODO: add support for HGPLAIN=+feature,-feature syntax
773 if '+strictflags' not in encoding.environ.get('HGPLAIN', '').split(','):
774 exceptions.append('strictflags')
771 775 if feature and exceptions:
772 776 return feature not in exceptions
773 777 return True
@@ -137,6 +137,20 b' typical client does not want echo-back m'
137 137 summary: 1
138 138
139 139
140 check strict parsing of early options:
141
142 >>> import os
143 >>> from hgclient import check, readchannel, runcommand
144 >>> os.environ['HGPLAIN'] = '+strictflags'
145 >>> @check
146 ... def cwd(server):
147 ... readchannel(server)
148 ... runcommand(server, ['log', '-b', '--config=alias.log=!echo pwned',
149 ... 'default'])
150 *** runcommand log -b --config=alias.log=!echo pwned default
151 abort: unknown revision '--config=alias.log=!echo pwned'!
152 [255]
153
140 154 check that "histedit --commands=-" can read rules from the input channel:
141 155
142 156 >>> import cStringIO
@@ -113,6 +113,51 b' Shell aliases bypass any command parsing'
113 113 $ hg log -b '--config=alias.log=!echo howdy'
114 114 howdy
115 115
116 Early options must come first if HGPLAIN=+strictflags is specified:
117 (BUG: chg cherry-picks early options to pass them as a server command)
118
119 #if no-chg
120 $ HGPLAIN=+strictflags hg log -b --config='hooks.pre-log=false' default
121 abort: unknown revision '--config=hooks.pre-log=false'!
122 [255]
123 $ HGPLAIN=+strictflags hg log -b -R. default
124 abort: unknown revision '-R.'!
125 [255]
126 $ HGPLAIN=+strictflags hg log -b --cwd=. default
127 abort: unknown revision '--cwd=.'!
128 [255]
129 #endif
130 $ HGPLAIN=+strictflags hg log -b --debugger default
131 abort: unknown revision '--debugger'!
132 [255]
133 $ HGPLAIN=+strictflags hg log -b --config='alias.log=!echo pwned' default
134 abort: unknown revision '--config=alias.log=!echo pwned'!
135 [255]
136
137 $ HGPLAIN=+strictflags hg log --config='hooks.pre-log=false' -b default
138 abort: option --config may not be abbreviated!
139 [255]
140 $ HGPLAIN=+strictflags hg log -q --cwd=.. -b default
141 abort: option --cwd may not be abbreviated!
142 [255]
143 $ HGPLAIN=+strictflags hg log -q -R . -b default
144 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
145 [255]
146
147 $ HGPLAIN=+strictflags hg --config='hooks.pre-log=false' log -b default
148 abort: pre-log hook exited with status 1
149 [255]
150 $ HGPLAIN=+strictflags hg --cwd .. -q -Ra log -b default
151 0:cb9a9f314b8b
152
153 For compatibility reasons, HGPLAIN=+strictflags is not enabled by plain HGPLAIN:
154
155 $ HGPLAIN= hg log --config='hooks.pre-log=false' -b default
156 abort: pre-log hook exited with status 1
157 [255]
158 $ HGPLAINEXCEPT= hg log --cwd .. -q -Ra -b default
159 0:cb9a9f314b8b
160
116 161 [defaults]
117 162
118 163 $ hg cat a
General Comments 0
You need to be logged in to leave comments. Login now