summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-11-06 12:25:25 (GMT)
committerSteven Knight <knight@baldmt.com>2002-11-06 12:25:25 (GMT)
commit8dbe61168174137944a5bc55ea5a9ff389336376 (patch)
treeb507cef9d3ffa1248dde67c7f26368841c148b42
parentd3a159a23fdeaa76c7931c7f8b1b7dafd43b4b99 (diff)
downloadSCons-8dbe61168174137944a5bc55ea5a9ff389336376.zip
SCons-8dbe61168174137944a5bc55ea5a9ff389336376.tar.gz
SCons-8dbe61168174137944a5bc55ea5a9ff389336376.tar.bz2
Refactor command-line parsing. (Steve Leblanc)
-rw-r--r--rpm/scons.spec8
-rw-r--r--src/CHANGES.txt5
-rw-r--r--src/engine/MANIFEST.in4
-rw-r--r--src/engine/SCons/Optik/.aeignore5
-rw-r--r--src/engine/SCons/Optik/__init__.py32
-rw-r--r--src/engine/SCons/Optik/errors.py55
-rw-r--r--src/engine/SCons/Optik/option.py388
-rw-r--r--src/engine/SCons/Optik/option_parser.py661
-rw-r--r--src/engine/SCons/Script/__init__.py1083
-rw-r--r--src/engine/setup.py1
-rw-r--r--src/setup.py1
-rw-r--r--test/SCONSFLAGS.py11
-rw-r--r--test/option--profile.py8
-rw-r--r--test/option-unknown.py14
14 files changed, 1600 insertions, 676 deletions
diff --git a/rpm/scons.spec b/rpm/scons.spec
index 8c1cf73..76f6d3b 100644
--- a/rpm/scons.spec
+++ b/rpm/scons.spec
@@ -68,6 +68,14 @@ rm -rf $RPM_BUILD_ROOT
/usr/lib/scons/SCons/Node/FS.pyc
/usr/lib/scons/SCons/Node/__init__.py
/usr/lib/scons/SCons/Node/__init__.pyc
+/usr/lib/scons/SCons/Optik/__init__.py
+/usr/lib/scons/SCons/Optik/__init__.pyc
+/usr/lib/scons/SCons/Optik/errors.py
+/usr/lib/scons/SCons/Optik/errors.pyc
+/usr/lib/scons/SCons/Optik/option.py
+/usr/lib/scons/SCons/Optik/option.pyc
+/usr/lib/scons/SCons/Optik/option_parser.py
+/usr/lib/scons/SCons/Optik/option_parser.pyc
/usr/lib/scons/SCons/Options.py
/usr/lib/scons/SCons/Options.pyc
/usr/lib/scons/SCons/Platform/cygwin.py
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index c91a59e..83c0d08 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -50,6 +50,11 @@ RELEASE 0.09 -
- Add separate $SHOBJPREFIX and $SHOBJSUFFIX construction variables
(by default, the same as $OBJPREFIX and $OBJSUFFIX).
+ From Steve LeBlanc:
+
+ - Refactor option processing to use our own version of Greg Ward's
+ Optik module, modified to run under Python 1.5.2.
+
From Jeff Petkau:
- Fix interpretation of '#/../foo' on Win32 systems.
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index bca093f..d500733 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -9,6 +9,10 @@ SCons/exitfuncs.py
SCons/Node/__init__.py
SCons/Node/Alias.py
SCons/Node/FS.py
+SCons/Optik/__init__.py
+SCons/Optik/errors.py
+SCons/Optik/option.py
+SCons/Optik/option_parser.py
SCons/Options.py
SCons/Platform/__init__.py
SCons/Platform/cygwin.py
diff --git a/src/engine/SCons/Optik/.aeignore b/src/engine/SCons/Optik/.aeignore
new file mode 100644
index 0000000..22ebd62
--- /dev/null
+++ b/src/engine/SCons/Optik/.aeignore
@@ -0,0 +1,5 @@
+*,D
+*.pyc
+.*.swp
+.consign
+.sconsign
diff --git a/src/engine/SCons/Optik/__init__.py b/src/engine/SCons/Optik/__init__.py
new file mode 100644
index 0000000..8ea41fb
--- /dev/null
+++ b/src/engine/SCons/Optik/__init__.py
@@ -0,0 +1,32 @@
+"""optik
+
+A powerful, extensible, and easy-to-use command-line parser for Python.
+
+By Greg Ward <gward@python.net>
+
+See http://optik.sourceforge.net/
+"""
+
+# Copyright (c) 2001 Gregory P. Ward. All rights reserved.
+# See the README.txt distributed with Optik for licensing terms.
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+# Original Optik revision this is based on:
+__Optik_revision__ = "__init__.py,v 1.11 2002/04/11 19:17:34 gward Exp"
+
+__version__ = "1.3"
+
+
+# Re-import these for convenience
+from SCons.Optik.option import Option
+from SCons.Optik.option_parser import \
+ OptionParser, SUPPRESS_HELP, SUPPRESS_USAGE
+from SCons.Optik.errors import OptionValueError
+
+
+# Some day, there might be many Option classes. As of Optik 1.3, the
+# preferred way to instantiate Options is indirectly, via make_option(),
+# which will become a factory function when there are many Option
+# classes.
+make_option = Option
diff --git a/src/engine/SCons/Optik/errors.py b/src/engine/SCons/Optik/errors.py
new file mode 100644
index 0000000..dca8a69
--- /dev/null
+++ b/src/engine/SCons/Optik/errors.py
@@ -0,0 +1,55 @@
+"""optik.errors
+
+Exception classes used by Optik.
+"""
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+# Original Optik revision this is based on:
+__Optik_revision__ = "errors.py,v 1.5 2002/02/13 23:29:47 gward Exp"
+
+# Copyright (c) 2001 Gregory P. Ward. All rights reserved.
+# See the README.txt distributed with Optik for licensing terms.
+
+# created 2001/10/17 GPW (from optik.py)
+
+
+class OptikError (Exception):
+ def __init__ (self, msg):
+ self.msg = msg
+
+ def __str__ (self):
+ return self.msg
+
+
+class OptionError (OptikError):
+ """
+ Raised if an Option instance is created with invalid or
+ inconsistent arguments.
+ """
+
+ def __init__ (self, msg, option):
+ self.msg = msg
+ self.option_id = str(option)
+
+ def __str__ (self):
+ if self.option_id:
+ return "option %s: %s" % (self.option_id, self.msg)
+ else:
+ return self.msg
+
+class OptionConflictError (OptionError):
+ """
+ Raised if conflicting options are added to an OptionParser.
+ """
+
+class OptionValueError (OptikError):
+ """
+ Raised if an invalid option value is encountered on the command
+ line.
+ """
+
+class BadOptionError (OptikError):
+ """
+ Raised if an invalid or ambiguous option is seen on the command-line.
+ """
diff --git a/src/engine/SCons/Optik/option.py b/src/engine/SCons/Optik/option.py
new file mode 100644
index 0000000..2e1ec33
--- /dev/null
+++ b/src/engine/SCons/Optik/option.py
@@ -0,0 +1,388 @@
+"""optik.option
+
+Defines the Option class and some standard value-checking functions.
+"""
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+# Original Optik revision this is based on:
+__Optik_revision__ = "option.py,v 1.19.2.1 2002/07/23 01:51:14 gward Exp"
+
+# Copyright (c) 2001 Gregory P. Ward. All rights reserved.
+# See the README.txt distributed with Optik for licensing terms.
+
+# created 2001/10/17, GPW (from optik.py)
+
+import sys
+import string
+from types import TupleType, ListType, DictType
+from SCons.Optik.errors import OptionError, OptionValueError
+
+_builtin_cvt = { "int" : (int, "integer"),
+ "long" : (long, "long integer"),
+ "float" : (float, "floating-point"),
+ "complex" : (complex, "complex") }
+
+def check_builtin (option, opt, value):
+ (cvt, what) = _builtin_cvt[option.type]
+ try:
+ return cvt(value)
+ except ValueError:
+ raise OptionValueError(
+ #"%s: invalid %s argument %s" % (opt, what, repr(value)))
+ "option %s: invalid %s value: %s" % (opt, what, repr(value)))
+
+def check_choice(option, opt, value):
+ if value in option.choices:
+ return value
+ else:
+ choices = string.join(map(repr, option.choices),", ")
+ raise OptionValueError(
+ "option %s: invalid choice: %s (choose from %s)"
+ % (opt, repr(value), choices))
+
+# Not supplying a default is different from a default of None,
+# so we need an explicit "not supplied" value.
+NO_DEFAULT = "NO"+"DEFAULT"
+
+
+class Option:
+ """
+ Instance attributes:
+ _short_opts : [string]
+ _long_opts : [string]
+
+ action : string
+ type : string
+ dest : string
+ default : any
+ nargs : int
+ const : any
+ choices : [string]
+ callback : function
+ callback_args : (any*)
+ callback_kwargs : { string : any }
+ help : string
+ metavar : string
+ """
+
+ # The list of instance attributes that may be set through
+ # keyword args to the constructor.
+ ATTRS = ['action',
+ 'type',
+ 'dest',
+ 'default',
+ 'nargs',
+ 'const',
+ 'choices',
+ 'callback',
+ 'callback_args',
+ 'callback_kwargs',
+ 'help',
+ 'metavar']
+
+ # The set of actions allowed by option parsers. Explicitly listed
+ # here so the constructor can validate its arguments.
+ ACTIONS = ("store",
+ "store_const",
+ "store_true",
+ "store_false",
+ "append",
+ "count",
+ "callback",
+ "help",
+ "version")
+
+ # The set of actions that involve storing a value somewhere;
+ # also listed just for constructor argument validation. (If
+ # the action is one of these, there must be a destination.)
+ STORE_ACTIONS = ("store",
+ "store_const",
+ "store_true",
+ "store_false",
+ "append",
+ "count")
+
+ # The set of actions for which it makes sense to supply a value
+ # type, ie. where we expect an argument to this option.
+ TYPED_ACTIONS = ("store",
+ "append",
+ "callback")
+
+ # The set of known types for option parsers. Again, listed here for
+ # constructor argument validation.
+ TYPES = ("string", "int", "long", "float", "complex", "choice")
+
+ # Dictionary of argument checking functions, which convert and
+ # validate option arguments according to the option type.
+ #
+ # Signature of checking functions is:
+ # check(option : Option, opt : string, value : string) -> any
+ # where
+ # option is the Option instance calling the checker
+ # opt is the actual option seen on the command-line
+ # (eg. "-a", "--file")
+ # value is the option argument seen on the command-line
+ #
+ # The return value should be in the appropriate Python type
+ # for option.type -- eg. an integer if option.type == "int".
+ #
+ # If no checker is defined for a type, arguments will be
+ # unchecked and remain strings.
+ TYPE_CHECKER = { "int" : check_builtin,
+ "long" : check_builtin,
+ "float" : check_builtin,
+ "complex" : check_builtin,
+ "choice" : check_choice,
+ }
+
+
+ # CHECK_METHODS is a list of unbound method objects; they are called
+ # by the constructor, in order, after all attributes are
+ # initialized. The list is created and filled in later, after all
+ # the methods are actually defined. (I just put it here because I
+ # like to define and document all class attributes in the same
+ # place.) Subclasses that add another _check_*() method should
+ # define their own CHECK_METHODS list that adds their check method
+ # to those from this class.
+ CHECK_METHODS = None
+
+
+ # -- Constructor/initialization methods ----------------------------
+
+ def __init__ (self, *opts, **attrs):
+ # Set _short_opts, _long_opts attrs from 'opts' tuple
+ opts = self._check_opt_strings(opts)
+ self._set_opt_strings(opts)
+
+ # Set all other attrs (action, type, etc.) from 'attrs' dict
+ self._set_attrs(attrs)
+
+ # Check all the attributes we just set. There are lots of
+ # complicated interdependencies, but luckily they can be farmed
+ # out to the _check_*() methods listed in CHECK_METHODS -- which
+ # could be handy for subclasses! The one thing these all share
+ # is that they raise OptionError if they discover a problem.
+ for checker in self.CHECK_METHODS:
+ checker(self)
+
+ def _check_opt_strings (self, opts):
+ # Filter out None because early versions of Optik had exactly
+ # one short option and one long option, either of which
+ # could be None.
+ opts = filter(None, opts)
+ if not opts:
+ raise OptionError("at least one option string must be supplied",
+ self)
+ return opts
+
+ def _set_opt_strings (self, opts):
+ self._short_opts = []
+ self._long_opts = []
+ for opt in opts:
+ if len(opt) < 2:
+ raise OptionError(
+ "invalid option string %s: "
+ "must be at least two characters long" % (`opt`,), self)
+ elif len(opt) == 2:
+ if not (opt[0] == "-" and opt[1] != "-"):
+ raise OptionError(
+ "invalid short option string %s: "
+ "must be of the form -x, (x any non-dash char)" % (`opt`,),
+ self)
+ self._short_opts.append(opt)
+ else:
+ if not (opt[0:2] == "--" and opt[2] != "-"):
+ raise OptionError(
+ "invalid long option string %s: "
+ "must start with --, followed by non-dash" % (`opt`,),
+ self)
+ self._long_opts.append(opt)
+
+ def _set_attrs (self, attrs):
+ for attr in self.ATTRS:
+ if attrs.has_key(attr):
+ setattr(self, attr, attrs[attr])
+ del attrs[attr]
+ else:
+ if attr == 'default':
+ setattr(self, attr, NO_DEFAULT)
+ else:
+ setattr(self, attr, None)
+ if attrs:
+ raise OptionError(
+ "invalid keyword arguments: %s" % string.join(attrs.keys(),", "),
+ self)
+
+
+ # -- Constructor validation methods --------------------------------
+
+ def _check_action (self):
+ if self.action is None:
+ self.action = "store"
+ elif self.action not in self.ACTIONS:
+ raise OptionError("invalid action: %s" % (`self.action`,), self)
+
+ def _check_type (self):
+ if self.type is None:
+ # XXX should factor out another class attr here: list of
+ # actions that *require* a type
+ if self.action in ("store", "append"):
+ if self.choices is not None:
+ # The "choices" attribute implies "choice" type.
+ self.type = "choice"
+ else:
+ # No type given? "string" is the most sensible default.
+ self.type = "string"
+ else:
+ if self.type not in self.TYPES:
+ raise OptionError("invalid option type: %s" % (`self.type`,), self)
+ if self.action not in self.TYPED_ACTIONS:
+ raise OptionError(
+ "must not supply a type for action %s" % (`self.action`,), self)
+
+ def _check_choice(self):
+ if self.type == "choice":
+ if self.choices is None:
+ raise OptionError(
+ "must supply a list of choices for type 'choice'", self)
+ elif type(self.choices) not in (TupleType, ListType):
+ raise OptionError(
+ "choices must be a list of strings ('%s' supplied)"
+ % string.split(str(type(self.choices)),"'")[1], self)
+ elif self.choices is not None:
+ raise OptionError(
+ "must not supply choices for type %s" % (repr(self.type),), self)
+
+ def _check_dest (self):
+ if self.action in self.STORE_ACTIONS and self.dest is None:
+ # No destination given, and we need one for this action.
+ # Glean a destination from the first long option string,
+ # or from the first short option string if no long options.
+ if self._long_opts:
+ # eg. "--foo-bar" -> "foo_bar"
+ self.dest = string.replace(self._long_opts[0][2:],'-', '_')
+ else:
+ self.dest = self._short_opts[0][1]
+
+ def _check_const (self):
+ if self.action != "store_const" and self.const is not None:
+ raise OptionError(
+ "'const' must not be supplied for action %s" % (repr(self.action),),
+ self)
+
+ def _check_nargs (self):
+ if self.action in self.TYPED_ACTIONS:
+ if self.nargs is None:
+ self.nargs = 1
+ elif self.nargs is not None:
+ raise OptionError(
+ "'nargs' must not be supplied for action %s" % (repr(self.action),),
+ self)
+
+ def _check_callback (self):
+ if self.action == "callback":
+ if not callable(self.callback):
+ raise OptionError(
+ "callback not callable: %s" % (repr(self.callback),), self)
+ if (self.callback_args is not None and
+ type(self.callback_args) is not TupleType):
+ raise OptionError(
+ "callback_args, if supplied, must be a tuple: not %s"
+ % (repr(self.callback_args),), self)
+ if (self.callback_kwargs is not None and
+ type(self.callback_kwargs) is not DictType):
+ raise OptionError(
+ "callback_kwargs, if supplied, must be a dict: not %s"
+ % (repr(self.callback_kwargs),), self)
+ else:
+ if self.callback is not None:
+ raise OptionError(
+ "callback supplied (%s) for non-callback option"
+ % (repr(self.callback),), self)
+ if self.callback_args is not None:
+ raise OptionError(
+ "callback_args supplied for non-callback option", self)
+ if self.callback_kwargs is not None:
+ raise OptionError(
+ "callback_kwargs supplied for non-callback option", self)
+
+
+ CHECK_METHODS = [_check_action,
+ _check_type,
+ _check_choice,
+ _check_dest,
+ _check_const,
+ _check_nargs,
+ _check_callback]
+
+
+ # -- Miscellaneous methods -----------------------------------------
+
+ def __str__ (self):
+ if self._short_opts or self._long_opts:
+ return string.join(self._short_opts + self._long_opts,"/")
+ else:
+ raise RuntimeError, "short_opts and long_opts both empty!"
+
+ def takes_value (self):
+ return self.type is not None
+
+
+ # -- Processing methods --------------------------------------------
+
+ def check_value (self, opt, value):
+ checker = self.TYPE_CHECKER.get(self.type)
+ if checker is None:
+ return value
+ else:
+ return checker(self, opt, value)
+
+ def process (self, opt, value, values, parser):
+
+ # First, convert the value(s) to the right type. Howl if any
+ # value(s) are bogus.
+ if value is not None:
+ if self.nargs == 1:
+ value = self.check_value(opt, value)
+ else:
+ def cv(v,check=self.check_value,o=opt):
+ return check(o,v)
+
+ value = tuple(map(cv,value))
+
+ # And then take whatever action is expected of us.
+ # This is a separate method to make life easier for
+ # subclasses to add new actions.
+ return self.take_action(
+ self.action, self.dest, opt, value, values, parser)
+
+ def take_action (self, action, dest, opt, value, values, parser):
+ if action == "store":
+ setattr(values, dest, value)
+ elif action == "store_const":
+ setattr(values, dest, self.const)
+ elif action == "store_true":
+ setattr(values, dest, 1)
+ elif action == "store_false":
+ setattr(values, dest, 0)
+ elif action == "append":
+ values.ensure_value(dest, []).append(value)
+ elif action == "count":
+ setattr(values, dest, values.ensure_value(dest, 0) + 1)
+ elif action == "callback":
+ args = self.callback_args or ()
+ kwargs = self.callback_kwargs or {}
+ apply( self.callback, (self, opt, value, parser,)+ args, kwargs)
+ elif action == "help":
+ parser.print_help()
+ sys.exit(0)
+ elif action == "version":
+ parser.print_version()
+ sys.exit(0)
+ else:
+ raise RuntimeError, "unknown action %s" % (repr(self.action),)
+
+ return 1
+
+# class Option
diff --git a/src/engine/SCons/Optik/option_parser.py b/src/engine/SCons/Optik/option_parser.py
new file mode 100644
index 0000000..ebe8336
--- /dev/null
+++ b/src/engine/SCons/Optik/option_parser.py
@@ -0,0 +1,661 @@
+"""optik.option_parser
+
+Provides the OptionParser and Values classes.
+"""
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+# Original Optik revision this is based on:
+__Optik_revision__ = "option_parser.py,v 1.38.2.1 2002/07/23 01:51:14 gward Exp"
+
+# Copyright (c) 2001 Gregory P. Ward. All rights reserved.
+# See the README.txt distributed with Optik for licensing terms.
+
+# created 2001/10/17, GPW (from optik.py)
+
+import sys, os
+import string
+import types
+from SCons.Optik.option import Option, NO_DEFAULT
+from SCons.Optik.errors import OptionConflictError, OptionValueError, BadOptionError
+
+def get_prog_name ():
+ return os.path.basename(sys.argv[0])
+
+
+SUPPRESS_HELP = "SUPPRESS"+"HELP"
+SUPPRESS_USAGE = "SUPPRESS"+"USAGE"
+
+class Values:
+
+ def __init__ (self, defaults=None):
+ if defaults:
+ for (attr, val) in defaults.items():
+ setattr(self, attr, val)
+
+
+ def _update_careful (self, dict):
+ """
+ Update the option values from an arbitrary dictionary, but only
+ use keys from dict that already have a corresponding attribute
+ in self. Any keys in dict without a corresponding attribute
+ are silently ignored.
+ """
+ for attr in dir(self):
+ if dict.has_key(attr):
+ dval = dict[attr]
+ if dval is not None:
+ setattr(self, attr, dval)
+
+ def _update_loose (self, dict):
+ """
+ Update the option values from an arbitrary dictionary,
+ using all keys from the dictionary regardless of whether
+ they have a corresponding attribute in self or not.
+ """
+ self.__dict__.update(dict)
+
+ def _update (self, dict, mode):
+ if mode == "careful":
+ self._update_careful(dict)
+ elif mode == "loose":
+ self._update_loose(dict)
+ else:
+ raise ValueError, "invalid update mode: %s" % (repr(mode),)
+
+ def read_module (self, modname, mode="careful"):
+ __import__(modname)
+ mod = sys.modules[modname]
+ self._update(vars(mod), mode)
+
+ def read_file (self, filename, mode="careful"):
+ vars = {}
+ execfile(filename, vars)
+ self._update(vars, mode)
+
+ def ensure_value (self, attr, value):
+ if not hasattr(self, attr) or getattr(self, attr) is None:
+ setattr(self, attr, value)
+ return getattr(self, attr)
+
+
+class OptionParser:
+ """
+ Class attributes:
+ standard_option_list : [Option]
+ list of standard options that will be accepted by all instances
+ of this parser class (intended to be overridden by subclasses).
+
+ Instance attributes:
+ usage : string
+ a usage string for your program. Before it is displayed
+ to the user, "%prog" will be expanded to the name of
+ your program (os.path.basename(sys.argv[0])).
+ option_list : [Option]
+ the list of all options accepted on the command-line of
+ this program
+ _short_opt : { string : Option }
+ dictionary mapping short option strings, eg. "-f" or "-X",
+ to the Option instances that implement them. If an Option
+ has multiple short option strings, it will appears in this
+ dictionary multiple times.
+ _long_opt : { string : Option }
+ dictionary mapping long option strings, eg. "--file" or
+ "--exclude", to the Option instances that implement them.
+ Again, a given Option can occur multiple times in this
+ dictionary.
+ defaults : { string : any }
+ dictionary mapping option destination names to default
+ values for each destination.
+
+ allow_interspersed_args : boolean = true
+ if true, positional arguments may be interspersed with options.
+ Assuming -a and -b each take a single argument, the command-line
+ -ablah foo bar -bboo baz
+ will be interpreted the same as
+ -ablah -bboo -- foo bar baz
+ If this flag were false, that command line would be interpreted as
+ -ablah -- foo bar -bboo baz
+ -- ie. we stop processing options as soon as we see the first
+ non-option argument. (This is the tradition followed by
+ Python's getopt module, Perl's Getopt::Std, and other argument-
+ parsing libraries, but it is generally annoying to users.)
+
+ rargs : [string]
+ the argument list currently being parsed. Only set when
+ parse_args() is active, and continually trimmed down as
+ we consume arguments. Mainly there for the benefit of
+ callback options.
+ largs : [string]
+ the list of leftover arguments that we have skipped while
+ parsing options. If allow_interspersed_args is false, this
+ list is always empty.
+ values : Values
+ the set of option values currently being accumulated. Only
+ set when parse_args() is active. Also mainly for callbacks.
+
+ Because of the 'rargs', 'largs', and 'values' attributes,
+ OptionParser is not thread-safe. If, for some perverse reason, you
+ need to parse command-line arguments simultaneously in different
+ threads, use different OptionParser instances.
+
+ """
+
+ standard_option_list = []
+
+
+ def __init__ (self,
+ usage=None,
+ option_list=None,
+ option_class=Option,
+ version=None,
+ conflict_handler="error"):
+ self.set_usage(usage)
+ self.option_class = option_class
+ self.version = version
+ self.set_conflict_handler(conflict_handler)
+ self.allow_interspersed_args = 1
+
+ # Create the various lists and dicts that constitute the
+ # "option list". See class docstring for details about
+ # each attribute.
+ self._create_option_list()
+
+ # Populate the option list; initial sources are the
+ # standard_option_list class attribute, the 'option_list'
+ # argument, and the STD_VERSION_OPTION global (if 'version'
+ # supplied).
+ self._populate_option_list(option_list)
+
+ self._init_parsing_state()
+
+ # -- Private methods -----------------------------------------------
+ # (used by the constructor)
+
+ def _create_option_list (self):
+ self.option_list = []
+ self._short_opt = {} # single letter -> Option instance
+ self._long_opt = {} # long option -> Option instance
+ self.defaults = {} # maps option dest -> default value
+
+ def _populate_option_list (self, option_list):
+ if self.standard_option_list:
+ self.add_options(self.standard_option_list)
+ if option_list:
+ self.add_options(option_list)
+
+ def _init_parsing_state (self):
+ # These are set in parse_args() for the convenience of callbacks.
+ self.rargs = None
+ self.largs = None
+ self.values = None
+
+
+ # -- Simple modifier methods ---------------------------------------
+
+ def set_usage (self, usage):
+ if usage is None:
+ self.usage = "usage: %prog [options]"
+ elif usage is SUPPRESS_USAGE:
+ self.usage = None
+ else:
+ self.usage = usage
+
+ def enable_interspersed_args (self):
+ self.allow_interspersed_args = 1
+
+ def disable_interspersed_args (self):
+ self.allow_interspersed_args = 0
+
+ def set_conflict_handler (self, handler):
+ if handler not in ("ignore", "error", "resolve"):
+ raise ValueError, "invalid conflict_resolution value %s" % (repr(handler),)
+ self.conflict_handler = handler
+
+ def set_default (self, dest, value):
+ self.defaults[dest] = value
+
+ def set_defaults (self, **kwargs):
+ self.defaults.update(kwargs)
+
+ def get_default_values(self):
+ return Values(self.defaults)
+
+
+ # -- Option-adding methods -----------------------------------------
+
+ def _check_conflict (self, option):
+ conflict_opts = []
+ for opt in option._short_opts:
+ if self._short_opt.has_key(opt):
+ conflict_opts.append((opt, self._short_opt[opt]))
+ for opt in option._long_opts:
+ if self._long_opt.has_key(opt):
+ conflict_opts.append((opt, self._long_opt[opt]))
+
+ if conflict_opts:
+ handler = self.conflict_handler
+ if handler == "ignore": # behaviour for Optik 1.0, 1.1
+ pass
+ elif handler == "error": # new in 1.2
+ raise OptionConflictError(
+ "conflicting option string(s): %s"
+ % string.join( map( lambda x: x[0], conflict_opts),", "),
+ option)
+ elif handler == "resolve": # new in 1.2
+ for (opt, c_option) in conflict_opts:
+ if len(opt)>2 and opt[:2]=="--":
+ c_option._long_opts.remove(opt)
+ del self._long_opt[opt]
+ else:
+ c_option._short_opts.remove(opt)
+ del self._short_opt[opt]
+ if not (c_option._short_opts or c_option._long_opts):
+ self.option_list.remove(c_option)
+
+
+ def add_option (self, *args, **kwargs):
+ """add_option(Option)
+ add_option(opt_str, ..., kwarg=val, ...)
+ """
+ if type(args[0]) is types.StringType:
+ option = apply(self.option_class,args, kwargs)
+ elif len(args) == 1 and not kwargs:
+ option = args[0]
+ if not isinstance(option, Option):
+ raise TypeError, "not an Option instance: %s" % (repr(option),)
+ else:
+ raise TypeError, "invalid arguments"
+
+ self._check_conflict(option)
+
+ self.option_list.append(option)
+ for opt in option._short_opts:
+ self._short_opt[opt] = option
+ for opt in option._long_opts:
+ self._long_opt[opt] = option
+
+ if option.dest is not None: # option has a dest, we need a default
+ if option.default is not NO_DEFAULT:
+ self.defaults[option.dest] = option.default
+ elif not self.defaults.has_key(option.dest):
+ self.defaults[option.dest] = None
+
+ def add_options (self, option_list):
+ for option in option_list:
+ self.add_option(option)
+
+
+ # -- Option query/removal methods ----------------------------------
+
+ def get_option (self, opt_str):
+ return (self._short_opt.get(opt_str) or
+ self._long_opt.get(opt_str))
+
+ def has_option (self, opt_str):
+ return (self._short_opt.has_key(opt_str) or
+ self._long_opt.has_key(opt_str))
+
+
+ def remove_option (self, opt_str):
+ option = self._short_opt.get(opt_str)
+ if option is None:
+ option = self._long_opt.get(opt_str)
+ if option is None:
+ raise ValueError("no such option %s" % (repr(opt_str),))
+
+ for opt in option._short_opts:
+ del self._short_opt[opt]
+ for opt in option._long_opts:
+ del self._long_opt[opt]
+ self.option_list.remove(option)
+
+
+ # -- Option-parsing methods ----------------------------------------
+
+ def _get_args (self, args):
+ if args is None:
+ return sys.argv[1:]
+ else:
+ return args[:] # don't modify caller's list
+
+ def parse_args (self, args=None, values=None):
+ """
+ parse_args(args : [string] = sys.argv[1:],
+ values : Values = None)
+ -> (values : Values, args : [string])
+
+ Parse the command-line options found in 'args' (default:
+ sys.argv[1:]). Any errors result in a call to 'error()', which
+ by default prints the usage message to stderr and calls
+ sys.exit() with an error message. On success returns a pair
+ (values, args) where 'values' is an Values instance (with all
+ your option values) and 'args' is the list of arguments left
+ over after parsing options.
+ """
+ rargs = self._get_args(args)
+ if values is None:
+ values = self.get_default_values()
+
+ # Store the halves of the argument list as attributes for the
+ # convenience of callbacks:
+ # rargs
+ # the rest of the command-line (the "r" stands for
+ # "remaining" or "right-hand")
+ # largs
+ # the leftover arguments -- ie. what's left after removing
+ # options and their arguments (the "l" stands for "leftover"
+ # or "left-hand")
+ self.rargs = rargs
+ self.largs = largs = []
+ self.values = values
+
+ try:
+ stop = self._process_args(largs, rargs, values)
+ except (BadOptionError, OptionValueError), err:
+ self.error(err.msg)
+
+ args = largs + rargs
+ return self.check_values(values, args)
+
+ def check_values (self, values, args):
+ """
+ check_values(values : Values, args : [string])
+ -> (values : Values, args : [string])
+
+ Check that the supplied option values and leftover arguments are
+ valid. Returns the option values and leftover arguments
+ (possibly adjusted, possibly completely new -- whatever you
+ like). Default implementation just returns the passed-in
+ values; subclasses may override as desired.
+ """
+ return (values, args)
+
+ def _process_args (self, largs, rargs, values):
+ """_process_args(largs : [string],
+ rargs : [string],
+ values : Values)
+
+ Process command-line arguments and populate 'values', consuming
+ options and arguments from 'rargs'. If 'allow_interspersed_args' is
+ false, stop at the first non-option argument. If true, accumulate any
+ interspersed non-option arguments in 'largs'.
+ """
+ while rargs:
+ arg = rargs[0]
+ # We handle bare "--" explicitly, and bare "-" is handled by the
+ # standard arg handler since the short arg case ensures that the
+ # len of the opt string is greater than 1.
+ if arg == "--":
+ del rargs[0]
+ return
+ elif arg[0:2] == "--":
+ # process a single long option (possibly with value(s))
+ self._process_long_opt(rargs, values)
+ elif arg[:1] == "-" and len(arg) > 1:
+ # process a cluster of short options (possibly with
+ # value(s) for the last one only)
+ self._process_short_opts(rargs, values)
+ elif self.allow_interspersed_args:
+ largs.append(arg)
+ del rargs[0]
+ else:
+ return # stop now, leave this arg in rargs
+
+ # Say this is the original argument list:
+ # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
+ # ^
+ # (we are about to process arg(i)).
+ #
+ # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of
+ # [arg0, ..., arg(i-1)] (any options and their arguments will have
+ # been removed from largs).
+ #
+ # The while loop will usually consume 1 or more arguments per pass.
+ # If it consumes 1 (eg. arg is an option that takes no arguments),
+ # then after _process_arg() is done the situation is:
+ #
+ # largs = subset of [arg0, ..., arg(i)]
+ # rargs = [arg(i+1), ..., arg(N-1)]
+ #
+ # If allow_interspersed_args is false, largs will always be
+ # *empty* -- still a subset of [arg0, ..., arg(i-1)], but
+ # not a very interesting subset!
+
+ def _match_long_opt (self, opt):
+ """_match_long_opt(opt : string) -> string
+
+ Determine which long option string 'opt' matches, ie. which one
+ it is an unambiguous abbrevation for. Raises BadOptionError if
+ 'opt' doesn't unambiguously match any long option string.
+ """
+ return _match_abbrev(opt, self._long_opt)
+
+ def _process_long_opt (self, rargs, values):
+ arg = rargs.pop(0)
+
+ # Value explicitly attached to arg? Pretend it's the next
+ # argument.
+ if "=" in arg:
+ (opt, next_arg) = string.split(arg,"=", 1)
+ rargs.insert(0, next_arg)
+ had_explicit_value = 1
+ else:
+ opt = arg
+ had_explicit_value = 0
+
+ opt = self._match_long_opt(opt)
+ option = self._long_opt[opt]
+ if option.takes_value():
+ nargs = option.nargs
+ if len(rargs) < nargs:
+ if nargs == 1:
+ self.error("%s option requires a value" % opt)
+ else:
+ self.error("%s option requires %d values"
+ % (opt, nargs))
+ elif nargs == 1:
+ value = rargs.pop(0)
+ else:
+ value = tuple(rargs[0:nargs])
+ del rargs[0:nargs]
+
+ elif had_explicit_value:
+ self.error("%s option does not take a value" % opt)
+
+ else:
+ value = None
+
+ option.process(opt, value, values, self)
+
+ def _process_short_opts (self, rargs, values):
+ arg = rargs.pop(0)
+ stop = 0
+ i = 1
+ for ch in arg[1:]:
+ opt = "-" + ch
+ option = self._short_opt.get(opt)
+ i = i+1 # we have consumed a character
+
+ if not option:
+ self.error("no such option: %s" % opt)
+ if option.takes_value():
+ # Any characters left in arg? Pretend they're the
+ # next arg, and stop consuming characters of arg.
+ if i < len(arg):
+ rargs.insert(0, arg[i:])
+ stop = 1
+
+ nargs = option.nargs
+ if len(rargs) < nargs:
+ if nargs == 1:
+ self.error("%s option requires a value" % opt)
+ else:
+ self.error("%s option requires %s values"
+ % (opt, nargs))
+ elif nargs == 1:
+ value = rargs.pop(0)
+ else:
+ value = tuple(rargs[0:nargs])
+ del rargs[0:nargs]
+
+ else: # option doesn't take a value
+ value = None
+
+ option.process(opt, value, values, self)
+
+ if stop:
+ break
+
+
+ # -- Output/error methods ------------------------------------------
+
+ def error (self, msg):
+ """error(msg : string)
+
+ Print a usage message incorporating 'msg' to stderr and exit.
+ If you override this in a subclass, it should not return -- it
+ should either exit or raise an exception.
+ """
+ self.print_usage(sys.stderr)
+ sys.stderr.write("\nSCons error: %s\n" % msg)
+ sys.exit(2)
+
+ def print_usage (self, file=None):
+ """print_usage(file : file = stdout)
+
+ Print the usage message for the current program (self.usage) to
+ 'file' (default stdout). Any occurence of the string "%prog" in
+ self.usage is replaced with the name of the current program
+ (basename of sys.argv[0]). Does nothing if self.usage is empty
+ or not defined.
+ """
+ if file is None:
+ file = sys.stdout
+ if self.usage:
+ usage = string.replace(self.usage,"%prog", get_prog_name())
+ file.write(usage + "\n")
+
+ def print_version (self, file=None):
+ """print_version(file : file = stdout)
+
+ Print the version message for this program (self.version) to
+ 'file' (default stdout). As with print_usage(), any occurence
+ of "%prog" in self.version is replaced by the current program's
+ name. Does nothing if self.version is empty or undefined.
+ """
+ if file is None:
+ file = sys.stdout
+ if self.version:
+ version = string.replace(self.version,"%prog", get_prog_name())
+ file.write(version+"\n")
+
+ def print_help (self, file=None):
+ """print_help(file : file = stdout)
+
+ Print an extended help message, listing all options and any
+ help text provided with them, to 'file' (default stdout).
+ """
+ from distutils.fancy_getopt import wrap_text
+
+ if file is None:
+ file = sys.stdout
+
+ self.print_usage(file)
+
+ # The help for each option consists of two parts:
+ # * the opt strings and metavars
+ # eg. ("-x", or "-fFILENAME, --file=FILENAME")
+ # * the user-supplied help string
+ # eg. ("turn on expert mode", "read data from FILENAME")
+ #
+ # If possible, we write both of these on the same line:
+ # -x turn on expert mode
+ #
+ # But if the opt string list is too long, we put the help
+ # string on a second line, indented to the same column it would
+ # start in if it fit on the first line.
+ # -fFILENAME, --file=FILENAME
+ # read data from FILENAME
+
+ file.write("Options:\n")
+ width = 78 # assume 80 cols for now
+
+ option_help = [] # list of (string, string) tuples
+ lengths = []
+
+ for option in self.option_list:
+ takes_value = option.takes_value()
+ if takes_value:
+ metavar = option.metavar or string.upper(option.dest)
+
+ opts = [] # list of "-a" or "--foo=FILE" strings
+ if option.help is SUPPRESS_HELP:
+ continue
+
+ if takes_value:
+ for sopt in option._short_opts:
+ opts.append(sopt + ' ' + metavar)
+ for lopt in option._long_opts:
+ opts.append(lopt + "=" + metavar)
+ else:
+ for opt in option._short_opts + option._long_opts:
+ opts.append(opt)
+
+ opts = string.join(opts,", ")
+ option_help.append((opts, option.help))
+ lengths.append(len(opts))
+
+ max_opts = min(max(lengths), 26)
+
+ for (opts, help) in option_help:
+ # how much to indent lines 2 .. N of help text
+ indent_rest = 2 + max_opts + 2
+ help_width = width - indent_rest
+
+ if len(opts) > max_opts:
+ opts = " " + opts + "\n"
+ indent_first = indent_rest
+ else: # start help on same line as opts
+ opts = " %-*s " % (max_opts, opts)
+ indent_first = 0
+
+ file.write(opts)
+
+ if help:
+ help_lines = wrap_text(help, help_width)
+ file.write( "%*s%s\n" % (indent_first, "", help_lines[0]))
+ for line in help_lines[1:]:
+ file.write(" %*s%s\n" % (indent_rest, "", line))
+ elif opts[-1] != "\n":
+ file.write("\n")
+
+# class OptionParser
+
+
+def _match_abbrev (s, wordmap):
+ """_match_abbrev(s : string, wordmap : {string : Option}) -> string
+
+ Return the string key in 'wordmap' for which 's' is an unambiguous
+ abbreviation. If 's' is found to be ambiguous or doesn't match any of
+ 'words', raise BadOptionError.
+ """
+ # Is there an exact match?
+ if wordmap.has_key(s):
+ return s
+ else:
+ # Isolate all words with s as a prefix.
+ possibilities = []
+ ls = len(s)
+ for word in wordmap.keys():
+ if len(word)>=ls and word[:ls]==s:
+ possibilities.append(word)
+ # No exact match, so there had better be just one possibility.
+ if len(possibilities) == 1:
+ return possibilities[0]
+ elif not possibilities:
+ raise BadOptionError("no such option: %s" % s)
+ else:
+ # More than one possible completion: ambiguous prefix.
+ raise BadOptionError("ambiguous option: %s (%s?)"
+ % (s, string.join(possibilities,", ")))
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index 1403724..bc6451c 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -39,7 +39,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import time
start_time = time.time()
-import getopt
import os
import os.path
import string
@@ -65,6 +64,7 @@ from SCons.Taskmaster import Taskmaster
import SCons.Builder
import SCons.Script.SConscript
import SCons.Warnings
+from SCons.Optik import OptionParser, SUPPRESS_HELP, OptionValueError
#
@@ -99,9 +99,9 @@ class BuildTask(SCons.Taskmaster.Task):
# don't try to walk the stack, just print the error.
sys.stderr.write("\nSCons error: %s\n" % e)
raise
- except:
- sys.stderr.write("scons: *** %s\n" % sys.exc_value)
- raise
+ except:
+ sys.stderr.write("scons: *** %s\n" % sys.exc_value)
+ raise
def executed(self):
SCons.Taskmaster.Task.executed(self)
@@ -110,9 +110,9 @@ class BuildTask(SCons.Taskmaster.Task):
if print_tree and self.top:
print
print SCons.Util.render_tree(self.targets[0], get_all_children)
- if print_dtree and self.top:
- print
- print SCons.Util.render_tree(self.targets[0], get_derived_children)
+ if print_dtree and self.top:
+ print
+ print SCons.Util.render_tree(self.targets[0], get_derived_children)
def failed(self):
global exit_status
@@ -157,29 +157,18 @@ class QuestionTask(SCons.Taskmaster.Task):
# Global variables
-include_dirs = []
-num_jobs = 1
-scripts = []
-task_class = BuildTask # default action is to build targets
-current_func = None
-calc = None
-ignore_errors = 0
keep_going_on_error = 0
-help_option = None
print_tree = 0
print_dtree = 0
print_time = 0
+ignore_errors = 0
sconscript_time = 0
command_time = 0
-climb_up = 0
-target_top = None
exit_status = 0 # exit status, assume success by default
profiling = 0
-max_drift = None
repositories = []
sig_module = None
-#
def print_it(text):
print text
@@ -264,583 +253,55 @@ def _scons_other_errors():
traceback.print_exc()
sys.exit(2)
-
-#
-# After options are initialized, the following variables are
-# filled in:
-#
-option_list = [] # list of Option objects
-short_opts = "" # string of short (single-character) options
-long_opts = [] # array of long (--) options
-opt_func = {} # mapping of option strings to functions
-
-def options_init():
- """Initialize command-line options processing.
-
- This is in a subroutine mainly so we can easily single-step over
- it in the debugger.
- """
-
- class Option:
- """Class for command-line option information.
-
- This exists to provide a central location for everything
- describing a command-line option, so that we can change
- options without having to update the code to handle the
- option in one place, the -H help message in another place,
- etc. There are no methods here, only attributes.
-
- You can initialize an Option with the following:
-
- func The function that will be called when this
- option is processed on the command line.
- Calling sequence is:
-
- func(opt, arg)
-
- If there is no func, then this Option probably
- stores an optstring to be printed.
-
- helpline
- The string to be printed in -H output. If no
- helpline is specified but a help string is
- specified (the usual case), a helpline will be
- constructed automatically from the short, long,
- arg, and help attributes. (In practice, then,
- setting helpline without setting func allows you
- to print arbitrary lines of text in the -H
- output.)
-
- short The string for short, single-hyphen
- command-line options.
- Do not include the hyphen:
-
- 'a' for -a, 'xy' for -x and -y, etc.
-
- long An array of strings for long, double-hyphen
- command-line options. Do not include
- the initial hyphens:
-
- ['my-option', 'verbose']
-
- arg If this option takes an argument, this string
- specifies how you want it to appear in the
- -H output ('DIRECTORY', 'FILE', etc.).
-
- help The help string that will be printed for
- this option in the -H output. Must be
- 49 characters or fewer.
-
- May be an array of strings, which will be
- printed on successive lines. The first string
- must be 49 characters or fewer. The remaining
- strings will be indented two spaces and must
- be 47 characters or fewer.
-
- future If non-zero, this indicates that this feature
- will be supported in a future release, not
- the currently planned one. SCons will
- recognize the option, but it won't show up
- in the -H output.
-
- The following attribute is derived from the supplied attributes:
-
- optstring
- A string, with hyphens, describing the flags
- for this option, as constructed from the
- specified short, long and arg attributes.
-
- All Option objects are stored in the global option_list list,
- in the order in which they're created. This is the list
- that's used to generate -H output, so the order in which the
- objects are created is the order in which they're printed.
-
- The upshot is that specifying a command-line option and having
- everything work correctly is a matter of defining a function to
- process its command-line argument (set the right flag, update
- the right value), and then creating an appropriate Option object
- at the correct point in the code below.
- """
-
- def __init__(self, func = None, helpline = None,
- short = None, long = None, arg = None,
- help = None, future = None):
- self.func = func
- self.short = short
- self.long = long
- self.arg = arg
- if not SCons.Util.is_List(help):
- help = [help]
- self.help = help
- opts = []
- if self.short:
- for c in self.short:
- if arg:
- c = c + " " + arg
- opts = opts + ['-' + c]
- if self.long:
- l = self.long
- if arg:
- l = map(lambda x,a=arg: x + "=" + a, self.long)
- opts = opts + map(lambda x: '--' + x, l)
- self.optstring = string.join(opts, ', ')
- if helpline:
- self.helpline = helpline
- elif help and not future:
- if len(self.optstring) <= 26:
- sep = " " * (28 - len(self.optstring))
- else:
- sep = self.helpstring = "\n" + " " * 30
- self.helpline = " " + self.optstring + sep + \
- string.join(self.help, "\n" + " " * 32)
- else:
- self.helpline = None
- global option_list
- option_list.append(self)
-
- # Generic routine for to-be-written options, used by multiple
- # options below.
-
- def opt_not_yet(opt, arg):
- sys.stderr.write("Warning: the %s option is not yet implemented\n"
- % opt)
-
- # In the following instantiations, the help string should be no
- # longer than 49 characters. Use the following as a guide:
- # help = "1234567890123456789012345678901234567890123456789"
-
- def opt_ignore(opt, arg):
- sys.stderr.write("Warning: ignoring %s option\n" % opt)
-
- Option(func = opt_ignore,
- short = 'bmSt', long = ['no-keep-going', 'stop', 'touch'],
- help = "Ignored for compatibility.")
-
- def opt_c(opt, arg):
- global task_class, calc
- task_class = CleanTask
- class CleanCalculator:
- def bsig(self, node):
- return None
- def csig(self, node):
- return None
- def current(self, node, sig):
- return 0
- def write(self):
- pass
- calc = CleanCalculator()
-
- Option(func = opt_c,
- short = 'c', long = ['clean', 'remove'],
- help = "Remove specified targets and dependencies.")
-
- Option(func = opt_not_yet, future = 1,
- long = ['cache-disable', 'no-cache'],
- help = "Do not retrieve built targets from Cache.")
-
- Option(func = opt_not_yet, future = 1,
- long = ['cache-force', 'cache-populate'],
- help = "Copy already-built targets into the Cache.")
-
- Option(func = opt_not_yet, future = 1,
- long = ['cache-show'],
- help = "Print what would have built Cached targets.")
-
- def opt_C(opt, arg):
- try:
- os.chdir(arg)
- except:
- sys.stderr.write("Could not change directory to 'arg'\n")
-
- Option(func = opt_C,
- short = 'C', long = ['directory'], arg = 'DIRECTORY',
- help = "Change to DIRECTORY before doing anything.")
-
- Option(func = opt_not_yet,
- short = 'd',
- help = "Print file dependency information.")
-
- def opt_D(opt, arg):
- global climb_up
- climb_up = 2
-
- Option(func = opt_D,
- short = 'D',
- help = ["Search up directory tree for SConstruct,",
- "build all Default() targets."])
-
- def opt_debug(opt, arg):
- global print_tree
- global print_dtree
- global print_time
- if arg == "pdb":
- args = [ sys.executable, "pdb.py" ] + \
- filter(lambda x: x != "--debug=pdb", sys.argv)
- if sys.platform == 'win32':
- args[1] = os.path.join(sys.prefix, "lib", "pdb.py")
- sys.exit(os.spawnve(os.P_WAIT, args[0], args, os.environ))
- else:
- args[1] = os.path.join(sys.prefix,
- "lib",
- "python" + sys.version[0:3],
- "pdb.py")
- os.execvpe(args[0], args, os.environ)
- elif arg == "tree":
- print_tree = 1
- elif arg == "dtree":
- print_dtree = 1
- elif arg == "time":
- print_time = 1
- else:
- sys.stderr.write("Warning: %s is not a valid debug type\n"
- % arg)
-
- Option(func = opt_debug,
- long = ['debug'], arg='TYPE',
- help = "Print various types of debugging information.")
-
- Option(func = opt_not_yet, future = 1,
- short = 'e', long = ['environment-overrides'],
- help = "Environment variables override makefiles.")
-
- def opt_f(opt, arg):
- global scripts
- scripts.append(arg)
-
- Option(func = opt_f,
- short = 'f', long = ['file', 'makefile', 'sconstruct'], arg = 'FILE',
- help = "Read FILE as the top-level SConstruct file.")
-
- def opt_help(opt, arg):
- global help_option
- help_option = 'h'
- def raisePrintHelp(text):
- raise PrintHelp, text
- SCons.Script.SConscript.HelpFunction = raisePrintHelp
-
- Option(func = opt_help,
- short = 'h', long = ['help'],
- help = "Print defined help message, or this one.")
-
- def opt_help_options(opt, arg):
- global help_option
- help_option = 'H'
-
- Option(func = opt_help_options,
- short = 'H', long = ['help-options'],
- help = "Print this message and exit.")
-
- def opt_i(opt, arg):
- global ignore_errors
- ignore_errors = 1
-
- Option(func = opt_i,
- short = 'i', long = ['ignore-errors'],
- help = "Ignore errors from build actions.")
-
- def opt_I(opt, arg):
- global include_dirs
- include_dirs = include_dirs + [arg]
-
- Option(func = opt_I,
- short = 'I', long = ['include-dir'], arg = 'DIRECTORY',
- help = "Search DIRECTORY for imported Python modules.")
-
- def opt_implicit_cache(opt, arg):
- import SCons.Node
- SCons.Node.implicit_cache = 1
-
- Option(func = opt_implicit_cache,
- long = ['implicit-cache'],
- help = "Cache implicit (scanned) dependencies.")
-
- def opt_implicit_deps_changed(opt, arg):
- import SCons.Node
- SCons.Node.implicit_cache = 1
- SCons.Node.implicit_deps_changed = 1
-
- Option(func = opt_implicit_deps_changed,
- long = ['implicit-deps-changed'],
- help = "Ignore the cached implicit dependencies.")
-
- def opt_implicit_deps_unchanged(opt, arg):
- import SCons.Node
- SCons.Node.implicit_cache = 1
- SCons.Node.implicit_deps_unchanged = 1
-
- Option(func = opt_implicit_deps_unchanged,
- long = ['implicit-deps-unchanged'],
- help = "Ignore changes in implicit dependencies.")
-
- def opt_j(opt, arg):
- global num_jobs
- try:
- num_jobs = int(arg)
- except:
- print UsageString()
- sys.exit(1)
-
- if num_jobs <= 0:
- print UsageString()
- sys.exit(1)
-
- Option(func = opt_j,
- short = 'j', long = ['jobs'], arg = 'N',
- help = "Allow N jobs at once.")
-
- def opt_k(opt, arg):
- global keep_going_on_error
- keep_going_on_error = 1
-
- Option(func = opt_k,
- short = 'k', long = ['keep-going'],
- help = "Keep going when a target can't be made.")
-
- Option(func = opt_not_yet, future = 1,
- short = 'l', long = ['load-average', 'max-load'], arg = 'N',
- help = "Don't start multiple jobs unless load is below N.")
-
- Option(func = opt_not_yet, future = 1,
- long = ['list-derived'],
- help = "Don't build; list files that would be built.")
-
- Option(func = opt_not_yet, future = 1,
- long = ['list-actions'],
- help = "Don't build; list files and build actions.")
-
- Option(func = opt_not_yet, future = 1,
- long = ['list-where'],
- help = "Don't build; list files and where defined.")
-
- def opt_max_drift(opt, arg):
- global max_drift
- try:
- max_drift = int(arg)
- except ValueError:
- raise UserError, "The argument for --max-drift must be an integer."
-
- Option(func = opt_max_drift,
- long = ['max-drift'],
- arg = 'SECONDS',
- help = "Set the maximum system clock drift to be SECONDS.")
-
- def opt_n(opt, arg):
- SCons.Action.execute_actions = None
- CleanTask.execute = CleanTask.show
-
- Option(func = opt_n,
- short = 'n', long = ['no-exec', 'just-print', 'dry-run', 'recon'],
- help = "Don't build; just print commands.")
-
- Option(func = opt_not_yet, future = 1,
- short = 'o', long = ['old-file', 'assume-old'], arg = 'FILE',
- help = "Consider FILE to be old; don't rebuild it.")
-
- Option(func = opt_not_yet, future = 1,
- long = ['override'], arg = 'FILE',
- help = "Override variables as specified in FILE.")
-
- Option(func = opt_not_yet, future = 1,
- short = 'p',
- help = "Print internal environments/objects.")
-
- def opt_profile(opt, arg):
- global profiling
- if not profiling:
- profiling = 1
- import profile
- profile.run('SCons.Script.main()', arg)
- sys.exit(exit_status)
-
- Option(func = opt_profile,
- long = ['profile'], arg = 'FILE',
- help = "Profile SCons and put results in FILE.")
-
- def opt_Q(opt, arg):
- global display
- def dont_print_it(text):
- pass
- display = dont_print_it
-
- Option(func = opt_Q,
- short = 'Q',
- help = "Don't print SCons progress messages.")
-
- def opt_q(opt, arg):
- global task_class
- task_class = QuestionTask
-
- Option(func = opt_q,
- short = 'q', long = ['question'],
- help = "Don't build; exit status says if up to date.")
-
- Option(func = opt_not_yet, future = 1,
- short = 'rR', long = ['no-builtin-rules', 'no-builtin-variables'],
- help = "Clear default environments and variables.")
-
- Option(func = opt_not_yet, future = 1,
- long = ['random'],
- help = "Build dependencies in random order.")
-
- def opt_s(opt, arg):
- global display
- def dont_print_it(text):
- pass
- display = dont_print_it
- SCons.Action.print_actions = None
-
- Option(func = opt_s,
- short = 's', long = ['silent', 'quiet'],
- help = "Don't print commands.")
-
- def opt_u(opt, arg):
- global climb_up
- climb_up = 1
-
- Option(func = opt_u,
- short = 'u', long = ['up', 'search-up'],
- help = ["Search up directory tree for SConstruct,",
- "build targets at or below current directory."])
-
- def opt_U(opt, arg):
- global climb_up
- climb_up = 3
-
- Option(func = opt_U,
- short = 'U',
- help = ["Search up directory tree for SConstruct,",
- "build Default() targets from local SConscript."])
-
- def option_v(opt, arg):
- import __main__
- import SCons
- print "SCons by Steven Knight et al.:"
- try:
- print "\tscript: v%s.%s, %s, by %s on %s" % (__main__.__version__,
- __main__.__build__,
- __main__.__date__,
- __main__.__developer__,
- __main__.__buildsys__)
- except:
- # On win32 there is no scons.py, so there is no __main__.__version__,
- # hence there is no script version.
- pass
- print "\tengine: v%s.%s, %s, by %s on %s" % (SCons.__version__,
- SCons.__build__,
- SCons.__date__,
- SCons.__developer__,
- SCons.__buildsys__)
- print "Copyright 2001, 2002 Steven Knight"
- sys.exit(0)
-
- Option(func = option_v,
- short = 'v', long = ['version'],
- help = "Print the SCons version number and exit.")
-
- Option(func = opt_not_yet, future = 1,
- short = 'w', long = ['print-directory'],
- help = "Print the current directory.")
-
- Option(func = opt_not_yet, future = 1,
- long = ['no-print-directory'],
- help = "Turn off -w, even if it was turned on implicitly.")
-
- Option(func = opt_not_yet, future = 1,
- long = ['write-filenames'], arg = 'FILE',
- help = "Write all filenames examined into FILE.")
-
- Option(func = opt_not_yet, future = 1,
- short = 'W', long = ['what-if', 'new-file', 'assume-new'], arg = 'FILE',
- help = "Consider FILE to be changed.")
-
- def opt_warn(opt, arg):
- """The --warn option. An argument to this option
- should be of the form <warning-class> or no-<warning-class>.
- The warning class is munged in order to get an actual class
- name from the SCons.Warnings module to enable or disable.
- The supplied <warning-class> is split on hyphens, each element
- is captialized, then smushed back together. Then the string
- "SCons.Warnings." is added to the front and "Warning" is added
- to the back to get the fully qualified class name.
-
- For example, --warn=deprecated will enable the
- SCons.Warnings.DeprecatedWarning class.
-
- --warn=no-dependency will disable the
- SCons.Warnings.DependencyWarning class.
-
- As a special case, --warn=all and --warn=no-all
- will enable or disable (respectively) the base
- class of all warnings, which is SCons.Warning.Warning."""
-
- elems = string.split(string.lower(arg), '-')
- enable = 1
- if elems[0] == 'no':
- enable = 0
- del elems[0]
-
- if len(elems) == 1 and elems[0] == 'all':
- class_name = "Warning"
- else:
- class_name = string.join(map(string.capitalize, elems), '') + \
- "Warning"
- try:
- clazz = getattr(SCons.Warnings, class_name)
- except AttributeError:
- sys.stderr.write("No warning type: '%s'\n" % arg)
+def _varargs(option, parser):
+ value = None
+ if parser.rargs:
+ arg = parser.rargs[0]
+ if arg[0] != "-":
+ value = arg
+ del parser.rargs[0]
+ return value
+
+def _setup_warn(arg):
+ """The --warn option. An argument to this option
+ should be of the form <warning-class> or no-<warning-class>.
+ The warning class is munged in order to get an actual class
+ name from the SCons.Warnings module to enable or disable.
+ The supplied <warning-class> is split on hyphens, each element
+ is captialized, then smushed back together. Then the string
+ "SCons.Warnings." is added to the front and "Warning" is added
+ to the back to get the fully qualified class name.
+
+ For example, --warn=deprecated will enable the
+ SCons.Warnings.DeprecatedWarning class.
+
+ --warn=no-dependency will disable the
+ SCons.Warnings.DependencyWarning class.
+
+ As a special case, --warn=all and --warn=no-all
+ will enable or disable (respectively) the base
+ class of all warnings, which is SCons.Warning.Warning."""
+
+ elems = string.split(string.lower(arg), '-')
+ enable = 1
+ if elems[0] == 'no':
+ enable = 0
+ del elems[0]
+
+ if len(elems) == 1 and elems[0] == 'all':
+ class_name = "Warning"
+ else:
+ class_name = string.join(map(string.capitalize, elems), '') + \
+ "Warning"
+ try:
+ clazz = getattr(SCons.Warnings, class_name)
+ except AttributeError:
+ sys.stderr.write("No warning type: '%s'\n" % arg)
+ else:
+ if enable:
+ SCons.Warnings.enableWarningClass(clazz)
else:
- if enable:
- SCons.Warnings.enableWarningClass(clazz)
- else:
- SCons.Warnings.suppressWarningClass(clazz)
-
- Option(func = opt_warn,
- long = [ 'warn', 'warning' ], arg='WARNING-SPEC',
- help = "Enable or disable warnings.")
-
-
- # We want to preserve the --warn-undefined-variables option for
- # compatibility with GNU Make. Unfortunately, this conflicts with
- # the --warn=type option that we're using for our own warning
- # control. The getopt module reports "--warn not a unique prefix"
- # when both are defined. We may be able to support both in the
- # future with a more robust getopt solution.
- #
- #Option(func = opt_not_yet, future = 1,
- # long = ['warn-undefined-variables'],
- # help = "Warn when an undefined variable is referenced.")
-
- def opt_Y(opt, arg):
- global repositories
- repositories.append(arg)
-
- Option(func = opt_Y,
- short = 'Y', long = ['repository'], arg = 'REPOSITORY',
- help = "Search REPOSITORY for source and target files.")
-
- global short_opts
- global long_opts
- global opt_func
- for o in option_list:
- if o.short:
- if o.func:
- for c in o.short:
- opt_func['-' + c] = o.func
- short_opts = short_opts + o.short
- if o.arg:
- short_opts = short_opts + ":"
- if o.long:
- if o.func:
- for l in o.long:
- opt_func['--' + l] = o.func
- if o.arg:
- long_opts = long_opts + map(lambda a: a + "=", o.long)
- else:
- long_opts = long_opts + o.long
-
-options_init()
-
-
+ SCons.Warnings.suppressWarningClass(clazz)
def _SConstruct_exists(dirname=''):
"""This function checks that an SConstruct file exists in a directory.
@@ -858,60 +319,343 @@ def _SConstruct_exists(dirname=''):
return sfile
return None
+def _set_globals(options):
+ global repositories, keep_going_on_error, print_tree, print_dtree
+ global print_time, ignore_errors
+
+ if options.repository:
+ repositories.extend(options.repository)
+ keep_going_on_error = options.keep_going
+ try:
+ if options.debug:
+ if options.debug == "tree":
+ print_tree = 1
+ elif options.debug == "dtree":
+ print_dtree = 1
+ elif options.debug == "time":
+ print_time = 1
+ except AttributeError:
+ pass
+ ignore_errors = options.ignore_errors
+
+def _create_path(plist):
+ path = '.'
+ for d in plist:
+ if os.path.isabs(d):
+ path = d
+ else:
+ path = path + '/' + d
+ return path
-def UsageString():
- help_opts = filter(lambda x: x.helpline, option_list)
- s = "Usage: scons [OPTION] [TARGET] ...\n" + "Options:\n" + \
- string.join(map(lambda x: x.helpline, help_opts), "\n") + "\n"
- return s
+class OptParser(OptionParser):
+ def __init__(self):
+ import __main__
+ import SCons
+ parts = ["SCons by Steven Knight et al.:\n"]
+ try:
+ parts.append("\tscript: v%s.%s, %s, by %s on %s\n" % (__main__.__version__,
+ __main__.__build__,
+ __main__.__date__,
+ __main__.__developer__,
+ __main__.__buildsys__))
+ except:
+ # On win32 there is no scons.py, so there is no __main__.__version__,
+ # hence there is no script version.
+ pass
+ parts.append("\tengine: v%s.%s, %s, by %s on %s\n" % (SCons.__version__,
+ SCons.__build__,
+ SCons.__date__,
+ SCons.__developer__,
+ SCons.__buildsys__))
+ parts.append("Copyright 2001, 2002 Steven Knight")
+ OptionParser.__init__(self, version=string.join(parts, ''),
+ usage="usage: scons [OPTION] [TARGET] ...")
+
+ # options ignored for compatibility
+ def opt_ignore(option, opt, value, parser):
+ sys.stderr.write("Warning: ignoring %s option\n" % opt)
+ self.add_option("-b", "-m", "-S", "-t", "--no-keep-going", "--stop",
+ "--touch", action="callback", callback=opt_ignore,
+ help="Ignored for compatibility.")
+
+ def opt_c(option, opt, value, parser):
+ setattr(parser.values, 'clean', 1)
+ self.add_option('-c', '--clean', '--remove', action="callback",
+ callback=opt_c,
+ help="Remove specified targets and dependencies.")
+
+ self.add_option('-C', '--directory', type="string", action = "append",
+ help="Change to DIRECTORY before doing anything.")
+
+ def opt_not_yet(option, opt, value, parser):
+ sys.stderr.write("Warning: the %s option is not yet implemented\n" % opt)
+ sys.exit(0)
+ self.add_option('-d', action="callback",
+ callback=opt_not_yet,
+ help = "Print file dependency information.")
+
+ self.add_option('-D', action="store_const", const=2, dest="climb_up",
+ help="Search up directory tree for SConstruct, "
+ "build all Default() targets.")
+
+ def opt_debug(option, opt, value, parser):
+ if value == "pdb":
+ args = [ sys.executable, "pdb.py" ] + \
+ filter(lambda x: x != "--debug=pdb", sys.argv)
+ if sys.platform == 'win32':
+ args[1] = os.path.join(sys.prefix, "lib", "pdb.py")
+ sys.exit(os.spawnve(os.P_WAIT, args[0], args, os.environ))
+ else:
+ args[1] = os.path.join(sys.prefix,
+ "lib",
+ "python" + sys.version[0:3],
+ "pdb.py")
+ os.execvpe(args[0], args, os.environ)
+ elif value in ["tree", "dtree", "time"]:
+ setattr(parser.values, 'debug', value)
+ else:
+ raise OptionValueError("Warning: %s is not a valid debug type" % value)
+ self.add_option('--debug', action="callback", type="string",
+ callback=opt_debug, nargs=1, dest="debug",
+ help="Print various types of debugging information.")
+
+ self.add_option('-f', '--file', '--makefile', '--sconstruct',
+ action="append", nargs=1,
+ help="Read FILE as the top-level SConstruct file.")
+
+ self.add_option('-h', '--help', action="store_true", default=0,
+ dest="help_msg",
+ help="Print defined help message, or this one.")
+
+ self.add_option("-H", "--help-options",
+ action="help",
+ help="Print this message and exit.")
+
+ self.add_option('-i', '--ignore-errors', action="store_true",
+ default=0, dest='ignore_errors',
+ help="Ignore errors from build actions.")
+
+ self.add_option('-I', '--include-dir', action="append",
+ dest='include_dir', metavar="DIRECTORY",
+ help="Search DIRECTORY for imported Python modules.")
+
+ self.add_option('--implicit-cache', action="store_true", default=0,
+ dest='implicit_cache',
+ help="Cache implicit dependencies")
+
+ self.add_option('--implicit-deps-changed', action="store_true",
+ default=0, dest='implicit_deps_changed',
+ help="Ignore the cached implicit deps.")
+ self.add_option('--implicit-deps-unchanged', action="store_true",
+ default=0, dest='implicit_deps_unchanged',
+ help="Ignore changes in implicit deps.")
+
+ def opt_j(option, opt, value, parser):
+ value = int(value)
+ setattr(parser.values, 'num_jobs', value)
+ self.add_option('-j', '--jobs', action="callback", type="int",
+ callback=opt_j, metavar="N",
+ help="Allow N jobs at once.")
+
+ self.add_option('-k', '--keep-going', action="store_true", default=0,
+ dest='keep_going',
+ help="Keep going when a target can't be made.")
+
+ self.add_option('--max-drift', type="int", action="store",
+ dest='max_drift',
+ help="Set the maximum system clock drift to be"
+ " MAX_DRIFT seconds.")
+
+ self.add_option('-n', '--no-exec', '--just-print', '--dry-run',
+ '--recon', action="store_true", dest='noexec',
+ default=0, help="Don't build; just print commands.")
+
+ def opt_profile(option, opt, value, parser):
+ global profiling
+ if not profiling:
+ profiling = 1
+ import profile
+ profile.run('SCons.Script.main()', value)
+ sys.exit(exit_status)
+ self.add_option('--profile', nargs=1, action="callback",
+ callback=opt_profile, type="string", dest="profile",
+ help="Profile SCons and put results in PROFILE.")
+
+ self.add_option('-q', '--question', action="store_true", default=0,
+ help="Don't build; exit status says if up to date.")
+
+ self.add_option('-Q', dest='no_progress', action="store_true",
+ default=0,
+ help="Don't print SCons progress messages.")
+
+ self.add_option('-s', '--silent', '--quiet', action="store_true",
+ default=0, help="Don't print commands.")
+
+ self.add_option('-u', '--up', '--search-up', action="store_const",
+ dest="climb_up", default=0, const=1,
+ help="Search up directory tree for SConstruct, "
+ "build targets at or below current directory.")
+ self.add_option('-U', action="store_const", dest="climb_up",
+ default=0, const=3,
+ help="Search up directory tree for SConstruct, "
+ "build Default() targets from local SConscript.")
+
+ self.add_option("-v", "--version",
+ action="version",
+ help="Print the SCons version number and exit.")
+
+ self.add_option('--warn', '--warning', nargs=1, action="store",
+ metavar="WARNING-SPEC",
+ help="Enable or disable warnings.")
+
+ self.add_option('-Y', '--repository', nargs=1, action="append",
+ help="Search REPOSITORY for source and target files.")
+
+ self.add_option('--cache-disable', '--no-cache', action="callback",
+ callback=opt_not_yet,
+ # help = "Do not retrieve built targets from Cache."
+ help=SUPPRESS_HELP)
+ self.add_option('--cache-force', '--cache-populate', action="callback",
+ callback=opt_not_yet,
+ # help = "Copy already-built targets into the Cache."
+ help=SUPPRESS_HELP)
+ self.add_option('--cache-show', action="callback",
+ callback=opt_not_yet,
+ # help = "Print what would have built Cached targets.",
+ help=SUPPRESS_HELP)
+ self.add_option('-e', '--environment-overrides', action="callback",
+ callback=opt_not_yet,
+ # help="Environment variables override makefiles."
+ help=SUPPRESS_HELP)
+ self.add_option('-l', '--load-average', '--max-load', action="callback",
+ callback=opt_not_yet, type="int", dest="load_average",
+ # action="store",
+ # help="Don't start multiple jobs unless load is below "
+ # "LOAD-AVERAGE."
+ # type="int",
+ help=SUPPRESS_HELP)
+ self.add_option('--list-derived', action="callback",
+ callback=opt_not_yet,
+ # help="Don't build; list files that would be built."
+ help=SUPPRESS_HELP)
+ self.add_option('--list-actions', action="callback",
+ callback=opt_not_yet,
+ # help="Don't build; list files and build actions."
+ help=SUPPRESS_HELP)
+ self.add_option('--list-where', action="callback",
+ callback=opt_not_yet,
+ # help="Don't build; list files and where defined."
+ help=SUPPRESS_HELP)
+ self.add_option('-o', '--old-file', '--assume-old', action="callback",
+ callback=opt_not_yet, type="string", dest="old_file",
+ # help = "Consider FILE to be old; don't rebuild it."
+ help=SUPPRESS_HELP)
+ self.add_option('--override', action="callback", dest="override",
+ callback=opt_not_yet, type="string",
+ # help="Override variables as specified in FILE."
+ help=SUPPRESS_HELP)
+ self.add_option('-p', action="callback",
+ callback=opt_not_yet,
+ # help="Print internal environments/objects."
+ help=SUPPRESS_HELP)
+ self.add_option('-r', '-R', '--no-builtin-rules',
+ '--no-builtin-variables', action="callback",
+ callback=opt_not_yet,
+ # help="Clear default environments and variables."
+ help=SUPPRESS_HELP)
+ self.add_option('--random', action="callback",
+ callback=opt_not_yet,
+ # help="Build dependencies in random order."
+ help=SUPPRESS_HELP)
+ self.add_option('-w', '--print-directory', action="callback",
+ callback=opt_not_yet,
+ # help="Print the current directory."
+ help=SUPPRESS_HELP)
+ self.add_option('--no-print-directory', action="callback",
+ callback=opt_not_yet,
+ # help="Turn off -w, even if it was turned on implicitly."
+ help=SUPPRESS_HELP)
+ self.add_option('--write-filenames', action="callback",
+ callback=opt_not_yet, type="string", dest="write_filenames",
+ # help="Write all filenames examined into FILE."
+ help=SUPPRESS_HELP)
+ self.add_option('-W', '--what-if', '--new-file', '--assume-new',
+ dest="new_file",
+ action="callback", callback=opt_not_yet, type="string",
+ # help="Consider FILE to be changed."
+ help=SUPPRESS_HELP)
+ self.add_option('--warn-undefined-variables', action="callback",
+ callback=opt_not_yet,
+ # help="Warn when an undefined variable is referenced."
+ help=SUPPRESS_HELP)
+
+ def parse_args(self, args=None, values=None):
+ opt, arglist = OptionParser.parse_args(self, args, values)
+ if opt.implicit_deps_changed or opt.implicit_deps_unchanged:
+ opt.implicit_cache = 1
+ if not hasattr(opt, "num_jobs"):
+ setattr(opt, "num_jobs", 1)
+ return opt, arglist
def _main():
- global scripts, num_jobs, task_class, calc, target_top
+ import SCons.Node
targets = []
- # It looks like 2.0 changed the name of the exception class
- # raised by getopt.
- try:
- getopt_err = getopt.GetoptError
- except:
- getopt_err = getopt.error
-
# Enable deprecated warnings by default.
SCons.Warnings._warningOut = _scons_internal_warning
SCons.Warnings.enableWarningClass(SCons.Warnings.DeprecatedWarning)
SCons.Warnings.enableWarningClass(SCons.Warnings.CorruptSConsignWarning)
+ all_args = sys.argv[1:]
try:
- cmd_opts, t = getopt.getopt(string.split(os.environ['SCONSFLAGS']),
- short_opts, long_opts)
+ all_args = string.split(os.environ['SCONSFLAGS']) + all_args
except KeyError:
- # It's all right if there's no SCONSFLAGS environment variable.
- pass
- except getopt_err, x:
- _scons_user_warning("SCONSFLAGS " + str(x))
- else:
- for opt, arg in cmd_opts:
- opt_func[opt](opt, arg)
+ # it's OK if there's no SCONSFLAGS
+ pass
+ parser = OptParser()
+ options, args = parser.parse_args(all_args)
- try:
- cmd_opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts)
- except getopt_err, x:
- _scons_user_error(x)
- else:
- for opt, arg in cmd_opts:
- opt_func[opt](opt, arg)
- xmit_args = []
- for a in args:
- if '=' in a:
- xmit_args.append(a)
- else:
- targets.append(a)
- SCons.Script.SConscript._scons_add_args(xmit_args)
+ if options.help_msg:
+ def raisePrintHelp(text):
+ raise PrintHelp, text
+ SCons.Script.SConscript.HelpFunction = raisePrintHelp
- if climb_up:
+ _set_globals(options)
+ SCons.Node.implicit_cache = options.implicit_cache
+ SCons.Node.implicit_deps_changed = options.implicit_deps_changed
+ SCons.Node.implicit_deps_unchanged = options.implicit_deps_unchanged
+ if options.warn:
+ _setup_warn(options.warn)
+ if options.noexec:
+ SCons.Action.execute_actions = None
+ CleanTask.execute = CleanTask.show
+ if options.no_progress or options.silent:
+ global display
+ def dont_print_it(text):
+ pass
+ display = dont_print_it
+ if options.silent:
+ SCons.Action.print_actions = None
+ if options.directory:
+ cdir = _create_path(options.directory)
+ try:
+ os.chdir(cdir)
+ except:
+ sys.stderr.write("Could not change directory to %s\n" % cdir)
+
+ xmit_args = []
+ for a in args:
+ if '=' in a:
+ xmit_args.append(a)
+ else:
+ targets.append(a)
+ SCons.Script.SConscript._scons_add_args(xmit_args)
+
+ target_top = None
+ if options.climb_up:
target_top = '.' # directory to prepend to targets
script_dir = os.getcwd() # location of script
while script_dir and not _SConstruct_exists(script_dir):
@@ -928,24 +672,25 @@ def _main():
SCons.Node.FS.default_fs.set_toplevel_dir(os.getcwd())
+ scripts = []
+ if options.file:
+ scripts.extend(options.file)
if not scripts:
sfile = _SConstruct_exists()
if sfile:
scripts.append(sfile)
- if help_option == 'H':
- print UsageString()
- sys.exit(0)
-
- if not scripts:
- if help_option == 'h':
+ if options.help_msg:
+ if not scripts:
# There's no SConstruct, but they specified -h.
# Give them the options usage now, before we fail
# trying to read a non-existent SConstruct file.
- print UsageString()
- sys.exit(0)
- else:
- raise UserError, "No SConstruct file found."
+ parser.print_help()
+ sys.exit(0)
+ SCons.Script.SConscript.print_help = 1
+
+ if not scripts:
+ raise UserError, "No SConstruct file found."
class Unbuffered:
def __init__(self, file):
@@ -958,7 +703,8 @@ def _main():
sys.stdout = Unbuffered(sys.stdout)
- sys.path = include_dirs + sys.path
+ if options.include_dir:
+ sys.path = options.include_dir + sys.path
global repositories
for rep in repositories:
@@ -976,27 +722,26 @@ def _main():
print text
print "Use scons -H for help about command-line options."
sys.exit(0)
-
display("scons: done reading SConscript files.")
SCons.Node.FS.default_fs.chdir(SCons.Node.FS.default_fs.Top)
- if help_option == 'h':
- # They specified -h, but there was no Help() inside the
- # SConscript files. Give them the options usage.
- print UsageString()
- sys.exit(0)
+ if options.help_msg:
+ # They specified -h, but there was no Help() inside the
+ # SConscript files. Give them the options usage.
+ parser.print_help(sys.stdout)
+ sys.exit(0)
if target_top:
target_top = SCons.Node.FS.default_fs.Dir(target_top)
- if climb_up == 2 and not targets:
+ if options.climb_up == 2 and not targets:
# -D with default targets
target_top = None
- elif climb_up == 3 and not targets:
+ elif options.climb_up == 3 and not targets:
# -U with default targets
default_targets = SCons.Script.SConscript.default_targets
- def check_dir(x):
+ def check_dir(x, target_top=target_top):
cwd = x.cwd.srcnode()
return cwd == target_top
default_targets = filter(check_dir, default_targets)
@@ -1038,22 +783,42 @@ def _main():
nodes = filter(lambda x: x is not None, map(Entry, targets))
+ calc = None
+ task_class = BuildTask # default action is to build targets
+ if options.question:
+ task_class = QuestionTask
+ try:
+ if options.clean:
+ task_class = CleanTask
+ class CleanCalculator:
+ def bsig(self, node):
+ return None
+ def csig(self, node):
+ return None
+ def current(self, node, sig):
+ return 0
+ def write(self):
+ pass
+ calc = CleanCalculator()
+ except AttributeError:
+ pass
+
if not calc:
- if max_drift is not None:
- if sig_module is not None:
+ if options.max_drift is not None:
+ if sig_module is not None:
SCons.Sig.default_calc = SCons.Sig.Calculator(module=sig_module,
- max_drift=max_drift)
- else:
- SCons.Sig.default_calc = SCons.Sig.Calculator(max_drift=max_drift)
+ max_drift=options.max_drift)
+ else:
+ SCons.Sig.default_calc = SCons.Sig.Calculator(max_drift=options.max_drift)
elif sig_module is not None:
SCons.Sig.default_calc = SCons.Sig.Calculator(module=sig_module)
-
+
calc = SCons.Sig.default_calc
display("scons: Building targets ...")
taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, calc)
- jobs = SCons.Job.Jobs(num_jobs, taskmaster)
+ jobs = SCons.Job.Jobs(options.num_jobs, taskmaster)
try:
jobs.run()
diff --git a/src/engine/setup.py b/src/engine/setup.py
index d1ef81b..115bced 100644
--- a/src/engine/setup.py
+++ b/src/engine/setup.py
@@ -63,6 +63,7 @@ software.""",
keywords = "scons, cons, make, build tool, make tool",
packages = ["SCons",
"SCons.Node",
+ "SCons.Optik",
"SCons.Scanner",
"SCons.Sig",
"SCons.Script"])
diff --git a/src/setup.py b/src/setup.py
index ceb4440..50c1491 100644
--- a/src/setup.py
+++ b/src/setup.py
@@ -76,6 +76,7 @@ arguments = {
'version' : "__VERSION__",
'packages' : ["SCons",
"SCons.Node",
+ "SCons.Optik",
"SCons.Platform",
"SCons.Scanner",
"SCons.Script",
diff --git a/test/SCONSFLAGS.py b/test/SCONSFLAGS.py
index f8d757a..2d0ac8d 100644
--- a/test/SCONSFLAGS.py
+++ b/test/SCONSFLAGS.py
@@ -29,7 +29,7 @@ import TestSCons
import os
import string
-test = TestSCons.TestSCons(match = TestCmd.match_re)
+test = TestSCons.TestSCons()
wpath = test.workpath()
@@ -59,11 +59,10 @@ test.fail_test(string.find(test.stdout(), '-H, --help-options') == -1)
os.environ['SCONSFLAGS'] = '-Z'
-test.run(arguments = "-H", stderr = r"""
-SCons warning: SCONSFLAGS option -Z not recognized
-File "[^"]*", line \d+, in \S+
-""")
+test.run(arguments = "-H", status = 2,
+ stderr = r"""usage: scons [OPTION] [TARGET] ...
-test.fail_test(string.find(test.stdout(), '-H, --help-options') == -1)
+SCons error: no such option: -Z
+""")
test.pass_test()
diff --git a/test/option--profile.py b/test/option--profile.py
index 6d7efe4..5ba9c46 100644
--- a/test/option--profile.py
+++ b/test/option--profile.py
@@ -49,9 +49,9 @@ stats.strip_dirs().print_stats()
s = sys.stdout.getvalue()
test.fail_test(string.find(s, '__init__.py') == -1)
-test.fail_test(string.find(s, 'option_v') == -1)
+test.fail_test(string.find(s, 'print_version') == -1)
test.fail_test(string.find(s, 'SCons.Script.main()') == -1)
-test.fail_test(string.find(s, 'getopt.py') == -1)
+test.fail_test(string.find(s, 'option_parser.py') == -1)
scons_prof = test.workpath('scons2.prof')
@@ -70,9 +70,9 @@ stats.strip_dirs().print_stats()
s = sys.stdout.getvalue()
test.fail_test(string.find(s, '__init__.py') == -1)
-test.fail_test(string.find(s, 'option_v') == -1)
+test.fail_test(string.find(s, 'print_version') == -1)
test.fail_test(string.find(s, 'SCons.Script.main()') == -1)
-test.fail_test(string.find(s, 'getopt.py') == -1)
+test.fail_test(string.find(s, 'option_parser.py') == -1)
test.pass_test()
diff --git a/test/option-unknown.py b/test/option-unknown.py
index 496a7e0..7ddad94 100644
--- a/test/option-unknown.py
+++ b/test/option-unknown.py
@@ -29,21 +29,21 @@ import TestSCons
import string
import sys
-test = TestSCons.TestSCons(match = TestCmd.match_re)
+test = TestSCons.TestSCons()
test.write('SConstruct', "")
test.run(arguments = '-Z',
- stderr = """
-SCons error: option -Z not recognized
-File "\S+", line \d+, in short_has_arg
+ stderr = """usage: scons [OPTION] [TARGET] ...
+
+SCons error: no such option: -Z
""",
status = 2)
test.run(arguments = '--ZizzerZazzerZuzz',
- stderr = """
-SCons error: option --ZizzerZazzerZuzz not recognized
-File "\S+", line \d+, in long_has_args
+ stderr = """usage: scons [OPTION] [TARGET] ...
+
+SCons error: no such option: --ZizzerZazzerZuzz
""",
status = 2)