Show More
@@ -220,8 +220,17 b' def _loadnewui(srcui, args):' | |||||
220 | newui._csystem = srcui._csystem |
|
220 | newui._csystem = srcui._csystem | |
221 |
|
221 | |||
222 | # command line args |
|
222 | # command line args | |
223 | args = args[:] |
|
223 | options = {} | |
224 | dispatch._parseconfig(newui, dispatch._earlygetopt(['--config'], args)) |
|
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 | # stolen from tortoisehg.util.copydynamicconfig() |
|
235 | # stolen from tortoisehg.util.copydynamicconfig() | |
227 | for section, name, value in srcui.walkconfig(): |
|
236 | for section, name, value in srcui.walkconfig(): | |
@@ -232,10 +241,9 b' def _loadnewui(srcui, args):' | |||||
232 | newui.setconfig(section, name, value, source) |
|
241 | newui.setconfig(section, name, value, source) | |
233 |
|
242 | |||
234 | # load wd and repo config, copied from dispatch.py |
|
243 | # load wd and repo config, copied from dispatch.py | |
235 | cwds = dispatch._earlygetopt(['--cwd'], args) |
|
244 | cwd = options['cwd'] | |
236 |
cwd = cwd |
|
245 | cwd = cwd and os.path.realpath(cwd) or None | |
237 | rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args) |
|
246 | rpath = options['repository'] | |
238 | rpath = rpath and rpath[-1] or '' |
|
|||
239 | path, newlui = dispatch._getlocal(newui, rpath, wd=cwd) |
|
247 | path, newlui = dispatch._getlocal(newui, rpath, wd=cwd) | |
240 |
|
248 | |||
241 | return (newui, newlui) |
|
249 | return (newui, newlui) |
@@ -150,6 +150,8 b' def dispatch(req):' | |||||
150 | try: |
|
150 | try: | |
151 | if not req.ui: |
|
151 | if not req.ui: | |
152 | req.ui = uimod.ui.load() |
|
152 | req.ui = uimod.ui.load() | |
|
153 | if req.ui.plain('strictflags'): | |||
|
154 | req.earlyoptions.update(_earlyparseopts(req.args)) | |||
153 | if _earlyreqoptbool(req, 'traceback', ['--traceback']): |
|
155 | if _earlyreqoptbool(req, 'traceback', ['--traceback']): | |
154 | req.ui.setconfig('ui', 'traceback', 'on', '--traceback') |
|
156 | req.ui.setconfig('ui', 'traceback', 'on', '--traceback') | |
155 |
|
157 | |||
@@ -644,6 +646,12 b' def _parseconfig(ui, config):' | |||||
644 |
|
646 | |||
645 | return configs |
|
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 | def _earlygetopt(aliases, args, strip=True): |
|
655 | def _earlygetopt(aliases, args, strip=True): | |
648 | """Return list of values for an option (or aliases). |
|
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 | def _earlyreqopt(req, name, aliases): |
|
741 | def _earlyreqopt(req, name, aliases): | |
734 | """Peek a list option without using a full options table""" |
|
742 | """Peek a list option without using a full options table""" | |
|
743 | if req.ui.plain('strictflags'): | |||
|
744 | return req.earlyoptions[name] | |||
735 | values = _earlygetopt(aliases, req.args, strip=False) |
|
745 | values = _earlygetopt(aliases, req.args, strip=False) | |
736 | req.earlyoptions[name] = values |
|
746 | req.earlyoptions[name] = values | |
737 | return values |
|
747 | return values | |
738 |
|
748 | |||
739 | def _earlyreqoptstr(req, name, aliases): |
|
749 | def _earlyreqoptstr(req, name, aliases): | |
740 | """Peek a string option without using a full options table""" |
|
750 | """Peek a string option without using a full options table""" | |
|
751 | if req.ui.plain('strictflags'): | |||
|
752 | return req.earlyoptions[name] | |||
741 | value = (_earlygetopt(aliases, req.args, strip=False) or [''])[-1] |
|
753 | value = (_earlygetopt(aliases, req.args, strip=False) or [''])[-1] | |
742 | req.earlyoptions[name] = value |
|
754 | req.earlyoptions[name] = value | |
743 | return value |
|
755 | return value | |
@@ -745,13 +757,15 b' def _earlyreqoptstr(req, name, aliases):' | |||||
745 | def _earlyreqoptbool(req, name, aliases): |
|
757 | def _earlyreqoptbool(req, name, aliases): | |
746 | """Peek a boolean option without using a full options table |
|
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 | >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) |
|
761 | >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) | |
750 | True |
|
762 | True | |
751 |
|
763 | |||
752 | >>> req = request([b'x', b'--', b'--debugger']) |
|
764 | >>> req = request([b'x', b'--', b'--debugger'], uimod.ui()) | |
753 | >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) |
|
765 | >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) | |
754 | """ |
|
766 | """ | |
|
767 | if req.ui.plain('strictflags'): | |||
|
768 | return req.earlyoptions[name] | |||
755 | try: |
|
769 | try: | |
756 | argcount = req.args.index("--") |
|
770 | argcount = req.args.index("--") | |
757 | except ValueError: |
|
771 | except ValueError: |
@@ -56,9 +56,17 b' HGPLAIN' | |||||
56 | localization. This can be useful when scripting against Mercurial |
|
56 | localization. This can be useful when scripting against Mercurial | |
57 | in the face of existing user configuration. |
|
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 | Equivalent options set via command line flags or environment |
|
65 | Equivalent options set via command line flags or environment | |
60 | variables are not overridden. |
|
66 | variables are not overridden. | |
61 |
|
67 | |||
|
68 | See :hg:`help scripting` for details. | |||
|
69 | ||||
62 | HGPLAINEXCEPT |
|
70 | HGPLAINEXCEPT | |
63 | This is a comma-separated list of features to preserve when |
|
71 | This is a comma-separated list of features to preserve when | |
64 | HGPLAIN is enabled. Currently the following values are supported: |
|
72 | HGPLAIN is enabled. Currently the following values are supported: |
@@ -74,6 +74,32 b' HGRCPATH' | |||||
74 | like the username and extensions that may be required to interface |
|
74 | like the username and extensions that may be required to interface | |
75 | with a repository. |
|
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 | Consuming Command Output |
|
103 | Consuming Command Output | |
78 | ======================== |
|
104 | ======================== | |
79 |
|
105 |
@@ -761,6 +761,7 b' class ui(object):' | |||||
761 |
|
761 | |||
762 | The return value can either be |
|
762 | The return value can either be | |
763 | - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT |
|
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 | - True otherwise |
|
765 | - True otherwise | |
765 | ''' |
|
766 | ''' | |
766 | if ('HGPLAIN' not in encoding.environ and |
|
767 | if ('HGPLAIN' not in encoding.environ and | |
@@ -768,6 +769,9 b' class ui(object):' | |||||
768 | return False |
|
769 | return False | |
769 | exceptions = encoding.environ.get('HGPLAINEXCEPT', |
|
770 | exceptions = encoding.environ.get('HGPLAINEXCEPT', | |
770 | '').strip().split(',') |
|
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 | if feature and exceptions: |
|
775 | if feature and exceptions: | |
772 | return feature not in exceptions |
|
776 | return feature not in exceptions | |
773 | return True |
|
777 | return True |
@@ -137,6 +137,20 b' typical client does not want echo-back m' | |||||
137 | summary: 1 |
|
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 | check that "histedit --commands=-" can read rules from the input channel: |
|
154 | check that "histedit --commands=-" can read rules from the input channel: | |
141 |
|
155 | |||
142 | >>> import cStringIO |
|
156 | >>> import cStringIO |
@@ -113,6 +113,51 b' Shell aliases bypass any command parsing' | |||||
113 | $ hg log -b '--config=alias.log=!echo howdy' |
|
113 | $ hg log -b '--config=alias.log=!echo howdy' | |
114 | howdy |
|
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 | [defaults] |
|
161 | [defaults] | |
117 |
|
162 | |||
118 | $ hg cat a |
|
163 | $ hg cat a |
General Comments 0
You need to be logged in to leave comments.
Login now