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 = cwd |
|
|
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