Skip to content

Commit 23ccbab

Browse files
committed
Fix short-option processing
Override the _process_short_opts method from optparse so it behaves better. This fix is lifted directly from SCons#3799, leaving an additional part to apply later. Fixes SCons#3798 Signed-off-by: Mats Wichmann <[email protected]>
1 parent 5d453c2 commit 23ccbab

File tree

5 files changed

+81
-11
lines changed

5 files changed

+81
-11
lines changed

CHANGES.txt

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ NOTE: Python 3.6 support is deprecated and will be dropped in a future release.
1212

1313
RELEASE VERSION/DATE TO BE FILLED IN LATER
1414

15+
From Dillan Mills:
16+
- Fix support for short options (`-x`).
17+
1518
From Mats Wichmann:
1619
- PackageVariable now does what the documentation always said it does
1720
if the variable is used on the command line with one of the enabling

RELEASE.txt

+5
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ FIXES
4343
it always produced True in this case).
4444
- Temporary files created by TempFileMunge() are now cleaned up on
4545
scons exit, instead of at the time they're used. Fixes #4595.
46+
- AddOption now correctly adds short (single-character) options.
47+
Previously an added short option would always report as unknown,
48+
while long option names for the same option worked. Short options
49+
that take a value require the user to specify the value immediately
50+
following the option, with no spaces (e.g. -j5 and not -j 5).
4651

4752
IMPROVEMENTS
4853
------------

SCons/Script/SConsOptions.py

+67-6
Original file line numberDiff line numberDiff line change
@@ -342,12 +342,13 @@ def error(self, msg: str) -> None:
342342
def _process_long_opt(self, rargs, values) -> None:
343343
"""SCons-specific processing of long options.
344344
345-
This is copied directly from the normal
346-
``optparse._process_long_opt()`` method, except that, if configured
347-
to do so, we catch the exception thrown when an unknown option
348-
is encountered and just stick it back on the "leftover" arguments
349-
for later (re-)processing. This is because we may see the option
350-
definition later, while processing SConscript files.
345+
This is copied directly from the normal Optparse
346+
:meth:`~optparse.OptionParser._process_long_opt` method, except
347+
that, if configured to do so, we catch the exception thrown
348+
when an unknown option is encountered and just stick it back
349+
on the "leftover" arguments for later (re-)processing. This is
350+
because we may see the option definition later, while processing
351+
SConscript files.
351352
"""
352353
arg = rargs.pop(0)
353354

@@ -414,6 +415,66 @@ def _process_long_opt(self, rargs, values) -> None:
414415

415416
option.process(opt, value, values, self)
416417

418+
419+
def _process_short_opts(self, rargs, values) -> None:
420+
"""SCons-specific processing of short options.
421+
422+
This is copied directly from the normal Optparse
423+
:meth:`~optparse.OptionParser._process_short_opts` method, except
424+
that, if configured to do so, we catch the exception thrown
425+
when an unknown option is encountered and just stick it back
426+
on the "leftover" arguments for later (re-)processing. This is
427+
because we may see the option definition later, while processing
428+
SConscript files.
429+
"""
430+
arg = rargs.pop(0)
431+
stop = False
432+
i = 1
433+
for ch in arg[1:]:
434+
opt = "-" + ch
435+
option = self._short_opt.get(opt)
436+
i += 1 # we have consumed a character
437+
438+
try:
439+
if not option:
440+
raise optparse.BadOptionError(opt)
441+
except optparse.BadOptionError:
442+
# SCons addition: if requested, add unknown options to
443+
# the "leftover arguments" list for later processing.
444+
if self.preserve_unknown_options:
445+
self.largs.append(arg)
446+
return
447+
raise
448+
449+
if option.takes_value():
450+
# Any characters left in arg? Pretend they're the
451+
# next arg, and stop consuming characters of arg.
452+
if i < len(arg):
453+
rargs.insert(0, arg[i:])
454+
stop = True
455+
456+
nargs = option.nargs
457+
if len(rargs) < nargs:
458+
if nargs == 1:
459+
self.error(_("%s option requires an argument") % opt)
460+
else:
461+
self.error(_("%s option requires %d arguments")
462+
% (opt, nargs))
463+
elif nargs == 1:
464+
value = rargs.pop(0)
465+
else:
466+
value = tuple(rargs[0:nargs])
467+
del rargs[0:nargs]
468+
469+
else: # option doesn't take a value
470+
value = None
471+
472+
option.process(opt, value, values, self)
473+
474+
if stop:
475+
break
476+
477+
417478
def reparse_local_options(self) -> None:
418479
"""Re-parse the leftover command-line options.
419480

test/AddOption/basic.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
DefaultEnvironment(tools=[])
3939
env = Environment(tools=[])
4040
AddOption(
41-
'--force',
41+
'-F', '--force',
4242
action="store_true",
4343
help='force installation (overwrite any existing files)',
4444
)
@@ -74,6 +74,7 @@
7474

7575
test.run('-Q -q .', stdout="None\nNone\n")
7676
test.run('-Q -q . --force', stdout="True\nNone\n")
77+
test.run('-Q -q . -F', stdout="True\nNone\n")
7778
test.run('-Q -q . --prefix=/home/foo', stdout="None\n/home/foo\n")
7879
test.run('-Q -q . -- --prefix=/home/foo --force', status=1, stdout="None\nNone\n")
7980
# check that SetOption works on prefix...

test/SCONSFLAGS.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,15 @@
6262
test.must_not_contain_any_line(test.stdout(), ['Help text.'])
6363
test.must_contain_all_lines(test.stdout(), ['-H, --help-options'])
6464

65-
os.environ['SCONSFLAGS'] = '-Z'
66-
6765
expect = r"""usage: scons [OPTIONS] [VARIABLES] [TARGETS]
6866
6967
SCons Error: no such option: -Z
7068
"""
7169

72-
test.run(arguments = "-H", status = 2,
73-
stderr = expect, match=TestSCons.match_exact)
70+
test.run(arguments="-Z", status=2, stderr=expect, match=TestSCons.match_exact)
71+
72+
os.environ['SCONSFLAGS'] = '-Z'
73+
test.run(status=2, stderr=expect, match=TestSCons.match_exact)
7474

7575
test.pass_test()
7676

0 commit comments

Comments
 (0)