summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/CHANGES.txt2
-rw-r--r--src/engine/SCons/Script/SConsOptions.py67
-rw-r--r--test/AddOption/longopts.py60
3 files changed, 128 insertions, 1 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 978c82c..39c8d32 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -49,6 +49,8 @@ RELEASE 2.3.1.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
- Added release_target_info() to File nodes, which helps to
reduce memory consumption in clean builds and update runs
of large projects.
+ - Fixed the handling of long options in the command-line
+ parsing (#2929).
From Gary Oberbrunner:
- Test harness: fail_test() can now print a message to help debugging.
diff --git a/src/engine/SCons/Script/SConsOptions.py b/src/engine/SCons/Script/SConsOptions.py
index 62033ba..d7262a9 100644
--- a/src/engine/SCons/Script/SConsOptions.py
+++ b/src/engine/SCons/Script/SConsOptions.py
@@ -337,6 +337,71 @@ class SConsOptionParser(optparse.OptionParser):
option.process(opt, value, values, self)
+ def reparse_local_options(self):
+ """
+ Re-parse the leftover command-line options stored
+ in self.largs, so that any value overridden on the
+ command line is immediately available if the user turns
+ around and does a GetOption() right away.
+
+ We mimic the processing of the single args
+ in the original OptionParser._process_args(), but here we
+ allow exact matches for long-opts only (no partial
+ argument names!).
+
+ Else, this would lead to problems in add_local_option()
+ below. When called from there, we try to reparse the
+ command-line arguments that
+ 1. haven't been processed so far (self.largs), but
+ 2. are possibly not added to the list of options yet.
+
+ So, when we only have a value for "--myargument" yet,
+ a command-line argument of "--myarg=test" would set it.
+ Responsible for this behaviour is the method
+ _match_long_opt(), which allows for partial matches of
+ the option name, as long as the common prefix appears to
+ be unique.
+ This would lead to further confusion, because we might want
+ to add another option "--myarg" later on (see issue #2929).
+
+ """
+ rargs = []
+ largs_restore = []
+ # Loop over all remaining arguments
+ skip = False
+ for l in self.largs:
+ if skip:
+ # Accept all remaining arguments as they are
+ largs_restore.append(l)
+ else:
+ if len(l) > 2 and l[0:2] == "--":
+ # Check long option
+ lopt = (l,)
+ if "=" in l:
+ # Split into option and value
+ lopt = l.split("=", 1)
+
+ if lopt[0] in self._long_opt:
+ # Argument is already known
+ rargs.append('='.join(lopt))
+ else:
+ # Not known yet, so reject for now
+ largs_restore.append('='.join(lopt))
+ else:
+ if l == "--" or l == "-":
+ # Stop normal processing and don't
+ # process the rest of the command-line opts
+ largs_restore.append(l)
+ skip = True
+ else:
+ rargs.append(l)
+
+ # Parse the filtered list
+ self.parse_args(rargs, self.values)
+ # Restore the list of remaining arguments for the
+ # next call of AddOption/add_local_option...
+ self.largs = self.largs + largs_restore
+
def add_local_option(self, *args, **kw):
"""
Adds a local option to the parser.
@@ -364,7 +429,7 @@ class SConsOptionParser(optparse.OptionParser):
# available if the user turns around and does a GetOption()
# right away.
setattr(self.values.__defaults__, result.dest, result.default)
- self.parse_args(self.largs, self.values)
+ self.reparse_local_options()
return result
diff --git a/test/AddOption/longopts.py b/test/AddOption/longopts.py
new file mode 100644
index 0000000..47ae4f1
--- /dev/null
+++ b/test/AddOption/longopts.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verifies that the default name matching of optparse for long options
+gets properly suppressed. We don't allow for partial matching
+of argument names, because it would lead to trouble in the test
+case below...
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """\
+AddOption('--myargument', dest='myargument', type='string', default='gully')
+AddOption('--myarg', dest='myarg', type='string', default='balla')
+print("myargument: " + str(GetOption('myargument')))
+print("myarg: " + str(GetOption('myarg')))
+""")
+
+test.run('-Q -q .',
+ stdout="myargument: gully\nmyarg: balla\n")
+
+test.run('-Q -q . --myargument=helloworld',
+ stdout="myargument: helloworld\nmyarg: balla\n")
+
+test.run('-Q -q . --myarg=helloworld',
+ stdout="myargument: gully\nmyarg: helloworld\n")
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: