diff --git a/scons/scons b/scons/scons deleted file mode 100644 index 7a73ab744..000000000 --- a/scons/scons +++ /dev/null @@ -1,161 +0,0 @@ -#! /usr/bin/env python -# -# SCons - a Software Constructor -# -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation -# -# 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__ = "/home/scons/scons/branch.0/baseline/src/script/scons.py 0.97.D001 2007/05/17 11:35:19 knight" - -__version__ = "0.97" - -__build__ = "D001" - -__buildsys__ = "roxbury" - -__date__ = "2007/05/17 11:35:19" - -__developer__ = "knight" - -import os -import os.path -import sys - -############################################################################## -# BEGIN STANDARD SCons SCRIPT HEADER -# -# This is the cut-and-paste logic so that a self-contained script can -# interoperate correctly with different SCons versions and installation -# locations for the engine. If you modify anything in this section, you -# should also change other scripts that use this same header. -############################################################################## - -# Strip the script directory from sys.path() so on case-insensitive -# (WIN32) systems Python doesn't think that the "scons" script is the -# "SCons" package. Replace it with our own library directories -# (version-specific first, in case they installed by hand there, -# followed by generic) so we pick up the right version of the build -# engine modules if they're in either directory. - -script_dir = sys.path[0] - -if script_dir in sys.path: - sys.path.remove(script_dir) - -libs = [] - -if os.environ.has_key("SCONS_LIB_DIR"): - libs.append(os.environ["SCONS_LIB_DIR"]) - -local = 'scons-local-' + __version__ -if script_dir: - local = os.path.join(script_dir, local) -libs.append(os.path.abspath(local)) - -scons_version = 'scons-%s' % __version__ - -prefs = [] - -if sys.platform == 'win32': - # sys.prefix is (likely) C:\Python*; - # check only C:\Python*. - prefs.append(sys.prefix) - prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages')) -else: - # On other (POSIX) platforms, things are more complicated due to - # the variety of path names and library locations. Try to be smart - # about it. - if script_dir == 'bin': - # script_dir is `pwd`/bin; - # check `pwd`/lib/scons*. - prefs.append(os.getcwd()) - else: - if script_dir == '.' or script_dir == '': - script_dir = os.getcwd() - head, tail = os.path.split(script_dir) - if tail == "bin": - # script_dir is /foo/bin; - # check /foo/lib/scons*. - prefs.append(head) - - head, tail = os.path.split(sys.prefix) - if tail == "usr": - # sys.prefix is /foo/usr; - # check /foo/usr/lib/scons* first, - # then /foo/usr/local/lib/scons*. - prefs.append(sys.prefix) - prefs.append(os.path.join(sys.prefix, "local")) - elif tail == "local": - h, t = os.path.split(head) - if t == "usr": - # sys.prefix is /foo/usr/local; - # check /foo/usr/local/lib/scons* first, - # then /foo/usr/lib/scons*. - prefs.append(sys.prefix) - prefs.append(head) - else: - # sys.prefix is /foo/local; - # check only /foo/local/lib/scons*. - prefs.append(sys.prefix) - else: - # sys.prefix is /foo (ends in neither /usr or /local); - # check only /foo/lib/scons*. - prefs.append(sys.prefix) - - temp = map(lambda x: os.path.join(x, 'lib'), prefs) - temp.extend(map(lambda x: os.path.join(x, - 'lib', - 'python' + sys.version[:3], - 'site-packages'), - prefs)) - prefs = temp - - # Add the parent directory of the current python's library to the - # preferences. On SuSE-91/AMD64, for example, this is /usr/lib64, - # not /usr/lib. - try: - libpath = os.__file__ - except AttributeError: - pass - else: - while libpath: - libpath, tail = os.path.split(libpath) - if tail[:6] == "python": - break - if libpath: - # Python library is in /usr/libfoo/python*; - # check /usr/libfoo/scons*. - prefs.append(libpath) - -# Look first for 'scons-__version__' in all of our preference libs, -# then for 'scons'. -libs.extend(map(lambda x: os.path.join(x, scons_version), prefs)) -libs.extend(map(lambda x: os.path.join(x, 'scons'), prefs)) - -sys.path = libs + sys.path - -############################################################################## -# END STANDARD SCons SCRIPT HEADER -############################################################################## - -import SCons.Script -SCons.Script.main() diff --git a/scons/scons-LICENSE b/scons/scons-LICENSE index f16cda12d..184b82e5d 100644 --- a/scons/scons-LICENSE +++ b/scons/scons-LICENSE @@ -1,3 +1,8 @@ + Copyright and license for SCons - a software construction tool + + This copyright and license do not apply to any other software + with which this software may have been included. + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation Permission is hereby granted, free of charge, to any person obtaining diff --git a/scons/scons-README b/scons/scons-README index 9f18e4d0c..97fc5f436 100644 --- a/scons/scons-README +++ b/scons/scons-README @@ -1,28 +1,42 @@ # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation -# src/README.txt 0.97.D001 2007/05/17 11:35:19 knight - SCons - a software construction tool - Version 0.97 +This is the scons-README file for a version of SCons packaged for local +execution--that is, execution out of a specific local directory, without +having to install SCons as a system-wide utility. +You are likely reading this file in one of the following two situations: -This is a beta release of SCons, a tool for building software (and other -files). SCons is implemented in Python, and its "configuration files" -are actually Python scripts, allowing you to use the full power of a -real scripting language to solve build problems. You do not, however, -need to know Python to use SCons effectively. + 1) You have unpacked an scons-local-{version} package and are + examining the contents. -See the RELEASE.txt file for notes about this specific release, -including known problems. See the CHANGES.txt file for a list of -changes since the previous release. + In this case, you are presumably interested in using this + package to include a local copy of SCons with some other + software that you package, so that you can use SCons to build + your software without forcing all of your users to have it fully + installed. Instructions for this can be found below. + If you are not looking to use SCons in this way, then please + use either the scons-{version} package to install SCons on your + system, or the scons-src-{version} package if you want the full + source to SCons, including its packaging code and underlying + tests and testing infrastructure. + + 2) This file was included in some other software package so that + the package could be built using SCons. + + In this case, follow the instructions provided with the + rest of the software package for how to use SCons to build + and/or install the software. The file containing build and + installation instructions will typically be named README or + INSTALL. LATEST VERSION ============== -Before going further, you can check that this package you have is -the latest version by checking the SCons download page at: +Before going further, you can check for the latest version of the +scons-local package, or any SCons package, at the SCons download page: http://www.scons.org/download.html @@ -31,149 +45,93 @@ EXECUTION REQUIREMENTS ====================== Running SCons requires Python version 1.5.2 or later. There should be -no other dependencies or requirements to run SCons. (There is, however, -an additional requirement to *install* SCons from this particular -package; see the next section.) +no other dependencies or requirements to run SCons. -By default, SCons knows how to search for available programming tools -on various systems--see the SCons man page for details. You may, -of course, override the default SCons choices made by appropriate +The default SCons configuration assumes use of the Microsoft Visual C++ +compiler suite on WIN32 systems, and assumes a C compiler named 'cc', +a C++ compiler named 'c++', and a Fortran compiler named 'g77' (such +as found in the GNU C compiler suite) on any other type of system. +You may, of course, override these default values by appropriate configuration of Environment construction variables. -INSTALLATION REQUIREMENTS -========================= - -Installing SCons from this package requires the Python distutils -package. The distutils package was not shipped as a standard part of -Python until Python version 1.6, so if your system is running Python -1.5.2, you may not have distutils installed. If you are running -Python version 1.6 or later, you should be fine. - -NOTE TO RED HAT USERS: Red Hat shipped Python 1.5.2 as the default all -the way up to Red Hat Linux 7.3, so you probably do *not* have distutils -installed, unless you have already done so manually or are running Red -Hat 8.0 or later. - -In this case, your options are: - - -- (Recommended.) Install from a pre-packaged SCons package that - does not require distutils: - - Red Hat Linux scons-0.97-1.noarch.rpm - - Debian GNU/Linux scons_0.97-1_all.deb - (or use apt-get) - - Windows scons-0.97.win32.exe - - -- (Optional.) Download the latest distutils package from the - following URL: - - http://www.python.org/sigs/distutils-sig/download.html - - Install the distutils according to the instructions on the page. - You can then proceed to the next section to install SCons from - this package. - - INSTALLATION ============ -Assuming your system satisfies the installation requirements in the -previous section, install SCons from this package simply by running the -provided Python-standard setup script as follows: +Installation of this package should be as simple as unpacking the +archive (either .tar.gz or .zip) in any directory (top-level or a +subdirectory) within the software package with which you want to ship +SCons. - # python setup.py install +Once you have installed this package, you should write an SConstruct +file at the top level of your source tree to build your software as you +see fit. -By default, the above command will do the following: +Then modify the build/install instructions for your package to instruct +your users to execute SCons as follows (if you installed this package in +your top-level directory): - -- Install the version-numbered "scons-0.97" and "sconsign-0.97" - scripts in the default system script directory (/usr/bin or - C:\Python*\Scripts, for example). This can be disabled by - specifying the "--no-version-script" option on the command - line. + $ python scons.py - -- Install scripts named "scons" and "sconsign" scripts in the - default system script directory (/usr/bin or C:\Python*\Scripts, - for example). This can be disabled by specifying the - "--no-scons-script" option on the command line, which is useful - if you want to install and experiment with a new version before - making it the default on your system. +Or (if, for example, you installed this package in a subdirectory named +"scons"): - On UNIX or Linux systems, you can have the "scons" and "sconsign" - scripts be hard links or symbolic links to the "scons-0.97" and - "sconsign-0.97" scripts by specifying the "--hardlink-scons" - or "--symlink-scons" options on the command line. + $ python scons/scons.py - -- Install "scons-0.97.bat" and "scons.bat" wrapper scripts in the - Python prefix directory on Windows (C:\Python*, for example). - This can be disabled by specifying the "--no-install-bat" option - on the command line. +That should be all you have to do. (If it isn't that simple, please let +us know!) - On UNIX or Linux systems, the "--install-bat" option may be - specified to have "scons-0.97.bat" and "scons.bat" files - installed in the default system script directory, which is useful - if you want to install SCons in a shared file system directory - that can be used to execute SCons from both UNIX/Linux and - Windows systems. - -- Install the SCons build engine (a Python module) in an - appropriate version-numbered SCons library directory - (/usr/lib/scons-0.97 or C:\Python*\scons-0.97, for example). - See below for more options related to installing the build - engine library. +CONTENTS OF THIS PACKAGE +======================== - -- Install the troff-format man pages in an appropriate directory - on UNIX or Linux systems (/usr/share/man/man1 or /usr/man/man1, - for example). This can be disabled by specifying the - "--no-install-man" option on the command line. The man pages - can be installed on Windows systems by specifying the - "--install-man" option on the command line. +This scons-local package consists of the following: -Note that, by default, SCons does not install its build engine library -in the standard Python library directories. If you want to be able to -use the SCons library modules (the build engine) in other Python -scripts, specify the "--standard-lib" option on the command line, as -follows: +scons-LICENSE + A copy of the copyright and terms under which SCons is + distributed (the Open Source Initiative-approved MIT license). - # python setup.py install --standard-lib + A disclaimer has been added to the beginning to make clear that + this license applies only to SCons, and not to any separate + software you've written with which you're planning to package + SCons. -This will install the build engine in the standard Python library -directory (/usr/lib/python*/site-packages or -C:\Python*\Lib\site-packages). +scons-README + What you're looking at right now. -Alternatively, you can have SCons install its build engine library in a -hard-coded standalone library directory, instead of the default -version-numbered directory, by specifying the "--standalone-lib" option -on the command line, as follows: +scons-local-{version}/ + The SCons build engine. This is structured as a Python + library. - # python setup.py install --standalone-lib - -This is usually not recommended, however. - -Note that, to install SCons in any of the above system directories, -you should have system installation privileges (that is, "root" or -"Administrator") when running the setup.py script. If you don't have -system installation privileges, you can use the --prefix option to -specify an alternate installation location, such as your home directory: - - $ python setup.py install --prefix=$HOME - -This will install SCons in the appropriate locations relative to -$HOME--that is, the scons script itself $HOME/bin and the associated -library in $HOME/lib/scons, for example. +scons.py + The SCons script itself. The script sets up the Python + sys.path variable to use the build engine found in the + scons-local-{version}/ directory in preference to any other + SCons build engine installed on your system. DOCUMENTATION ============= -See the RELEASE.txt file for notes about this specific release, -including known problems. See the CHANGES.txt file for a list of -changes since the previous release. +Because this package is intended to be included with other software by +experienced users, we have not included any SCons documentation in this +package (other than this scons-README file you're reading right now). -The scons.1 man page is included in this package, and contains a section -of small examples for getting started using SCons. +If, however, you need documentation about SCons, then consult any of the +following from the corresponding scons-{version} or scons-src-{version} +package: + + The RELEASE.txt file (src/RELEASE.txt file in the + scons-src-{version} package), which contains notes about this + specific release, including known problems. + + The CHANGES.txt file (src/CHANGES.txt file in the + scons-src-{version} package), which contains a list of changes + since the previous release. + + The scons.1 man page (doc/man/scons.1 in the scons-src-{version} + package), which contains a section of small examples for getting + started using SCons. Additional documentation for SCons is available at: @@ -184,8 +142,8 @@ LICENSING ========= SCons is distributed under the MIT license, a full copy of which is -available in the LICENSE.txt file. The MIT license is an approved Open -Source license, which means: +available in the scons-LICENSE file in this package. The MIT license is +an approved Open Source license, which means: This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative. @@ -199,51 +157,27 @@ available at: REPORTING BUGS ============== -Please report bugs by following the detailed instructions on our Bug -Submission page: +You can report bugs either by following the "Tracker - Bugs" link +on the SCons project page: - http://scons.tigris.org/bug-submission.html + http://sourceforge.net/projects/scons/ -You can also send mail to the SCons developers' mailing list: +or by sending mail to the SCons developers mailing list: - dev@scons.tigris.org - -But even if you send email to the mailing list please make sure that you -ALSO submit a bug report to the project page bug tracker, because bug -reports in email often get overlooked in the general flood of messages. + scons-devel@lists.sourceforge.net MAILING LISTS ============= -An active mailing list for users of SCons is available. You may send -questions or comments to the list at: +A mailing list for users of SCons is available. You may send questions +or comments to the list at: - users@scons.tigris.org + scons-users@lists.sourceforge.net -You may subscribe to the mailing list by sending email to: +You may subscribe to the scons-users mailing list at: - users-subscribe@scons.tigris.org - -There is also a low-volume mailing list available for announcements -about SCons. Subscribe by sending email to: - - announce-subscribe@scons.tigris.org - -There are other mailing lists available for SCons developers, for -notification of SCons code changes, and for notification of updated -bug reports and project documents. Please see our mailing lists page -for details. - - -DONATIONS -========= - -If you find SCons helpful, please consider making a donation (of cash, -software, or hardware) to support continued work on the project. -Information is available at: - - http://www.scons.org/donate.html + http://lists.sourceforge.net/lists/listinfo/scons-users FOR MORE INFORMATION @@ -265,9 +199,6 @@ With plenty of help from the SCons Development team: Chad Austin Charles Crain Steve Leblanc - Greg Noel - Gary Oberbrunner Anthony Roach - Greg Spencer - Christoph Wiedemann + Terrel Shumway diff --git a/scons/scons-local-0.97/SCons/Action.py b/scons/scons-local-0.97.0d20071212/SCons/Action.py similarity index 91% rename from scons/scons-local-0.97/SCons/Action.py rename to scons/scons-local-0.97.0d20071212/SCons/Action.py index 257731a26..5a7efccac 100644 --- a/scons/scons-local-0.97/SCons/Action.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Action.py @@ -31,8 +31,8 @@ other modules: get_contents() Fetches the "contents" of an Action for signature calculation. - This is what the Sig/*.py subsystem uses to decide if a target - needs to be rebuilt because its action changed. + This is what gets MD5 checksumm'ed to decide if a target needs + to be rebuilt because its action changed. genstring() Returns a string representation of the Action *without* @@ -95,7 +95,7 @@ way for wrapping up the functions. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Action.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Action.py 2523 2007/12/12 09:37:41 knight" import dis import os @@ -287,6 +287,7 @@ class _ActionAction(ActionBase): target = [target] if not SCons.Util.is_List(source): source = [source] + if exitstatfunc is _null: exitstatfunc = self.exitstatfunc if presub is _null: presub = self.presub @@ -329,12 +330,20 @@ class _ActionAction(ActionBase): os.chdir(chdir) try: stat = self.execute(target, source, env) - stat = exitstatfunc(stat) + if isinstance(stat, SCons.Errors.BuildError): + s = exitstatfunc(stat.status) + if s: + stat.status = s + else: + stat = s + else: + stat = exitstatfunc(stat) finally: if save_cwd: os.chdir(save_cwd) if s and save_cwd: print_func('os.chdir(%s)' % repr(save_cwd), target, source, env) + return stat @@ -476,7 +485,11 @@ class CommandAction(_ActionAction): cmd_line = escape_list(cmd_line, escape) result = spawn(shell, escape, cmd_line[0], cmd_line, ENV) if not ignore and result: - return result + msg = "Error %s" % result + return SCons.Errors.BuildError(errstr=msg, + status=result, + action=self, + command=cmd_line) return 0 def get_contents(self, target, source, env): @@ -493,6 +506,22 @@ class CommandAction(_ActionAction): cmd = str(cmd) return env.subst_target_source(cmd, SUBST_SIG, target, source) + def get_implicit_deps(self, target, source, env): + icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True) + if SCons.Util.is_String(icd) and icd[:1] == '$': + icd = env.subst(icd) + if not icd or icd in ('0', 'None'): + return [] + from SCons.Subst import SUBST_SIG + cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source) + res = [] + for cmd_line in cmd_list: + if cmd_line: + d = env.WhereIs(str(cmd_line[0])) + if d: + res.append(env.fs.File(d)) + return res + class CommandGeneratorAction(ActionBase): """Class for command-generator actions.""" def __init__(self, generator, *args, **kw): @@ -515,9 +544,11 @@ class CommandGeneratorAction(ActionBase): def __str__(self): try: - env = self.presub_env or {} + env = self.presub_env except AttributeError: - env = {} + env = None + if env is None: + env = SCons.Defaults.DefaultEnvironment() act = self._generate([], [], env, 1) return str(act) @@ -538,6 +569,9 @@ class CommandGeneratorAction(ActionBase): """ return self._generate(target, source, env, 1).get_contents(target, source, env) + def get_implicit_deps(self, target, source, env): + return self._generate(target, source, env, 1).get_implicit_deps(target, source, env) + # A LazyAction is a kind of hybrid generator and command action for @@ -666,9 +700,19 @@ class FunctionAction(_ActionAction): # target file will appear). try: filename = e.filename except AttributeError: filename = None - raise SCons.Errors.BuildError(node=target, - errstr=e.strerror, - filename=filename) + result = SCons.Errors.BuildError(node=target, + errstr=e.strerror, + status=1, + filename=filename, + action=self, + command=self.strfunction(target, source, env)) + else: + if result: + msg = "Error %s" % result + result = SCons.Errors.BuildError(errstr=msg, + status=result, + action=self, + command=self.strfunction(target, source, env)) return result def get_contents(self, target, source, env): @@ -713,6 +757,9 @@ class FunctionAction(_ActionAction): return contents + env.subst(string.join(map(lambda v: '${'+v+'}', self.varlist))) + def get_implicit_deps(self, target, source, env): + return [] + class ListAction(ActionBase): """Class for lists of other actions.""" def __init__(self, list): @@ -756,6 +803,12 @@ class ListAction(ActionBase): return stat return 0 + def get_implicit_deps(self, target, source, env): + result = [] + for act in self.list: + result.extend(act.get_implicit_deps(target, source, env)) + return result + class ActionCaller: """A class for delaying calling an Action function with specific (positional and keyword) arguments until the Action is actually @@ -790,8 +843,9 @@ class ActionCaller: # was called by using this hard-coded value as a special return. if s == '$__env__': return env - else: + elif SCons.Util.is_String(s): return env.subst(s, 0, target, source) + return self.parent.convert(s) def subst_args(self, target, source, env): return map(lambda x, self=self, t=target, s=source, e=env: self.subst(x, t, s, e), @@ -821,9 +875,10 @@ class ActionFactory: called with and give them to the ActionCaller object we create, so it can hang onto them until it needs them. """ - def __init__(self, actfunc, strfunc): + def __init__(self, actfunc, strfunc, convert=lambda x: x): self.actfunc = actfunc self.strfunc = strfunc + self.convert = convert def __call__(self, *args, **kw): ac = ActionCaller(self, args, kw) action = Action(ac, strfunction=ac.strfunction) diff --git a/scons/scons-local-0.97/SCons/Builder.py b/scons/scons-local-0.97.0d20071212/SCons/Builder.py similarity index 93% rename from scons/scons-local-0.97/SCons/Builder.py rename to scons/scons-local-0.97.0d20071212/SCons/Builder.py index 2849a44bf..5bd2098ac 100644 --- a/scons/scons-local-0.97/SCons/Builder.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Builder.py @@ -39,9 +39,6 @@ used by other modules: variable. This also takes care of warning about possible mistakes in keyword arguments. - targets() - Returns the list of targets for a specific builder instance. - add_emitter() Adds an emitter for a specific file suffix, used by some Tool modules to specify that (for example) a yacc invocation on a .y @@ -101,7 +98,7 @@ There are the following methods for internal use within this module: # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Builder.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Builder.py 2523 2007/12/12 09:37:41 knight" import SCons.compat @@ -367,6 +364,7 @@ class BuilderBase: chdir = _null, is_explicit = 1, src_builder = [], + ensure_suffix = False, **overrides): if __debug__: logInstanceCreation(self, 'Builder.BuilderBase') self._memo = {} @@ -394,6 +392,7 @@ class BuilderBase: self.set_suffix(suffix) self.set_src_suffix(src_suffix) + self.ensure_suffix = ensure_suffix self.target_factory = target_factory self.source_factory = source_factory @@ -467,28 +466,28 @@ class BuilderBase: executor.add_sources(slist) return executor + def _adjustixes(self, files, pre, suf, ensure_suffix=False): + if not files: + return [] + result = [] + if not SCons.Util.is_List(files): + files = [files] + + for f in files: + if SCons.Util.is_String(f): + f = SCons.Util.adjustixes(f, pre, suf, ensure_suffix) + result.append(f) + return result + def _create_nodes(self, env, target = None, source = None): """Create and return lists of target and source nodes. """ - def _adjustixes(files, pre, suf): - if not files: - return [] - result = [] - if not SCons.Util.is_List(files): - files = [files] - - for f in files: - if SCons.Util.is_String(f): - f = SCons.Util.adjustixes(f, pre, suf) - result.append(f) - return result - src_suf = self.get_src_suffix(env) target_factory = env.get_factory(self.target_factory) source_factory = env.get_factory(self.source_factory) - source = _adjustixes(source, None, src_suf) + source = self._adjustixes(source, None, src_suf) slist = env.arg2nodes(source, source_factory) pre = self.get_prefix(env, slist) @@ -505,7 +504,7 @@ class BuilderBase: splitext = lambda S,self=self,env=env: self.splitext(S,env) tlist = [ t_from_s(pre, suf, splitext) ] else: - target = _adjustixes(target, pre, suf) + target = self._adjustixes(target, pre, suf, self.ensure_suffix) tlist = env.arg2nodes(target, target_factory) if self.emitter: @@ -520,6 +519,9 @@ class BuilderBase: t.builder_set(self) new_targets.append(t) + orig_tlist = tlist[:] + orig_slist = slist[:] + target, source = self.emitter(target=tlist, source=slist, env=env) # Now delete the temporary builders that we attached to any @@ -533,8 +535,10 @@ class BuilderBase: # Have to call arg2nodes yet again, since it is legal for # emitters to spit out strings as well as Node instances. - tlist = env.arg2nodes(target, target_factory) - slist = env.arg2nodes(source, source_factory) + tlist = env.arg2nodes(target, target_factory, + target=orig_tlist, source=orig_slist) + slist = env.arg2nodes(source, source_factory, + target=orig_tlist, source=orig_slist) return tlist, slist @@ -550,10 +554,10 @@ class BuilderBase: if not tgt is None: tgt = [tgt] if not src is None: src = [src] result.extend(self._execute(env, tgt, src, overwarn)) - return result + return SCons.Node.NodeList(result) overwarn.warn() - + tlist, slist = self._create_nodes(env, target, source) # Check for errors with the specified target/source lists. @@ -647,13 +651,6 @@ class BuilderBase: return '' return ret[0] - def targets(self, node): - """Return the list of targets for this builder instance. - - For most normal builders, this is just the supplied node. - """ - return [ node ] - def add_emitter(self, suffix, emitter): """Add a suffix-emitter mapping to this Builder. @@ -699,22 +696,16 @@ class BuilderBase: for suf in bld.src_suffixes(env): sdict[suf] = bld return sdict - - def src_builder_sources(self, env, source, overwarn={}): - source_factory = env.get_factory(self.source_factory) - slist = env.arg2nodes(source, source_factory) + def src_builder_sources(self, env, source, overwarn={}): sdict = self._get_sdict(env) src_suffixes = self.src_suffixes(env) - lengths_dict = {} - for l in map(len, src_suffixes): - lengths_dict[l] = None - lengths = lengths_dict.keys() + lengths = list(set(map(len, src_suffixes))) - def match_src_suffix(node, src_suffixes=src_suffixes, lengths=lengths): - node_suffixes = map(lambda l, n=node: n.name[-l:], lengths) + def match_src_suffix(name, src_suffixes=src_suffixes, lengths=lengths): + node_suffixes = map(lambda l, n=name: n[-l:], lengths) for suf in src_suffixes: if suf in node_suffixes: return suf @@ -722,25 +713,38 @@ class BuilderBase: result = [] - for snode in slist: - match_suffix = match_src_suffix(snode) + if SCons.Util.is_List(source): + source = SCons.Util.flatten(source) + else: + source = [source] + for s in source: + if SCons.Util.is_String(s): + match_suffix = match_src_suffix(s) + if not match_suffix and not '.' in s: + src_suf = self.get_src_suffix(env) + s = self._adjustixes(s, None, src_suf)[0] + else: + match_suffix = match_src_suffix(s.name) if match_suffix: try: bld = sdict[match_suffix] except KeyError: - result.append(snode) + result.append(s) else: - tlist = bld._execute(env, None, [snode], overwarn) + tlist = bld._execute(env, None, [s], overwarn) # If the subsidiary Builder returned more than one # target, then filter out any sources that this # Builder isn't capable of building. if len(tlist) > 1: - tlist = filter(match_src_suffix, tlist) + mss = lambda t, m=match_src_suffix: m(t.name) + tlist = filter(mss, tlist) result.extend(tlist) else: - result.append(snode) + result.append(s) - return result + source_factory = env.get_factory(self.source_factory) + + return env.arg2nodes(result, source_factory) def _get_src_builders_key(self, env): return id(env) diff --git a/scons/scons-local-0.97.0d20071212/SCons/CacheDir.py b/scons/scons-local-0.97.0d20071212/SCons/CacheDir.py new file mode 100644 index 000000000..871c62ec2 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/CacheDir.py @@ -0,0 +1,217 @@ +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/CacheDir.py 2523 2007/12/12 09:37:41 knight" + +__doc__ = """ +CacheDir support +""" + +import os.path +import stat +import string +import sys + +import SCons.Action + +cache_debug = False +cache_force = False +cache_show = False + +def CacheRetrieveFunc(target, source, env): + t = target[0] + fs = t.fs + cd = env.get_CacheDir() + cachedir, cachefile = cd.cachepath(t) + if not fs.exists(cachefile): + cd.CacheDebug('CacheRetrieve(%s): %s not in cache\n', t, cachefile) + return 1 + cd.CacheDebug('CacheRetrieve(%s): retrieving from %s\n', t, cachefile) + if SCons.Action.execute_actions: + if fs.islink(cachefile): + fs.symlink(fs.readlink(cachefile), t.path) + else: + env.copy_from_cache(cachefile, t.path) + st = fs.stat(cachefile) + fs.chmod(t.path, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) + return 0 + +def CacheRetrieveString(target, source, env): + t = target[0] + fs = t.fs + cd = env.get_CacheDir() + cachedir, cachefile = cd.cachepath(t) + if t.fs.exists(cachefile): + return "Retrieved `%s' from cache" % t.path + return None + +CacheRetrieve = SCons.Action.Action(CacheRetrieveFunc, CacheRetrieveString) + +CacheRetrieveSilent = SCons.Action.Action(CacheRetrieveFunc, None) + +def CachePushFunc(target, source, env): + t = target[0] + if t.nocache: + return + fs = t.fs + cd = env.get_CacheDir() + cachedir, cachefile = cd.cachepath(t) + if fs.exists(cachefile): + # Don't bother copying it if it's already there. Note that + # usually this "shouldn't happen" because if the file already + # existed in cache, we'd have retrieved the file from there, + # not built it. This can happen, though, in a race, if some + # other person running the same build pushes their copy to + # the cache after we decide we need to build it but before our + # build completes. + cd.CacheDebug('CachePush(%s): %s already exists in cache\n', t, cachefile) + return + + cd.CacheDebug('CachePush(%s): pushing to %s\n', t, cachefile) + + tempfile = cachefile+'.tmp'+str(os.getpid()) + errfmt = "Unable to copy %s to cache. Cache file is %s" + + if not fs.isdir(cachedir): + try: + fs.makedirs(cachedir) + except EnvironmentError: + # We may have received an exception because another process + # has beaten us creating the directory. + if not fs.isdir(cachedir): + msg = errfmt % (str(target), cachefile) + raise SCons.Errors.EnvironmentError, msg + + try: + if fs.islink(t.path): + fs.symlink(fs.readlink(t.path), tempfile) + else: + fs.copy2(t.path, tempfile) + fs.rename(tempfile, cachefile) + st = fs.stat(t.path) + fs.chmod(cachefile, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) + except EnvironmentError: + # It's possible someone else tried writing the file at the + # same time we did, or else that there was some problem like + # the CacheDir being on a separate file system that's full. + # In any case, inability to push a file to cache doesn't affect + # the correctness of the build, so just print a warning. + msg = errfmt % (str(target), cachefile) + SCons.Warnings.warn(SCons.Warnings.CacheWriteErrorWarning, msg) + +CachePush = SCons.Action.Action(CachePushFunc, None) + +class CacheDir: + + def __init__(self, path): + try: + import hashlib + except ImportError: + msg = "No hashlib or MD5 module available, CacheDir() not supported" + SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg) + else: + self.path = path + + def CacheDebugWrite(self, fmt, target, cachefile): + self.debugFP.write(fmt % (target, os.path.split(cachefile)[1])) + + def CacheDebugQuiet(self, fmt, target, cachefile): + pass + + def CacheDebugInit(self, fmt, target, cachefile): + if cache_debug: + if cache_debug == '-': + self.debugFP = sys.stdout + else: + self.debugFP = open(cache_debug, 'w') + self.CacheDebug = self.CacheDebugWrite + self.CacheDebug(fmt, target, cachefile) + else: + self.CacheDebug = self.CacheDebugQuiet + + CacheDebug = CacheDebugInit + + def cachepath(self, node): + """ + """ + sig = node.get_cachedir_bsig() + subdir = string.upper(sig[0]) + dir = os.path.join(self.path, subdir) + return dir, os.path.join(dir, sig) + + def retrieve(self, node): + """ + This method is called from multiple threads in a parallel build, + so only do thread safe stuff here. Do thread unsafe stuff in + built(). + + Note that there's a special trick here with the execute flag + (one that's not normally done for other actions). Basically + if the user requested a no_exec (-n) build, then + SCons.Action.execute_actions is set to 0 and when any action + is called, it does its showing but then just returns zero + instead of actually calling the action execution operation. + The problem for caching is that if the file does NOT exist in + cache then the CacheRetrieveString won't return anything to + show for the task, but the Action.__call__ won't call + CacheRetrieveFunc; instead it just returns zero, which makes + the code below think that the file *was* successfully + retrieved from the cache, therefore it doesn't do any + subsequent building. However, the CacheRetrieveString didn't + print anything because it didn't actually exist in the cache, + and no more build actions will be performed, so the user just + sees nothing. The fix is to tell Action.__call__ to always + execute the CacheRetrieveFunc and then have the latter + explicitly check SCons.Action.execute_actions itself. + """ + retrieved = False + + if cache_show: + if CacheRetrieveSilent(node, [], node.get_build_env(), execute=1) == 0: + node.build(presub=0, execute=0) + retrieved = 1 + else: + if CacheRetrieve(node, [], node.get_build_env(), execute=1) == 0: + retrieved = 1 + if retrieved: + # Record build signature information, but don't + # push it out to cache. (We just got it from there!) + node.set_state(SCons.Node.executed) + SCons.Node.Node.built(node) + + return retrieved + + def push(self, node): + return CachePush(node, [], node.get_build_env()) + + def push_if_forced(self, node): + if cache_force: + return self.push(node) + +class Null(SCons.Util.Null): + def repr(self): + return 'CacheDir.Null()' + def cachepath(self, node): + return None, None + def retrieve(self, node): + return False diff --git a/scons/scons-local-0.97/SCons/Conftest.py b/scons/scons-local-0.97.0d20071212/SCons/Conftest.py similarity index 85% rename from scons/scons-local-0.97/SCons/Conftest.py rename to scons/scons-local-0.97.0d20071212/SCons/Conftest.py index 81a8ee4d1..fcf8c5a75 100644 --- a/scons/scons-local-0.97/SCons/Conftest.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Conftest.py @@ -318,6 +318,102 @@ int main() { return ret +def CheckTypeSize(context, type_name, header = None, language = None, expect = None): + """This check can be used to get the size of a given type, or to check whether + the type is of expected size. + + Arguments: + - type : str + the type to check + - includes : sequence + list of headers to include in the test code before testing the type + - language : str + 'C' or 'C++' + - expect : int + if given, will test wether the type has the given number of bytes. + If not given, will automatically find the size. + + Returns: + status : int + 0 if the check failed, or the found size of the type if the check succeeded.""" + + # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. + if context.headerfilename: + includetext = '#include "%s"' % context.headerfilename + else: + includetext = '' + + if not header: + header = "" + + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("Cannot check for %s type: %s\n" % (type_name, msg)) + return msg + + src = includetext + header + if not expect is None: + # Only check if the given size is the right one + context.Display('Checking %s is %d bytes... ' % (type_name, expect)) + + # test code taken from autoconf: this is a pretty clever hack to find that + # a type is of a given size using only compilation. This speeds things up + # quite a bit compared to straightforward code using TryRun + src = src + r""" +typedef %s scons_check_type; + +int main() +{ + static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)]; + test_array[0] = 0; + + return 0; +} +""" + + # XXX: Try* vs CompileProg ? + st = context.TryCompile(src % (type_name, expect), suffix) + if st: + _Have(context, "SIZEOF_" + type_name, str(expect)) + context.Display("yes\n") + return expect + else: + context.Display("no\n") + _LogFailed(context, src, st) + return 0 + else: + # Only check if the given size is the right one + context.Message('Checking size of %s ... ' % type_name) + + # We have to be careful with the program we wish to test here since + # compilation will be attempted using the current environment's flags. + # So make sure that the program will compile without any warning. For + # example using: 'int main(int argc, char** argv)' will fail with the + # '-Wall -Werror' flags since the variables argc and argv would not be + # used in the program... + # + src = src + """ +#include +#include +int main() { + printf("%d", (int)sizeof(""" + type_name + """)); + return 0; +} + """ + ret = context.TryRun(src, suffix) + st = ret[0] + try: + size = int(ret[1]) + _Have(context, "SIZEOF_" + type_name, str(size)) + context.Display("%d\n" % size) + except ValueError: + size = 0 + _LogFailed(context, src, st) + context.Display(" Failed !\n") + if st: + return size + else: + return 0 def CheckLib(context, libs, func_name = None, header = None, extra_libs = None, call = None, language = None, autoadd = 1): @@ -462,7 +558,7 @@ def _Have(context, key, have): key_up = re.sub('[^A-Z0-9_]', '_', key_up) context.havedict[key_up] = have if have == 1: - line = "#define %s\n" % key_up + line = "#define %s 1\n" % key_up elif have == 0: line = "/* #undef %s */\n" % key_up elif type(have) == IntType: diff --git a/scons/scons-local-0.97/SCons/Debug.py b/scons/scons-local-0.97.0d20071212/SCons/Debug.py similarity index 98% rename from scons/scons-local-0.97/SCons/Debug.py rename to scons/scons-local-0.97.0d20071212/SCons/Debug.py index 6ca2779af..c2e552d71 100644 --- a/scons/scons-local-0.97/SCons/Debug.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Debug.py @@ -29,7 +29,7 @@ needed by most users. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Debug.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Debug.py 2523 2007/12/12 09:37:41 knight" import os import string @@ -197,3 +197,4 @@ def Trace(msg, file=None, mode='w'): # Assume we were passed an open file pointer. fp = file fp.write(msg) + fp.flush() diff --git a/scons/scons-local-0.97/SCons/Defaults.py b/scons/scons-local-0.97.0d20071212/SCons/Defaults.py similarity index 70% rename from scons/scons-local-0.97/SCons/Defaults.py rename to scons/scons-local-0.97.0d20071212/SCons/Defaults.py index 488518039..e4b0391c1 100644 --- a/scons/scons-local-0.97/SCons/Defaults.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Defaults.py @@ -32,7 +32,7 @@ from distutils.msvccompiler. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Defaults.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Defaults.py 2523 2007/12/12 09:37:41 knight" @@ -46,9 +46,9 @@ import sys import SCons.Action import SCons.Builder +import SCons.CacheDir import SCons.Environment import SCons.PathList -import SCons.Sig import SCons.Subst import SCons.Tool @@ -60,12 +60,40 @@ _default_env = None # Lazily instantiate the default environment so the overhead of creating # it doesn't apply when it's not needed. +def _fetch_DefaultEnvironment(*args, **kw): + """ + Returns the already-created default construction environment. + """ + global _default_env + return _default_env + def DefaultEnvironment(*args, **kw): + """ + Initial public entry point for creating the default construction + Environment. + + After creating the environment, we overwrite our name + (DefaultEnvironment) with the _fetch_DefaultEnvironment() function, + which more efficiently returns the initialized default construction + environment without checking for its existence. + + (This function still exists with its _default_check because someone + else (*cough* Script/__init__.py *cough*) may keep a reference + to this function. So we can't use the fully functional idiom of + having the name originally be a something that *only* creates the + construction environment and then overwrites the name.) + """ global _default_env if not _default_env: + import SCons.Util _default_env = apply(SCons.Environment.Environment, args, kw) - _default_env._build_signature = 1 - _default_env._calc_module = SCons.Sig.default_module + if SCons.Util.md5: + _default_env.Decider('MD5') + else: + _default_env.Decider('timestamp-match') + global DefaultEnvironment + DefaultEnvironment = _fetch_DefaultEnvironment + _default_env._CacheDir = SCons.CacheDir.Null() return _default_env # Emitters for setting the shared attribute on object files, @@ -104,9 +132,9 @@ LaTeXScan = SCons.Tool.LaTeXScanner ObjSourceScan = SCons.Tool.SourceFileScanner ProgScan = SCons.Tool.ProgramScanner -# This isn't really a tool scanner, so it doesn't quite belong with -# the rest of those in Tool/__init__.py, but I'm not sure where else it -# should go. Leave it here for now. +# These aren't really tool scanners, so they don't quite belong with +# the rest of those in Tool/__init__.py, but I'm not sure where else +# they should go. Leave them here for now. import SCons.Scanner.Dir DirScanner = SCons.Scanner.Dir.DirScanner() DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner() @@ -129,19 +157,28 @@ LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR") # ways by creating ActionFactory instances. ActionFactory = SCons.Action.ActionFactory -Chmod = ActionFactory(os.chmod, +def chmod_func(path, mode): + return os.chmod(str(path), mode) + +Chmod = ActionFactory(chmod_func, lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode)) def copy_func(dest, src): - if os.path.isfile(src): + if SCons.Util.is_List(src) and os.path.isdir(dest): + for file in src: + shutil.copy(file, dest) + return 0 + elif os.path.isfile(src): return shutil.copy(src, dest) else: return shutil.copytree(src, dest, 1) Copy = ActionFactory(copy_func, - lambda dest, src: 'Copy("%s", "%s")' % (dest, src)) + lambda dest, src: 'Copy("%s", "%s")' % (dest, src), + convert=str) def delete_func(entry, must_exist=0): + entry = str(entry) if not must_exist and not os.path.exists(entry): return None if not os.path.exists(entry) or os.path.isfile(entry): @@ -155,12 +192,15 @@ def delete_strfunc(entry, must_exist=0): Delete = ActionFactory(delete_func, delete_strfunc) Mkdir = ActionFactory(os.makedirs, - lambda dir: 'Mkdir("%s")' % dir) + lambda dir: 'Mkdir("%s")' % dir, + convert=str) Move = ActionFactory(lambda dest, src: os.rename(src, dest), - lambda dest, src: 'Move("%s", "%s")' % (dest, src)) + lambda dest, src: 'Move("%s", "%s")' % (dest, src), + convert=str) def touch_func(file): + file = str(file) mtime = int(time.time()) if os.path.exists(file): atime = os.path.getatime(file) @@ -173,33 +213,6 @@ Touch = ActionFactory(touch_func, lambda file: 'Touch("%s")' % file) # Internal utility functions -def installFunc(dest, source, env): - """Install a source file or directory into a destination by copying, - (including copying permission/mode bits).""" - - if os.path.isdir(source): - if os.path.exists(dest): - if not os.path.isdir(dest): - raise SCons.Errors.UserError, "cannot overwrite non-directory `%s' with a directory `%s'" % (str(dest), str(source)) - else: - parent = os.path.split(dest)[0] - if not os.path.exists(parent): - os.makedirs(parent) - shutil.copytree(source, dest) - else: - shutil.copy2(source, dest) - st = os.stat(source) - os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) - - return 0 - -def installStr(dest, source, env): - source = str(source) - if os.path.isdir(source): - type = 'directory' - else: - type = 'file' - return 'Install %s: "%s" as "%s"' % (type, source, dest) def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None): """ @@ -258,91 +271,46 @@ def _concat_ixes(prefix, list, suffix, env): return result def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=None): - """This is a wrapper around _concat() that checks for the existence - of prefixes or suffixes on list elements and strips them where it - finds them. This is used by tools (like the GNU linker) that need - to turn something like 'libfoo.a' into '-lfoo'.""" + """ + This is a wrapper around _concat()/_concat_ixes() that checks for the + existence of prefixes or suffixes on list elements and strips them + where it finds them. This is used by tools (like the GNU linker) + that need to turn something like 'libfoo.a' into '-lfoo'. + """ - if not callable(c): - if callable(env["_concat"]): - c = env["_concat"] - else: - c = _concat - def f(list, sp=stripprefix, ss=stripsuffix): - result = [] - for l in list: - if isinstance(l, SCons.Node.FS.File): - result.append(l) - continue - if not SCons.Util.is_String(l): - l = str(l) - if l[:len(sp)] == sp: - l = l[len(sp):] - if l[-len(ss):] == ss: - l = l[:-len(ss)] - result.append(l) - return result - return c(prefix, list, suffix, env, f) + if not list: + return list -# This is an alternate _stripixes() function that passes all of our tests -# (as of 21 February 2007), like the current version above. It's more -# straightforward because it does its manipulation directly, not using -# the funky f call-back function to _concat(). (In this respect it's -# like the updated _defines() function below.) -# -# The most convoluted thing is that it still uses a custom _concat() -# function if one was placed in the construction environment; there's -# a specific test for that functionality, but it might be worth getting -# rid of. -# -# Since this work was done while trying to get 0.97 out the door -# (just prior to 0.96.96), I decided to be cautious and leave the old -# function as is, to minimize the chance of other corner-case regressions. -# The updated version is captured here so we can uncomment it and start -# using it at a less sensitive time in the development cycle (or when -# it's clearly required to fix something). -# -#def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=None): -# """ -# This is a wrapper around _concat()/_concat_ixes() that checks for the -# existence of prefixes or suffixes on list elements and strips them -# where it finds them. This is used by tools (like the GNU linker) -# that need to turn something like 'libfoo.a' into '-lfoo'. -# """ -# -# if not list: -# return list -# -# if not callable(c): -# env_c = env['_concat'] -# if env_c != _concat and callable(env_c): -# # There's a custom _concat() method in the construction -# # environment, and we've allowed people to set that in -# # the past (see test/custom-concat.py), so preserve the -# # backwards compatibility. -# c = env_c -# else: -# c = _concat_ixes -# -# if SCons.Util.is_List(list): -# list = SCons.Util.flatten(list) -# -# lsp = len(stripprefix) -# lss = len(stripsuffix) -# stripped = [] -# for l in SCons.PathList.PathList(list).subst_path(env, None, None): -# if isinstance(l, SCons.Node.FS.File): -# stripped.append(l) -# continue -# if not SCons.Util.is_String(l): -# l = str(l) -# if l[:lsp] == stripprefix: -# l = l[lsp:] -# if l[-lss:] == stripsuffix: -# l = l[:-lss] -# stripped.append(l) -# -# return c(prefix, stripped, suffix, env) + if not callable(c): + env_c = env['_concat'] + if env_c != _concat and callable(env_c): + # There's a custom _concat() method in the construction + # environment, and we've allowed people to set that in + # the past (see test/custom-concat.py), so preserve the + # backwards compatibility. + c = env_c + else: + c = _concat_ixes + + if SCons.Util.is_List(list): + list = SCons.Util.flatten(list) + + lsp = len(stripprefix) + lss = len(stripsuffix) + stripped = [] + for l in SCons.PathList.PathList(list).subst_path(env, None, None): + if isinstance(l, SCons.Node.FS.File): + stripped.append(l) + continue + if not SCons.Util.is_String(l): + l = str(l) + if l[:lsp] == stripprefix: + l = l[lsp:] + if l[-lss:] == stripsuffix: + l = l[:-lss] + stripped.append(l) + + return c(prefix, stripped, suffix, env) def _defines(prefix, defs, suffix, env, c=_concat_ixes): """A wrapper around _concat_ixes that turns a list or string @@ -430,9 +398,6 @@ ConstructionEnvironment = { 'DSUFFIXES' : SCons.Tool.DSuffixes, 'ENV' : {}, 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes, - 'INSTALL' : installFunc, - 'INSTALLSTR' : installStr, - '_installStr' : installStr, 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, '_concat' : _concat, '_defines' : _defines, diff --git a/scons/scons-local-0.97/SCons/Environment.py b/scons/scons-local-0.97.0d20071212/SCons/Environment.py similarity index 82% rename from scons/scons-local-0.97/SCons/Environment.py rename to scons/scons-local-0.97.0d20071212/SCons/Environment.py index f94c5f549..c3244795f 100644 --- a/scons/scons-local-0.97/SCons/Environment.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Environment.py @@ -6,7 +6,7 @@ construction information to the build engine. Keyword arguments supplied when the construction Environment is created are construction variables used to initialize the -Environment +Environment """ # @@ -32,12 +32,13 @@ Environment # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Environment.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Environment.py 2523 2007/12/12 09:37:41 knight" import copy import os import os.path +import shlex import string from UserDict import UserDict @@ -53,7 +54,6 @@ import SCons.Node.FS import SCons.Node.Python import SCons.Platform import SCons.SConsign -import SCons.Sig import SCons.Subst import SCons.Tool import SCons.Util @@ -67,32 +67,13 @@ _null = _Null CleanTargets = {} CalculatorArgs = {} +semi_deepcopy = SCons.Util.semi_deepcopy + # Pull UserError into the global name space for the benefit of # Environment().SourceSignatures(), which has some import statements # which seem to mess up its ability to reference SCons directly. UserError = SCons.Errors.UserError -def installFunc(target, source, env): - """Install a source file into a target using the function specified - as the INSTALL construction variable.""" - try: - install = env['INSTALL'] - except KeyError: - raise SCons.Errors.UserError('Missing INSTALL construction variable.') - return install(target[0].path, source[0].path, env) - -def installString(target, source, env): - s = env.get('INSTALLSTR', '') - if callable(s): - return s(target[0].path, source[0].path, env) - else: - return env.subst_target_source(s, 0, target, source) - -installAction = SCons.Action.Action(installFunc, installString) - -InstallBuilder = SCons.Builder.Builder(action=installAction, - name='InstallBuilder') - def alias_builder(env, target, source): pass @@ -103,23 +84,6 @@ AliasBuilder = SCons.Builder.Builder(action = alias_builder, is_explicit = None, name='AliasBuilder') -def our_deepcopy(x): - """deepcopy lists and dictionaries, and just copy the reference - for everything else.""" - if SCons.Util.is_Dict(x): - copy = {} - for key in x.keys(): - copy[key] = our_deepcopy(x[key]) - elif SCons.Util.is_List(x): - copy = map(our_deepcopy, x) - try: - copy = x.__class__(copy) - except AttributeError: - pass - else: - copy = x - return copy - def apply_tools(env, tools, toolpath): # Store the toolpath in the Environment. if toolpath is not None: @@ -143,7 +107,7 @@ reserved_construction_var_names = \ ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES'] def copy_non_reserved_keywords(dict): - result = our_deepcopy(dict) + result = semi_deepcopy(dict) for k in result.keys(): if k in reserved_construction_var_names: SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, @@ -161,8 +125,9 @@ def _set_BUILDERS(env, key, value): for k in bd.keys(): del bd[k] except KeyError: - env._dict[key] = BuilderDict(kwbd, env) - env._dict[key].update(value) + bd = BuilderDict(kwbd, env) + env._dict[key] = bd + bd.update(value) def _del_SCANNERS(env, key): del env._dict[key] @@ -172,13 +137,72 @@ def _set_SCANNERS(env, key, value): env._dict[key] = value env.scanner_map_delete() -class BuilderWrapper: - """Wrapper class that associates an environment with a Builder at - instantiation.""" - def __init__(self, env, builder): - self.env = env - self.builder = builder + +# The following is partly based on code in a comment added by Peter +# Shannon at the following page (there called the "transplant" class): +# +# ASPN : Python Cookbook : Dynamically added methods to a class +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 +# +# We had independently been using the idiom as BuilderWrapper, but +# factoring out the common parts into this base class, and making +# BuilderWrapper a subclass that overrides __call__() to enforce specific +# Builder calling conventions, simplified some of our higher-layer code. + +class MethodWrapper: + """ + A generic Wrapper class that associates a method (which can + actually be any callable) with an object. As part of creating this + MethodWrapper object an attribute with the specified (by default, + the name of the supplied method) is added to the underlying object. + When that new "method" is called, our __call__() method adds the + object as the first argument, simulating the Python behavior of + supplying "self" on method calls. + + We hang on to the name by which the method was added to the underlying + base class so that we can provide a method to "clone" ourselves onto + a new underlying object being copied (without which we wouldn't need + to save that info). + """ + def __init__(self, object, method, name=None): + if name is None: + name = method.__name__ + self.object = object + self.method = method + self.name = name + setattr(self.object, name, self) + + def __call__(self, *args, **kwargs): + nargs = (self.object,) + args + return apply(self.method, nargs, kwargs) + + def clone(self, new_object): + """ + Returns an object that re-binds the underlying "method" to + the specified new object. + """ + return self.__class__(new_object, self.method, self.name) + +class BuilderWrapper(MethodWrapper): + """ + A MethodWrapper subclass that that associates an environment with + a Builder. + + This mainly exists to wrap the __call__() function so that all calls + to Builders can have their argument lists massaged in the same way + (treat a lone argument as the source, treat two arguments as target + then source, make sure both target and source are lists) without + having to have cut-and-paste code to do it. + + As a bit of obsessive backwards compatibility, we also intercept + attempts to get or set the "env" or "builder" attributes, which were + the names we used before we put the common functionality into the + MethodWrapper base class. We'll keep this around for a while in case + people shipped Tool modules that reached into the wrapper (like the + Tool/qt.py module does, or did). There shouldn't be a lot attribute + fetching or setting on these, so a little extra work shouldn't hurt. + """ def __call__(self, target=None, source=_null, *args, **kw): if source is _null: source = target @@ -187,7 +211,29 @@ class BuilderWrapper: target = [target] if not source is None and not SCons.Util.is_List(source): source = [source] - return apply(self.builder, (self.env, target, source) + args, kw) + return apply(MethodWrapper.__call__, (self, target, source) + args, kw) + + def __repr__(self): + return '' % repr(self.name) + + def __str__(self): + return self.__repr__() + + def __getattr__(self, name): + if name == 'env': + return self.object + elif name == 'builder': + return self.method + else: + return self.__dict__[name] + + def __setattr__(self, name, value): + if name == 'env': + self.object = value + elif name == 'builder': + self.method = value + else: + self.__dict__[name] = value # This allows a Builder to be executed directly # through the Environment to which it's attached. @@ -196,9 +242,9 @@ class BuilderWrapper: # But we do have a unit test for this, and can't # yet rule out that it would be useful in the # future, so leave it for now. - def execute(self, **kw): - kw['env'] = self.env - apply(self.builder.execute, (), kw) + #def execute(self, **kw): + # kw['env'] = self.env + # apply(self.builder.execute, (), kw) class BuilderDict(UserDict): """This is a dictionary-like class used by an Environment to hold @@ -212,28 +258,18 @@ class BuilderDict(UserDict): self.env = env UserDict.__init__(self, dict) + def __semi_deepcopy__(self): + return self.__class__(self.data, self.env) + def __setitem__(self, item, val): - UserDict.__setitem__(self, item, val) try: - self.setenvattr(item, val) + method = getattr(self.env, item).method except AttributeError: - # Have to catch this because sometimes __setitem__ gets - # called out of __init__, when we don't have an env - # attribute yet, nor do we want one! pass - - def setenvattr(self, item, val): - """Set the corresponding environment attribute for this Builder. - - If the value is already a BuilderWrapper, we pull the builder - out of it and make another one, so that making a copy of an - existing BuilderDict is guaranteed separate wrappers for each - Builder + Environment pair.""" - try: - builder = val.builder - except AttributeError: - builder = val - setattr(self.env, item, BuilderWrapper(self.env, builder)) + else: + self.env.RemoveMethod(method) + UserDict.__setitem__(self, item, val) + BuilderWrapper(self.env, val, item) def __delitem__(self, item): UserDict.__delitem__(self, item) @@ -276,11 +312,12 @@ class SubstitutionEnvironment: """Initialization of an underlying SubstitutionEnvironment class. """ if __debug__: logInstanceCreation(self, 'Environment.SubstitutionEnvironment') - self.fs = SCons.Node.FS.default_fs or SCons.Node.FS.FS() + self.fs = SCons.Node.FS.get_default_fs() self.ans = SCons.Node.Alias.default_ans self.lookup_list = SCons.Node.arg2nodes_lookups self._dict = kw.copy() self._init_special() + self.added_methods = [] #self._memo = {} def _init_special(self): @@ -327,7 +364,7 @@ class SubstitutionEnvironment: def items(self): return self._dict.items() - def arg2nodes(self, args, node_factory=_null, lookup_list=_null): + def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw): if node_factory is _null: node_factory = self.fs.File if lookup_list is _null: @@ -351,7 +388,9 @@ class SubstitutionEnvironment: break if not n is None: if SCons.Util.is_String(n): - n = self.subst(n, raw=1) + # n = self.subst(n, raw=1, **kw) + kw['raw'] = 1 + n = apply(self.subst, (n,), kw) if node_factory: n = node_factory(n) if SCons.Util.is_List(n): @@ -359,14 +398,16 @@ class SubstitutionEnvironment: else: nodes.append(n) elif node_factory: - v = node_factory(self.subst(v, raw=1)) + # v = node_factory(self.subst(v, raw=1, **kw)) + kw['raw'] = 1 + v = node_factory(apply(self.subst, (v,), kw)) if SCons.Util.is_List(v): nodes.extend(v) else: nodes.append(v) else: nodes.append(v) - + return nodes def gvars(self): @@ -473,6 +514,23 @@ class SubstitutionEnvironment: raise OSError("'%s' exited %d" % (command, status)) return out + def AddMethod(self, function, name=None): + """ + Adds the specified function as a method of this construction + environment with the specified name. If the name is omitted, + the default name is the name of the function itself. + """ + method = MethodWrapper(self, function, name) + self.added_methods.append(method) + + def RemoveMethod(self, function): + """ + Removes the specified function's MethodWrapper from the + added_methods list, so we don't re-bind it when making a clone. + """ + is_not_func = lambda dm, f=function: not dm.method is f + self.added_methods = filter(is_not_func, self.added_methods) + def Override(self, overrides): """ Produce a modified environment whose variables are overriden by @@ -564,7 +622,7 @@ class SubstitutionEnvironment: # -R dir (deprecated linker rpath) # IBM compilers may also accept -qframeworkdir=foo - params = string.split(arg) + params = shlex.split(arg) append_next_arg_to = None # for multi-word args for arg in params: if append_next_arg_to: @@ -705,6 +763,29 @@ class SubstitutionEnvironment: self[key] = t return self +# Used by the FindSourceFiles() method, below. +# Stuck here for support of pre-2.2 Python versions. +def build_source(ss, result): + for s in ss: + if isinstance(s, SCons.Node.FS.Dir): + build_source(s.all_children(), result) + elif s.has_builder(): + build_source(s.sources, result) + elif isinstance(s.disambiguate(), SCons.Node.FS.File): + result.append(s) + +def default_decide_source(dependency, target, prev_ni): + f = SCons.Defaults.DefaultEnvironment().decide_source + return f(dependency, target, prev_ni) + +def default_decide_target(dependency, target, prev_ni): + f = SCons.Defaults.DefaultEnvironment().decide_target + return f(dependency, target, prev_ni) + +def default_copy_from_cache(src, dst): + f = SCons.Defaults.DefaultEnvironment().copy_from_cache + return f(src, dst) + class Base(SubstitutionEnvironment): """Base class for "real" construction Environments. These are the primary objects used to communicate dependency and construction @@ -752,11 +833,23 @@ class Base(SubstitutionEnvironment): """ if __debug__: logInstanceCreation(self, 'Environment.Base') self._memo = {} - self.fs = SCons.Node.FS.default_fs or SCons.Node.FS.FS() + self.fs = SCons.Node.FS.get_default_fs() self.ans = SCons.Node.Alias.default_ans self.lookup_list = SCons.Node.arg2nodes_lookups - self._dict = our_deepcopy(SCons.Defaults.ConstructionEnvironment) + self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment) self._init_special() + self.added_methods = [] + + # We don't use AddMethod, or define these as methods in this + # class, because we *don't* want these functions to be bound + # methods. They need to operate independently so that the + # settings will work properly regardless of whether a given + # target ends up being built with a Base environment or an + # OverrideEnvironment or what have you. + self.decide_target = default_decide_target + self.decide_source = default_decide_source + + self.copy_from_cache = default_copy_from_cache self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self) @@ -787,6 +880,8 @@ class Base(SubstitutionEnvironment): # reserved variable name like TARGETS. pass + SCons.Tool.Initializers(self) + if tools is None: tools = self._dict.get('TOOLS', None) if tools is None: @@ -812,16 +907,13 @@ class Base(SubstitutionEnvironment): except KeyError: return None - def get_calculator(self): + def get_CacheDir(self): try: - module = self._calc_module - c = apply(SCons.Sig.Calculator, (module,), CalculatorArgs) + return self._CacheDir except AttributeError: - # Note that we're calling get_calculator() here, so the - # DefaultEnvironment() must have a _calc_module attribute - # to avoid infinite recursion. - c = SCons.Defaults.DefaultEnvironment().get_calculator() - return c + cd = SCons.Defaults.DefaultEnvironment()._CacheDir + self._CacheDir = cd + return cd def get_factory(self, factory, default='File'): """Return a factory function for creating Nodes for this @@ -883,7 +975,7 @@ class Base(SubstitutionEnvironment): self._memo['_gsm'] = result return result - + def get_scanner(self, skey): """Find the appropriate scanner given a key (usually a file suffix). """ @@ -903,13 +995,21 @@ class Base(SubstitutionEnvironment): """ self._dict.update(dict) - def use_build_signature(self): + def get_src_sig_type(self): try: - return self._build_signature + return self.src_sig_type except AttributeError: - b = SCons.Defaults.DefaultEnvironment()._build_signature - self._build_signature = b - return b + t = SCons.Defaults.DefaultEnvironment().src_sig_type + self.src_sig_type = t + return t + + def get_tgt_sig_type(self): + try: + return self.tgt_sig_type + except AttributeError: + t = SCons.Defaults.DefaultEnvironment().tgt_sig_type + self.tgt_sig_type = t + return t ####################################################################### # Public methods for manipulating an Environment. These begin with @@ -978,7 +1078,11 @@ class Base(SubstitutionEnvironment): try: update_dict(val) except (AttributeError, TypeError, ValueError): - orig[val] = None + if SCons.Util.is_Dict(val): + for k, v in val.items(): + orig[k] = v + else: + orig[val] = None self.scanner_map_delete(kw) def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep): @@ -994,7 +1098,7 @@ class Base(SubstitutionEnvironment): orig = self._dict[envname][name] nv = SCons.Util.AppendPath(orig, newpath, sep) - + if not self._dict.has_key(envname): self._dict[envname] = {} @@ -1037,29 +1141,95 @@ class Base(SubstitutionEnvironment): objects in the original Environment. """ clone = copy.copy(self) - clone._dict = our_deepcopy(self._dict) + clone._dict = semi_deepcopy(self._dict) + try: cbd = clone._dict['BUILDERS'] - clone._dict['BUILDERS'] = BuilderDict(cbd, clone) except KeyError: pass + else: + clone._dict['BUILDERS'] = BuilderDict(cbd, clone) + + clone.added_methods = [] + for mw in self.added_methods: + clone.added_methods.append(mw.clone(clone)) clone._memo = {} - apply_tools(clone, tools, toolpath) - - # Apply passed-in variables after the new tools. + # Apply passed-in variables before the tools + # so the tools can use the new variables kw = copy_non_reserved_keywords(kw) new = {} for key, value in kw.items(): new[key] = SCons.Subst.scons_subst_once(value, self, key) apply(clone.Replace, (), new) + + apply_tools(clone, tools, toolpath) + + # apply them again in case the tools overwrote them + apply(clone.Replace, (), new) + if __debug__: logInstanceCreation(self, 'Environment.EnvironmentClone') return clone def Copy(self, *args, **kw): return apply(self.Clone, args, kw) + def _changed_build(self, dependency, target, prev_ni): + if dependency.changed_state(target, prev_ni): + return 1 + return self.decide_source(dependency, target, prev_ni) + + def _changed_content(self, dependency, target, prev_ni): + return dependency.changed_content(target, prev_ni) + + def _changed_source(self, dependency, target, prev_ni): + target_env = dependency.get_build_env() + type = target_env.get_tgt_sig_type() + if type == 'source': + return target_env.decide_source(dependency, target, prev_ni) + else: + return target_env.decide_target(dependency, target, prev_ni) + + def _changed_timestamp_then_content(self, dependency, target, prev_ni): + return dependency.changed_timestamp_then_content(target, prev_ni) + + def _changed_timestamp_newer(self, dependency, target, prev_ni): + return dependency.changed_timestamp_newer(target, prev_ni) + + def _changed_timestamp_match(self, dependency, target, prev_ni): + return dependency.changed_timestamp_match(target, prev_ni) + + def _copy_from_cache(self, src, dst): + return self.fs.copy(src, dst) + + def _copy2_from_cache(self, src, dst): + return self.fs.copy2(src, dst) + + def Decider(self, function): + copy_function = self._copy2_from_cache + if function in ('MD5', 'content'): + if not SCons.Util.md5: + raise UserError, "MD5 signatures are not available in this version of Python." + function = self._changed_content + elif function == 'MD5-timestamp': + function = self._changed_timestamp_then_content + elif function in ('timestamp-newer', 'make'): + function = self._changed_timestamp_newer + copy_function = self._copy_from_cache + elif function == 'timestamp-match': + function = self._changed_timestamp_match + elif not callable(function): + raise UserError, "Unknown Decider value %s" % repr(function) + + # We don't use AddMethod because we don't want to turn the + # function, which only expects three arguments, into a bound + # method, which would add self as an initial, fourth argument. + self.decide_target = function + self.decide_source = function + + self.copy_from_cache = copy_function + def Detect(self, progs): """Return the first available program in progs. """ @@ -1110,7 +1280,7 @@ class Base(SubstitutionEnvironment): for path in paths: dir,name = os.path.split(str(path)) - if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: + if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: return path def ParseConfig(self, command, function=None, unique=1): @@ -1233,7 +1403,11 @@ class Base(SubstitutionEnvironment): try: update_dict(val) except (AttributeError, TypeError, ValueError): - orig[val] = None + if SCons.Util.is_Dict(val): + for k, v in val.items(): + orig[k] = v + else: + orig[val] = None self.scanner_map_delete(kw) def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep): @@ -1249,7 +1423,7 @@ class Base(SubstitutionEnvironment): orig = self._dict[envname][name] nv = SCons.Util.PrependPath(orig, newpath, sep) - + if not self._dict.has_key(envname): self._dict[envname] = {} @@ -1288,13 +1462,15 @@ class Base(SubstitutionEnvironment): with new construction variables and/or values. """ try: - kwbd = our_deepcopy(kw['BUILDERS']) - del kw['BUILDERS'] - self.__setitem__('BUILDERS', kwbd) + kwbd = kw['BUILDERS'] except KeyError: pass + else: + kwbd = semi_deepcopy(kwbd) + del kw['BUILDERS'] + self.__setitem__('BUILDERS', kwbd) kw = copy_non_reserved_keywords(kw) - self._update(our_deepcopy(kw)) + self._update(semi_deepcopy(kw)) self.scanner_map_delete(kw) def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix): @@ -1453,7 +1629,7 @@ class Base(SubstitutionEnvironment): def AlwaysBuild(self, *targets): tlist = [] for t in targets: - tlist.extend(self.arg2nodes(t, self.fs.File)) + tlist.extend(self.arg2nodes(t, self.fs.Entry)) for t in tlist: t.set_always_build() return tlist @@ -1468,7 +1644,11 @@ class Base(SubstitutionEnvironment): return apply(SCons.Builder.Builder, [], nkw) def CacheDir(self, path): - self.fs.CacheDir(self.subst(path)) + import SCons.CacheDir + if path is None: + self._CacheDir = SCons.CacheDir.Null() + else: + self._CacheDir = SCons.CacheDir.CacheDir(self.subst(path)) def Clean(self, targets, files): global CleanTargets @@ -1551,7 +1731,11 @@ class Base(SubstitutionEnvironment): """Directly execute an action through an Environment """ action = apply(self.Action, (action,) + args, kw) - return action([], [], self) + result = action([], [], self) + if isinstance(result, SCons.Errors.BuildError): + return result.status + else: + return result def File(self, name, *args, **kw): """ @@ -1573,6 +1757,9 @@ class Base(SubstitutionEnvironment): else: return result[0] + def Glob(self, pattern, ondisk=True, source=False, strings=False): + return self.fs.Glob(self.subst(pattern), ondisk, source, strings) + def Ignore(self, target, dependency): """Ignore a dependency.""" tlist = self.arg2nodes(target, self.fs.Entry) @@ -1581,50 +1768,6 @@ class Base(SubstitutionEnvironment): t.add_ignore(dlist) return tlist - def Install(self, dir, source): - """Install specified files in the given directory.""" - try: - dnodes = self.arg2nodes(dir, self.fs.Dir) - except TypeError: - fmt = "Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" - raise SCons.Errors.UserError, fmt % str(dir) - try: - sources = self.arg2nodes(source, self.fs.Entry) - except TypeError: - if SCons.Util.is_List(source): - s = repr(map(str, source)) - else: - s = str(source) - fmt = "Source `%s' of Install() is neither a file nor a directory. Install() source must be one or more files or directories" - raise SCons.Errors.UserError, fmt % s - tgt = [] - for dnode in dnodes: - for src in sources: - # Prepend './' so the lookup doesn't interpret an initial - # '#' on the file name portion as meaning the Node should - # be relative to the top-level SConstruct directory. - target = self.fs.Entry('.'+os.sep+src.name, dnode) - tgt.extend(InstallBuilder(self, target, src)) - return tgt - - def InstallAs(self, target, source): - """Install sources as targets.""" - sources = self.arg2nodes(source, self.fs.Entry) - targets = self.arg2nodes(target, self.fs.Entry) - if len(sources) != len(targets): - if not SCons.Util.is_List(target): - target = [target] - if not SCons.Util.is_List(source): - source = [source] - t = repr(map(str, target)) - s = repr(map(str, source)) - fmt = "Target (%s) and source (%s) lists of InstallAs() must be the same length." - raise SCons.Errors.UserError, fmt % (t, s) - result = [] - for src, tgt in map(lambda x, y: (x, y), sources, targets): - result.extend(InstallBuilder(self, tgt, src)) - return result - def Literal(self, string): return SCons.Subst.Literal(string) @@ -1652,6 +1795,16 @@ class Base(SubstitutionEnvironment): dirs = self.arg2nodes(list(dirs), self.fs.Dir) apply(self.fs.Repository, dirs, kw) + def Requires(self, target, prerequisite): + """Specify that 'prerequisite' must be built before 'target', + (but 'target' does not actually depend on 'prerequisite' + and need not be rebuilt if it changes).""" + tlist = self.arg2nodes(target, self.fs.Entry) + plist = self.arg2nodes(prerequisite, self.fs.Entry) + for t in tlist: + t.add_prerequisite(plist) + return tlist + def Scanner(self, *args, **kw): nargs = [] for arg in args: @@ -1669,7 +1822,7 @@ class Base(SubstitutionEnvironment): SCons.SConsign.File(name, dbm_module) def SideEffect(self, side_effect, target): - """Tell scons that side_effects are built as side + """Tell scons that side_effects are built as side effects of building targets.""" side_effects = self.arg2nodes(side_effect, self.fs.Entry) targets = self.arg2nodes(target, self.fs.Entry) @@ -1693,21 +1846,15 @@ class Base(SubstitutionEnvironment): def SourceSignatures(self, type): type = self.subst(type) + self.src_sig_type = type if type == 'MD5': - try: - import SCons.Sig.MD5 - except ImportError: - msg = "No MD5 module available, using time stamps" - SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg) - import SCons.Sig.TimeStamp - self._calc_module = SCons.Sig.TimeStamp - else: - self._calc_module = SCons.Sig.MD5 + if not SCons.Util.md5: + raise UserError, "MD5 signatures are not available in this version of Python." + self.decide_source = self._changed_content elif type == 'timestamp': - import SCons.Sig.TimeStamp - self._calc_module = SCons.Sig.TimeStamp + self.decide_source = self._changed_timestamp_match else: - raise UserError, "Unknown source signature type '%s'"%type + raise UserError, "Unknown source signature type '%s'" % type def Split(self, arg): """This function converts a string or list into a list of strings @@ -1729,18 +1876,66 @@ class Base(SubstitutionEnvironment): def TargetSignatures(self, type): type = self.subst(type) - if type == 'build': - self._build_signature = 1 - elif type == 'content': - self._build_signature = 0 + self.tgt_sig_type = type + if type in ('MD5', 'content'): + if not SCons.Util.md5: + raise UserError, "MD5 signatures are not available in this version of Python." + self.decide_target = self._changed_content + elif type == 'timestamp': + self.decide_target = self._changed_timestamp_match + elif type == 'build': + self.decide_target = self._changed_build + elif type == 'source': + self.decide_target = self._changed_source else: - raise SCons.Errors.UserError, "Unknown target signature type '%s'"%type + raise UserError, "Unknown target signature type '%s'"%type def Value(self, value, built_value=None): """ """ return SCons.Node.Python.Value(value, built_value) + def FindSourceFiles(self, node='.'): + """ returns a list of all source files. + """ + node = self.arg2nodes(node, self.fs.Entry)[0] + + sources = [] + # Uncomment this and get rid of the global definition when we + # drop support for pre-2.2 Python versions. + #def build_source(ss, result): + # for s in ss: + # if isinstance(s, SCons.Node.FS.Dir): + # build_source(s.all_children(), result) + # elif s.has_builder(): + # build_source(s.sources, result) + # elif isinstance(s.disambiguate(), SCons.Node.FS.File): + # result.append(s) + build_source(node.all_children(), sources) + + # now strip the build_node from the sources by calling the srcnode + # function + def get_final_srcnode(file): + srcnode = file.srcnode() + while srcnode != file.srcnode(): + srcnode = file.srcnode() + return srcnode + + # get the final srcnode for all nodes, this means stripping any + # attached build node. + map( get_final_srcnode, sources ) + + # remove duplicates + return list(set(sources)) + + def FindInstalledFiles(self): + """ returns the list of all targets of the Install and InstallAs Builder. + """ + from SCons.Tool import install + if install._UNIQUE_INSTALLED_FILES is None: + install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES) + return install._UNIQUE_INSTALLED_FILES + class OverrideEnvironment(Base): """A proxy that overrides variables in a wrapped construction environment by returning values from an overrides dictionary in @@ -1839,7 +2034,7 @@ class OverrideEnvironment(Base): # Overridden public construction environment methods. def Replace(self, **kw): kw = copy_non_reserved_keywords(kw) - self.__dict__['overrides'].update(our_deepcopy(kw)) + self.__dict__['overrides'].update(semi_deepcopy(kw)) # The entry point that will be used by the external world # to refer to a construction environment. This allows the wrapper diff --git a/scons/scons-local-0.97/SCons/Errors.py b/scons/scons-local-0.97.0d20071212/SCons/Errors.py similarity index 82% rename from scons/scons-local-0.97/SCons/Errors.py rename to scons/scons-local-0.97.0d20071212/SCons/Errors.py index 9a65e13ec..428213663 100644 --- a/scons/scons-local-0.97/SCons/Errors.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Errors.py @@ -28,15 +28,21 @@ and user errors in SCons. """ -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Errors.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Errors.py 2523 2007/12/12 09:37:41 knight" class BuildError(Exception): - def __init__(self, node=None, errstr="Unknown error", filename=None, *args): + def __init__(self, node=None, errstr="Unknown error", status=0, + filename=None, executor=None, action=None, command=None, + *args): self.node = node self.errstr = errstr + self.status = status self.filename = filename + self.executor = executor + self.action = action + self.command = command apply(Exception.__init__, (self,) + args) class InternalError(Exception): @@ -48,6 +54,9 @@ class UserError(Exception): class StopError(Exception): pass +class EnvironmentError(Exception): + pass + class ExplicitExit(Exception): def __init__(self, node=None, status=None, *args): self.node = node diff --git a/scons/scons-local-0.97/SCons/Executor.py b/scons/scons-local-0.97.0d20071212/SCons/Executor.py similarity index 77% rename from scons/scons-local-0.97/SCons/Executor.py rename to scons/scons-local-0.97.0d20071212/SCons/Executor.py index c54747b47..f7179768c 100644 --- a/scons/scons-local-0.97/SCons/Executor.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Executor.py @@ -28,11 +28,12 @@ Nodes. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Executor.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Executor.py 2523 2007/12/12 09:37:41 knight" import string from SCons.Debug import logInstanceCreation +import SCons.Errors import SCons.Memoize @@ -59,6 +60,7 @@ class Executor: self.overridelist = overridelist self.targets = targets self.sources = sources[:] + self.sources_need_sorting = False self.builder_kw = builder_kw self._memo = {} @@ -74,10 +76,17 @@ class Executor: def get_action_list(self): return self.pre_actions + self.action_list + self.post_actions + memoizer_counters.append(SCons.Memoize.CountValue('get_build_env')) + def get_build_env(self): """Fetch or create the appropriate build Environment for this Executor. """ + try: + return self._memo['get_build_env'] + except KeyError: + pass + # Create the build environment instance with appropriate # overrides. These get evaluated against the current # environment's construction variables so that users can @@ -91,42 +100,49 @@ class Executor: env = self.env or SCons.Defaults.DefaultEnvironment() build_env = env.Override(overrides) + self._memo['get_build_env'] = build_env + return build_env def get_build_scanner_path(self, scanner): - """Fetch the scanner path for this executor's targets - and sources. + """Fetch the scanner path for this executor's targets and sources. """ env = self.get_build_env() try: cwd = self.targets[0].cwd except (IndexError, AttributeError): cwd = None - return scanner.path(env, cwd, self.targets, self.sources) + return scanner.path(env, cwd, self.targets, self.get_sources()) def get_kw(self, kw={}): result = self.builder_kw.copy() result.update(kw) return result - def do_nothing(self, target, exitstatfunc, kw): - pass + def do_nothing(self, target, kw): + return 0 - def do_execute(self, target, exitstatfunc, kw): + def do_execute(self, target, kw): """Actually execute the action list.""" env = self.get_build_env() kw = self.get_kw(kw) + status = 0 for act in self.get_action_list(): - apply(act, - (self.targets, self.sources, env, exitstatfunc), - kw) + status = apply(act, (self.targets, self.get_sources(), env), kw) + if isinstance(status, SCons.Errors.BuildError): + status.executor = self + raise status + elif status: + msg = "Error %s" % status + raise SCons.Errors.BuildError(errstr=msg, executor=self, action=act) + return status # use extra indirection because with new-style objects (Python 2.2 # and above) we can't override special methods, and nullify() needs # to be able to do this. - def __call__(self, target, exitstatfunc, **kw): - self.do_execute(target, exitstatfunc, kw) + def __call__(self, target, **kw): + return self.do_execute(target, kw) def cleanup(self): self._memo = {} @@ -135,8 +151,14 @@ class Executor: """Add source files to this Executor's list. This is necessary for "multi" Builders that can be called repeatedly to build up a source file list for a given target.""" - slist = filter(lambda x, s=self.sources: x not in s, sources) - self.sources.extend(slist) + self.sources.extend(sources) + self.sources_need_sorting = True + + def get_sources(self): + if self.sources_need_sorting: + self.sources = SCons.Util.uniquer_hashables(self.sources) + self.sources_need_sorting = False + return self.sources def add_pre_action(self, action): self.pre_actions.append(action) @@ -148,7 +170,7 @@ class Executor: def my_str(self): env = self.get_build_env() - get = lambda action, t=self.targets, s=self.sources, e=env: \ + get = lambda action, t=self.targets, s=self.get_sources(), e=env: \ action.genstring(t, s, e) return string.join(map(get, self.get_action_list()), "\n") @@ -173,7 +195,7 @@ class Executor: except KeyError: pass env = self.get_build_env() - get = lambda action, t=self.targets, s=self.sources, e=env: \ + get = lambda action, t=self.targets, s=self.get_sources(), e=env: \ action.get_contents(t, s, e) result = string.join(map(get, self.get_action_list()), "") self._memo['get_contents'] = result @@ -191,7 +213,7 @@ class Executor: def scan_sources(self, scanner): if self.sources: - self.scan(scanner, self.sources) + self.scan(scanner, self.get_sources()) def scan(self, scanner, node_list): """Scan a list of this Executor's files (targets or sources) for @@ -218,17 +240,20 @@ class Executor: scanner_list = map(select_specific_scanner, scanner_list) scanner_list = filter(remove_null_scanners, scanner_list) scanner_path_list = map(add_scanner_path, scanner_list) + deps = [] for node, scanner, path in scanner_path_list: deps.extend(node.get_implicit_deps(env, scanner, path)) + deps.extend(self.get_implicit_deps()) + for tgt in self.targets: tgt.add_to_implicit(deps) def get_missing_sources(self): """ """ - return filter(lambda s: s.missing(), self.sources) + return filter(lambda s: s.missing(), self.get_sources()) def _get_unignored_sources_key(self, ignore=()): return tuple(ignore) @@ -248,9 +273,12 @@ class Executor: except KeyError: pass - sourcelist = self.sources + sourcelist = self.get_sources() if ignore: - sourcelist = filter(lambda s, i=ignore: not s in i, sourcelist) + idict = {} + for i in ignore: + idict[i] = 1 + sourcelist = filter(lambda s, i=idict: not i.has_key(s), sourcelist) memo_dict[ignore] = sourcelist @@ -280,6 +308,15 @@ class Executor: return result + def get_implicit_deps(self): + """Return the executor's implicit dependencies, i.e. the nodes of + the commands to be executed.""" + result = [] + build_env = self.get_build_env() + for act in self.get_action_list(): + result.extend(act.get_implicit_deps(self.targets, self.get_sources(), build_env)) + return result + _Executor = Executor @@ -296,9 +333,15 @@ class Null(_Executor): kw['action'] = [] apply(_Executor.__init__, (self,), kw) def get_build_env(self): - class NullEnvironment: - def get_scanner(self, key): - return None + import SCons.Util + class NullEnvironment(SCons.Util.Null): + #def get_scanner(self, key): + # return None + #def changed_since_last_build(self, dependency, target, prev_ni): + # return dependency.changed_since_last_buld(target, prev_ni) + def get_CacheDir(self): + import SCons.CacheDir + return SCons.CacheDir.Null() return NullEnvironment() def get_build_scanner_path(self): return None diff --git a/scons/scons-local-0.97/SCons/Job.py b/scons/scons-local-0.97.0d20071212/SCons/Job.py similarity index 82% rename from scons/scons-local-0.97/SCons/Job.py rename to scons/scons-local-0.97.0d20071212/SCons/Job.py index 492be1052..b0252c959 100644 --- a/scons/scons-local-0.97/SCons/Job.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Job.py @@ -29,7 +29,7 @@ stop, and wait on jobs. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Job.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Job.py 2523 2007/12/12 09:37:41 knight" import SCons.compat @@ -76,6 +76,9 @@ class Jobs: signal.signal(signal.SIGINT, signal.SIG_IGN) raise + def cleanup(self): + self.job.cleanup() + class Serial: """This class is used to execute tasks in series, and is more efficient than Parallel, but is only appropriate for non-parallel builds. Only @@ -122,6 +125,8 @@ class Serial: task.postprocess() + def cleanup(self): + pass # Trap import failure so that everything in the Job module but the # Parallel class (and its dependent classes) will work if the interpreter @@ -148,6 +153,12 @@ else: while 1: task = self.requestQueue.get() + if not task: + # The "None" value is used as a sentinel by + # ThreadPool.cleanup(). This indicates that there + # are no more tasks, so we should quit. + break + try: task.execute() except KeyboardInterrupt: @@ -170,8 +181,10 @@ else: self.resultsQueue = Queue.Queue(0) # Create worker threads + self.workers = [] for _ in range(num): - Worker(self.requestQueue, self.resultsQueue) + worker = Worker(self.requestQueue, self.resultsQueue) + self.workers.append(worker) def put(self, obj): """Put task into request queue.""" @@ -182,7 +195,36 @@ else: return self.resultsQueue.get(block) def preparation_failed(self, obj): - self.resultsQueue.put((obj, 0)) + self.resultsQueue.put((obj, False)) + + def cleanup(self): + """ + Shuts down the thread pool, giving each worker thread a + chance to shut down gracefully. + """ + # For each worker thread, put a sentinel "None" value + # on the requestQueue (indicating that there's no work + # to be done) so that each worker thread will get one and + # terminate gracefully. + for _ in self.workers: + self.requestQueue.put(None) + + # Wait for all of the workers to terminate. + # + # If we don't do this, later Python versions (2.4, 2.5) often + # seem to raise exceptions during shutdown. This happens + # in requestQueue.get(), as an assertion failure that + # requestQueue.not_full is notified while not acquired, + # seemingly because the main thread has shut down (or is + # in the process of doing so) while the workers are still + # trying to pull sentinels off the requestQueue. + # + # Normally these terminations should happen fairly quickly, + # but we'll stick a one-second timeout on here just in case + # someone gets hung. + for worker in self.workers: + worker.join(1.0) + self.workers = [] class Parallel: """This class is used to execute tasks in parallel, and is somewhat @@ -261,3 +303,6 @@ else: if self.tp.resultsQueue.empty(): break + + def cleanup(self): + self.tp.cleanup() diff --git a/scons/scons-local-0.97/SCons/Memoize.py b/scons/scons-local-0.97.0d20071212/SCons/Memoize.py similarity index 98% rename from scons/scons-local-0.97/SCons/Memoize.py rename to scons/scons-local-0.97.0d20071212/SCons/Memoize.py index 09250e900..ad3d99b5a 100644 --- a/scons/scons-local-0.97/SCons/Memoize.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Memoize.py @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Memoize.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Memoize.py 2523 2007/12/12 09:37:41 knight" __doc__ = """Memoizer diff --git a/scons/scons-local-0.97/SCons/Node/Alias.py b/scons/scons-local-0.97.0d20071212/SCons/Node/Alias.py similarity index 70% rename from scons/scons-local-0.97/SCons/Node/Alias.py rename to scons/scons-local-0.97.0d20071212/SCons/Node/Alias.py index 83dd9f728..ae2398f99 100644 --- a/scons/scons-local-0.97/SCons/Node/Alias.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Node/Alias.py @@ -30,7 +30,7 @@ This creates a hash of global Aliases (dummy targets). # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Node/Alias.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Node/Alias.py 2523 2007/12/12 09:37:41 knight" import string import UserDict @@ -57,10 +57,13 @@ class AliasNameSpace(UserDict.UserDict): return None class AliasNodeInfo(SCons.Node.NodeInfoBase): - pass + current_version_id = 1 + field_list = ['csig'] + def str_to_node(self, s): + return default_ans.Alias(s) class AliasBuildInfo(SCons.Node.BuildInfoBase): - pass + current_version_id = 1 class Alias(SCons.Node.Node): @@ -74,8 +77,11 @@ class Alias(SCons.Node.Node): def __str__(self): return self.name + def make_ready(self): + self.get_csig() + really_build = SCons.Node.Node.build - current = SCons.Node.Node.children_are_up_to_date + is_up_to_date = SCons.Node.Node.children_are_up_to_date def is_under(self, dir): # Make Alias nodes get built regardless of @@ -85,9 +91,9 @@ class Alias(SCons.Node.Node): def get_contents(self): """The contents of an alias is the concatenation - of all the contents of its sources""" - contents = map(lambda n: n.get_contents(), self.children()) - return string.join(contents, '') + of the content signatures of all its sources.""" + childsigs = map(lambda n: n.get_csig(), self.children()) + return string.join(childsigs, '') def sconsign(self): """An Alias is not recorded in .sconsign files""" @@ -97,6 +103,13 @@ class Alias(SCons.Node.Node): # # + def changed_since_last_build(self, target, prev_ni): + cur_csig = self.get_csig() + try: + return cur_csig != prev_ni.csig + except AttributeError: + return 1 + def build(self): """A "builder" for aliases.""" pass @@ -107,6 +120,25 @@ class Alias(SCons.Node.Node): self.reset_executor() self.build = self.really_build + def get_csig(self): + """ + Generate a node's content signature, the digested signature + of its content. + + node - the node + cache - alternate node to use for the signature cache + returns - the content signature + """ + try: + return self.ninfo.csig + except AttributeError: + pass + + contents = self.get_contents() + csig = SCons.Util.MD5signature(contents) + self.get_ninfo().csig = csig + return csig + default_ans = AliasNameSpace() SCons.Node.arg2nodes_lookups.append(default_ans.lookup) diff --git a/scons/scons-local-0.97/SCons/Node/FS.py b/scons/scons-local-0.97.0d20071212/SCons/Node/FS.py similarity index 62% rename from scons/scons-local-0.97/SCons/Node/FS.py rename to scons/scons-local-0.97.0d20071212/SCons/Node/FS.py index 0065b8f00..43ff0da9a 100644 --- a/scons/scons-local-0.97/SCons/Node/FS.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Node/FS.py @@ -33,10 +33,12 @@ that can be used by scripts or modules looking for the canonical default. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Node/FS.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Node/FS.py 2523 2007/12/12 09:37:41 knight" +import fnmatch import os import os.path +import re import shutil import stat import string @@ -49,10 +51,13 @@ from SCons.Debug import logInstanceCreation import SCons.Errors import SCons.Memoize import SCons.Node +import SCons.Node.Alias import SCons.Subst import SCons.Util import SCons.Warnings +from SCons.Debug import Trace + # The max_drift value: by default, use a cached signature value for # any file that's been untouched for more than two days. default_max_drift = 2*24*60*60 @@ -81,6 +86,42 @@ def save_strings(val): global Save_Strings Save_Strings = val +# +# Avoid unnecessary function calls by recording a Boolean value that +# tells us whether or not os.path.splitdrive() actually does anything +# on this system, and therefore whether we need to bother calling it +# when looking up path names in various methods below. +# + +do_splitdrive = None + +def initialize_do_splitdrive(): + global do_splitdrive + drive, path = os.path.splitdrive('X:/foo') + do_splitdrive = not not drive + +initialize_do_splitdrive() + +# + +needs_normpath_check = None + +def initialize_normpath_check(): + """ + Initialize the normpath_check regular expression. + + This function is used by the unit tests to re-initialize the pattern + when testing for behavior with different values of os.sep. + """ + global needs_normpath_check + if os.sep == '/': + pattern = r'.*/|\.$|\.\.$' + else: + pattern = r'.*[/%s]|\.$|\.\.$' % re.escape(os.sep) + needs_normpath_check = re.compile(pattern) + +initialize_normpath_check() + # # SCons.Action objects for interacting with the outside world. # @@ -223,71 +264,6 @@ def get_MkdirBuilder(): name = "MkdirBuilder") return MkdirBuilder -def CacheRetrieveFunc(target, source, env): - t = target[0] - fs = t.fs - cachedir, cachefile = t.cachepath() - if not fs.exists(cachefile): - fs.CacheDebug('CacheRetrieve(%s): %s not in cache\n', t, cachefile) - return 1 - fs.CacheDebug('CacheRetrieve(%s): retrieving from %s\n', t, cachefile) - if SCons.Action.execute_actions: - fs.copy2(cachefile, t.path) - st = fs.stat(cachefile) - fs.chmod(t.path, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) - return 0 - -def CacheRetrieveString(target, source, env): - t = target[0] - cachedir, cachefile = t.cachepath() - if t.fs.exists(cachefile): - return "Retrieved `%s' from cache" % t.path - return None - -CacheRetrieve = SCons.Action.Action(CacheRetrieveFunc, CacheRetrieveString) - -CacheRetrieveSilent = SCons.Action.Action(CacheRetrieveFunc, None) - -def CachePushFunc(target, source, env): - t = target[0] - if t.nocache: - return - fs = t.fs - cachedir, cachefile = t.cachepath() - if fs.exists(cachefile): - # Don't bother copying it if it's already there. Note that - # usually this "shouldn't happen" because if the file already - # existed in cache, we'd have retrieved the file from there, - # not built it. This can happen, though, in a race, if some - # other person running the same build pushes their copy to - # the cache after we decide we need to build it but before our - # build completes. - fs.CacheDebug('CachePush(%s): %s already exists in cache\n', t, cachefile) - return - - fs.CacheDebug('CachePush(%s): pushing to %s\n', t, cachefile) - - if not fs.isdir(cachedir): - fs.makedirs(cachedir) - - tempfile = cachefile+'.tmp' - try: - fs.copy2(t.path, tempfile) - fs.rename(tempfile, cachefile) - st = fs.stat(t.path) - fs.chmod(cachefile, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) - except (IOError, OSError): - # It's possible someone else tried writing the file at the - # same time we did, or else that there was some problem like - # the CacheDir being on a separate file system that's full. - # In any case, inability to push a file to cache doesn't affect - # the correctness of the build, so just print a warning. - SCons.Warnings.warn(SCons.Warnings.CacheWriteErrorWarning, - "Unable to copy %s to cache. Cache file is %s" - % (str(target), cachefile)) - -CachePush = SCons.Action.Action(CachePushFunc, None) - class _Null: pass @@ -482,7 +458,7 @@ class EntryProxy(SCons.Util.Proxy): def __get_dir(self): return EntryProxy(self.get().dir) - + dictSpecialAttrs = { "base" : __get_base_path, "posix" : __get_posix_path, "windows" : __get_windows_path, @@ -537,7 +513,7 @@ class Base(SCons.Node.Node): def __init__(self, name, directory, fs): """Initialize a generic Node.FS.Base object. - + Call the superclass initialization, take care of setting up our relative and absolute paths, identify our parent directory, and indicate that this node should use @@ -552,6 +528,7 @@ class Base(SCons.Node.Node): assert directory, "A directory must be provided" self.abspath = directory.entry_abspath(name) + self.labspath = directory.entry_labspath(name) if directory.path == '.': self.path = name else: @@ -566,6 +543,16 @@ class Base(SCons.Node.Node): self.cwd = None # will hold the SConscript directory for target nodes self.duplicate = directory.duplicate + def must_be_same(self, klass): + """ + This node, which already existed, is being looked up as the + specified klass. Raise an exception if it isn't. + """ + if self.__class__ is klass or klass is Entry: + return + raise TypeError, "Tried to lookup %s '%s' as a %s." %\ + (self.__class__.__name__, self.path, klass.__name__) + def get_dir(self): return self.dir @@ -595,9 +582,29 @@ class Base(SCons.Node.Node): return result def _get_str(self): + global Save_Strings if self.duplicate or self.is_derived(): return self.get_path() - return self.srcnode().get_path() + srcnode = self.srcnode() + if srcnode.stat() is None and not self.stat() is None: + result = self.get_path() + else: + result = srcnode.get_path() + if not Save_Strings: + # We're not at the point where we're saving the string string + # representations of FS Nodes (because we haven't finished + # reading the SConscript files and need to have str() return + # things relative to them). That also means we can't yet + # cache values returned (or not returned) by stat(), since + # Python code in the SConscript files might still create + # or otherwise affect the on-disk file. So get rid of the + # values that the underlying stat() method saved. + try: del self._memo['stat'] + except KeyError: pass + if not self is srcnode: + try: del srcnode._memo['stat'] + except KeyError: pass + return result rstr = __str__ @@ -658,15 +665,11 @@ class Base(SCons.Node.Node): corresponding to its source file. Otherwise, return ourself. """ - dir=self.dir - name=self.name - while dir: - if dir.srcdir: - srcnode = self.fs.Entry(name, dir.srcdir, - klass=self.__class__) - return srcnode - name = dir.name + os.sep + name - dir = dir.up() + srcdir_list = self.dir.srcdir_list() + if srcdir_list: + srcnode = srcdir_list[0].Entry(self.name) + srcnode.must_be_same(self.__class__) + return srcnode return self def get_path(self, dir=None): @@ -722,6 +725,15 @@ class Base(SCons.Node.Node): return ret def target_from_source(self, prefix, suffix, splitext=SCons.Util.splitext): + """ + + Generates a target entry that corresponds to this entry (usually + a source file) with the specified prefix and suffix. + + Note that this method can be overridden dynamically for generated + files that need different behavior. See Tool/swig.py for + an example. + """ return self.dir.Entry(prefix + splitext(self.name)[0] + suffix) def _Rfindalldirs_key(self, pathlist): @@ -767,6 +779,29 @@ class Base(SCons.Node.Node): cwd = self.cwd or self.fs._cwd return cwd.Rfindalldirs(pathlist) + memoizer_counters.append(SCons.Memoize.CountValue('rentry')) + + def rentry(self): + try: + return self._memo['rentry'] + except KeyError: + pass + result = self + if not self.exists(): + norm_name = _my_normcase(self.name) + for dir in self.dir.get_all_rdirs(): + try: + node = dir.entries[norm_name] + except KeyError: + if dir.entry_exists_on_disk(self.name): + result = dir.Entry(self.name) + break + self._memo['rentry'] = result + return result + + def _glob1(self, pattern, ondisk=True, source=False, strings=False): + return [] + class Entry(Base): """This is the class for generic Node.FS entries--that is, things that could be a File or a Dir, but we're just not sure yet. @@ -826,7 +861,7 @@ class Entry(Base): def get_contents(self): """Fetch the contents of the entry. - + Since this should return the real contents from the file system, we check to see into what sort of subclass we should morph this Entry.""" @@ -842,12 +877,13 @@ class Entry(Base): else: return self.get_contents() - def must_be_a_Dir(self): + def must_be_same(self, klass): """Called to make sure a Node is a Dir. Since we're an Entry, we can morph into one.""" - self.__class__ = Dir - self._morph() - return self + if not self.__class__ is klass: + self.__class__ = klass + self._morph() + self.clear # The following methods can get called before the Taskmaster has # had a chance to call disambiguate() directly to see if this Entry @@ -872,6 +908,15 @@ class Entry(Base): raise "rel_path() could not disambiguate File/Dir" return d.rel_path(other) + def new_ninfo(self): + return self.disambiguate().new_ninfo() + + def changed_since_last_build(self, target, prev_ni): + return self.disambiguate().changed_since_last_build(target, prev_ni) + + def _glob1(self, pattern, ondisk=True, source=False, strings=False): + return self.disambiguate()._glob1(pattern, ondisk, source, strings) + # This is for later so we can differentiate between Entry the class and Entry # the method of the FS class. _classEntry = Entry @@ -881,7 +926,7 @@ class LocalFS: if SCons.Memoize.use_memoizer: __metaclass__ = SCons.Memoize.Memoized_Metaclass - + # This class implements an abstraction layer for operations involving # a local file system. Essentially, this wraps any function in # the os, os.path or shutil modules that we use to actually go do @@ -900,6 +945,8 @@ class LocalFS: # return os.chdir(path) def chmod(self, path, mode): return os.chmod(path, mode) + def copy(self, src, dst): + return shutil.copy(src, dst) def copy2(self, src, dst): return shutil.copy2(src, dst) def exists(self, path): @@ -976,9 +1023,6 @@ class FS(LocalFS): self.Root = {} self.SConstruct_dir = None - self.CachePath = None - self.cache_force = None - self.cache_show = None self.max_drift = default_max_drift self.Top = None @@ -988,10 +1032,13 @@ class FS(LocalFS): self.pathTop = path self.defaultDrive = _my_normcase(os.path.splitdrive(self.pathTop)[0]) - self.Top = self._doLookup(Dir, os.path.normpath(self.pathTop)) + self.Top = self.Dir(self.pathTop) self.Top.path = '.' self.Top.tpath = '.' self._cwd = self.Top + + DirNodeInfo.fs = self + FileNodeInfo.fs = self def set_SConstruct_dir(self, dir): self.SConstruct_dir = dir @@ -1005,167 +1052,6 @@ class FS(LocalFS): def getcwd(self): return self._cwd - def __checkClass(self, node, klass): - if isinstance(node, klass) or klass == Entry: - return node - if node.__class__ == Entry: - node.__class__ = klass - node._morph() - return node - raise TypeError, "Tried to lookup %s '%s' as a %s." % \ - (node.__class__.__name__, node.path, klass.__name__) - - def _doLookup_key(self, fsclass, name, directory = None, create = 1): - return (fsclass, name, directory) - - memoizer_counters.append(SCons.Memoize.CountDict('_doLookup', _doLookup_key)) - - def _doLookup(self, fsclass, name, directory = None, create = 1): - """This method differs from the File and Dir factory methods in - one important way: the meaning of the directory parameter. - In this method, if directory is None or not supplied, the supplied - name is expected to be an absolute path. If you try to look up a - relative path with directory=None, then an AssertionError will be - raised. - """ - memo_key = (fsclass, name, directory) - try: - memo_dict = self._memo['_doLookup'] - except KeyError: - memo_dict = {} - self._memo['_doLookup'] = memo_dict - else: - try: - return memo_dict[memo_key] - except KeyError: - pass - - if not name: - # This is a stupid hack to compensate for the fact that the - # POSIX and Windows versions of os.path.normpath() behave - # differently in older versions of Python. In particular, - # in POSIX: - # os.path.normpath('./') == '.' - # in Windows: - # os.path.normpath('./') == '' - # os.path.normpath('.\\') == '' - # - # This is a definite bug in the Python library, but we have - # to live with it. - name = '.' - path_orig = string.split(name, os.sep) - path_norm = string.split(_my_normcase(name), os.sep) - - first_orig = path_orig.pop(0) # strip first element - unused = path_norm.pop(0) # strip first element - - drive, path_first = os.path.splitdrive(first_orig) - if path_first: - path_orig = [ path_first, ] + path_orig - path_norm = [ _my_normcase(path_first), ] + path_norm - else: - # Absolute path - drive = _my_normcase(drive) - try: - directory = self.Root[drive] - except KeyError: - if not create: - raise SCons.Errors.UserError - directory = RootDir(drive, self) - self.Root[drive] = directory - if not drive: - self.Root[self.defaultDrive] = directory - elif drive == self.defaultDrive: - self.Root[''] = directory - - if not path_orig: - memo_dict[memo_key] = directory - return directory - - last_orig = path_orig.pop() # strip last element - last_norm = path_norm.pop() # strip last element - - # Lookup the directory - for orig, norm in map(None, path_orig, path_norm): - try: - entries = directory.entries - except AttributeError: - # We tried to look up the entry in either an Entry or - # a File. Give whatever it is a chance to do what's - # appropriate: morph into a Dir or raise an exception. - directory.must_be_a_Dir() - entries = directory.entries - try: - directory = entries[norm] - except KeyError: - if not create: - raise SCons.Errors.UserError - - d = Dir(orig, directory, self) - - # Check the file system (or not, as configured) to make - # sure there isn't already a file there. - d.diskcheck_match() - - directory.entries[norm] = d - directory.add_wkid(d) - directory = d - - directory.must_be_a_Dir() - - try: - e = directory.entries[last_norm] - except KeyError: - if not create: - raise SCons.Errors.UserError - - result = fsclass(last_orig, directory, self) - - # Check the file system (or not, as configured) to make - # sure there isn't already a directory at the path on - # disk where we just created a File node, and vice versa. - result.diskcheck_match() - - directory.entries[last_norm] = result - directory.add_wkid(result) - else: - result = self.__checkClass(e, fsclass) - - memo_dict[memo_key] = result - - return result - - def _transformPath(self, name, directory): - """Take care of setting up the correct top-level directory, - usually in preparation for a call to doLookup(). - - If the path name is prepended with a '#', then it is unconditionally - interpreted as relative to the top-level directory of this FS. - - If directory is None, and name is a relative path, - then the same applies. - """ - if not SCons.Util.is_String(name): - # This handles cases where the object is a Proxy wrapping - # a Node.FS.File object (e.g.). It would be good to handle - # this more directly some day by having the callers of this - # function recognize that a Proxy can be treated like the - # underlying object (that is, get rid of the isinstance() - # calls that explicitly look for a Node.FS.Base object). - name = str(name) - if name and name[0] == '#': - directory = self.Top - name = name[1:] - if name and (name[0] == os.sep or name[0] == '/'): - # Correct such that '#/foo' is equivalent - # to '#foo'. - name = name[1:] - name = os.path.normpath(os.path.join('.', name)) - return (name, directory) - elif not directory: - directory = self._cwd - return (os.path.normpath(name), directory) - def chdir(self, dir, change_os_dir=0): """Change the current working directory for lookups. If change_os_dir is true, we will also change the "real" cwd @@ -1181,25 +1067,112 @@ class FS(LocalFS): self._cwd = curr raise - def Entry(self, name, directory = None, create = 1, klass=None): + def get_root(self, drive): + """ + Returns the root directory for the specified drive, creating + it if necessary. + """ + drive = _my_normcase(drive) + try: + return self.Root[drive] + except KeyError: + root = RootDir(drive, self) + self.Root[drive] = root + if not drive: + self.Root[self.defaultDrive] = root + elif drive == self.defaultDrive: + self.Root[''] = root + return root + + def _lookup(self, p, directory, fsclass, create=1): + """ + The generic entry point for Node lookup with user-supplied data. + + This translates arbitrary input into a canonical Node.FS object + of the specified fsclass. The general approach for strings is + to turn it into a fully normalized absolute path and then call + the root directory's lookup_abs() method for the heavy lifting. + + If the path name begins with '#', it is unconditionally + interpreted relative to the top-level directory of this FS. '#' + is treated as a synonym for the top-level SConstruct directory, + much like '~' is treated as a synonym for the user's home + directory in a UNIX shell. So both '#foo' and '#/foo' refer + to the 'foo' subdirectory underneath the top-level SConstruct + directory. + + If the path name is relative, then the path is looked up relative + to the specified directory, or the current directory (self._cwd, + typically the SConscript directory) if the specified directory + is None. + """ + if isinstance(p, Base): + # It's already a Node.FS object. Make sure it's the right + # class and return. + p.must_be_same(fsclass) + return p + # str(p) in case it's something like a proxy object + p = str(p) + + initial_hash = (p[0:1] == '#') + if initial_hash: + # There was an initial '#', so we strip it and override + # whatever directory they may have specified with the + # top-level SConstruct directory. + p = p[1:] + directory = self.Top + + if directory and not isinstance(directory, Dir): + directory = self.Dir(directory) + + if do_splitdrive: + drive, p = os.path.splitdrive(p) + else: + drive = '' + if drive and not p: + # This causes a naked drive letter to be treated as a synonym + # for the root directory on that drive. + p = os.sep + absolute = os.path.isabs(p) + + needs_normpath = needs_normpath_check.match(p) + + if initial_hash or not absolute: + # This is a relative lookup, either to the top-level + # SConstruct directory (because of the initial '#') or to + # the current directory (the path name is not absolute). + # Add the string to the appropriate directory lookup path, + # after which the whole thing gets normalized. + if not directory: + directory = self._cwd + if p: + p = directory.labspath + '/' + p + else: + p = directory.labspath + + if needs_normpath: + p = os.path.normpath(p) + + if drive or absolute: + root = self.get_root(drive) + else: + if not directory: + directory = self._cwd + root = directory.root + + if os.sep != '/': + p = string.replace(p, os.sep, '/') + return root._lookup_abs(p, fsclass, create) + + def Entry(self, name, directory = None, create = 1): """Lookup or create a generic Entry node with the specified name. If the name is a relative path (begins with ./, ../, or a file name), then it is looked up relative to the supplied directory node, or to the top level directory of the FS (supplied at construction time) if no directory is supplied. """ + return self._lookup(name, directory, Entry, create) - if not klass: - klass = Entry - - if isinstance(name, Base): - return self.__checkClass(name, klass) - else: - if directory and not isinstance(directory, Dir): - directory = self.Dir(directory) - name, directory = self._transformPath(name, directory) - return self._doLookup(klass, name, directory, create) - def File(self, name, directory = None, create = 1): """Lookup or create a File node with the specified name. If the name is a relative path (begins with ./, ../, or a file name), @@ -1210,9 +1183,9 @@ class FS(LocalFS): This method will raise TypeError if a directory is found at the specified path. """ - return self.Entry(name, directory, create, File) - - def Dir(self, name, directory = None, create = 1): + return self._lookup(name, directory, File, create) + + def Dir(self, name, directory = None, create = True): """Lookup or create a Dir node with the specified name. If the name is a relative path (begins with ./, ../, or a file name), then it is looked up relative to the supplied directory node, @@ -1222,12 +1195,12 @@ class FS(LocalFS): This method will raise TypeError if a normal file is found at the specified path. """ - return self.Entry(name, directory, create, Dir) - + return self._lookup(name, directory, Dir, create) + def BuildDir(self, build_dir, src_dir, duplicate=1): """Link the supplied build directory to the source directory for purposes of building files.""" - + if not isinstance(src_dir, SCons.Node.Node): src_dir = self.Dir(src_dir) if not isinstance(build_dir, SCons.Node.Node): @@ -1247,30 +1220,6 @@ class FS(LocalFS): d = self.Dir(d) self.Top.addRepository(d) - def CacheDebugWrite(self, fmt, target, cachefile): - self.CacheDebugFP.write(fmt % (target, os.path.split(cachefile)[1])) - - def CacheDebugQuiet(self, fmt, target, cachefile): - pass - - CacheDebug = CacheDebugQuiet - - def CacheDebugEnable(self, file): - if file == '-': - self.CacheDebugFP = sys.stdout - else: - self.CacheDebugFP = open(file, 'w') - self.CacheDebug = self.CacheDebugWrite - - def CacheDir(self, path): - try: - import SCons.Sig.MD5 - except ImportError: - msg = "No MD5 module available, CacheDir() not supported" - SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg) - else: - self.CachePath = path - def build_dir_target_climb(self, orig, dir, tail): """Create targets in corresponding build directories @@ -1298,11 +1247,40 @@ class FS(LocalFS): message = fmt % string.join(map(str, targets)) return targets, message + def Glob(self, pathname, ondisk=True, source=True, strings=False, cwd=None): + """ + Globs + + This is mainly a shim layer + """ + if cwd is None: + cwd = self.getcwd() + return cwd.glob(pathname, ondisk, source, strings) + class DirNodeInfo(SCons.Node.NodeInfoBase): - pass + # This should get reset by the FS initialization. + current_version_id = 1 + + fs = None + + def str_to_node(self, s): + top = self.fs.Top + root = top.root + if do_splitdrive: + drive, s = os.path.splitdrive(s) + if drive: + root = self.fs.get_root(drive) + if not os.path.isabs(s): + s = top.labspath + '/' + s + return root._lookup_abs(s, Entry) class DirBuildInfo(SCons.Node.BuildInfoBase): - pass + current_version_id = 1 + +glob_magic_check = re.compile('[*?[]') + +def has_glob_magic(s): + return glob_magic_check.search(s) is not None class Dir(Base): """A class for directories in a file system. @@ -1337,6 +1315,7 @@ class Dir(Base): self.searched = 0 self._sconsign = None self.build_dirs = [] + self.root = self.dir.root # Don't just reset the executor, replace its action list, # because it might have some pre-or post-actions that need to @@ -1365,23 +1344,50 @@ class Dir(Base): pass if duplicate != None: node.duplicate=duplicate - + def __resetDuplicate(self, node): if node != self: node.duplicate = node.get_dir().duplicate def Entry(self, name): - """Create an entry node named 'name' relative to this directory.""" + """ + Looks up or creates an entry node named 'name' relative to + this directory. + """ return self.fs.Entry(name, self) - def Dir(self, name): - """Create a directory node named 'name' relative to this directory.""" - return self.fs.Dir(name, self) + def Dir(self, name, create=True): + """ + Looks up or creates a directory node named 'name' relative to + this directory. + """ + dir = self.fs.Dir(name, self, create) + return dir def File(self, name): - """Create a file node named 'name' relative to this directory.""" + """ + Looks up or creates a file node named 'name' relative to + this directory. + """ return self.fs.File(name, self) + def _lookup_rel(self, name, klass, create=1): + """ + Looks up a *normalized* relative path name, relative to this + directory. + + This method is intended for use by internal lookups with + already-normalized path data. For general-purpose lookups, + use the Entry(), Dir() and File() methods above. + + This method does *no* input checking and will die or give + incorrect results if it's passed a non-normalized path name (e.g., + a path containing '..'), an absolute path name, a top-relative + ('#foo') path name, or any kind of object. + """ + name = self.labspath + '/' + name + return self.root._lookup_abs(name, klass, create) + def link(self, srcdir, duplicate): """Set this directory as the build directory for the supplied source directory.""" @@ -1411,7 +1417,10 @@ class Dir(Base): while dir: for rep in dir.getRepositories(): result.append(rep.Dir(fname)) - fname = dir.name + os.sep + fname + if fname == '.': + fname = dir.name + else: + fname = dir.name + os.sep + fname dir = dir.up() self._memo['get_all_rdirs'] = result @@ -1435,6 +1444,17 @@ class Dir(Base): def rel_path(self, other): """Return a path to "other" relative to this directory. """ + + # This complicated and expensive method, which constructs relative + # paths between arbitrary Node.FS objects, is no longer used + # by SCons itself. It was introduced to store dependency paths + # in .sconsign files relative to the target, but that ended up + # being significantly inefficient. + # + # We're continuing to support the method because some SConstruct + # files out there started using it when it was available, and + # we're all about backwards compatibility.. + try: memo_dict = self._memo['rel_path'] except KeyError: @@ -1508,12 +1528,23 @@ class Dir(Base): self.clear() return scanner(self, env, path) + # + # Taskmaster interface subsystem + # + + def prepare(self): + pass + def build(self, **kw): """A null "builder" for directories.""" global MkdirBuilder if not self.builder is MkdirBuilder: apply(SCons.Node.Node.build, [self,], kw) + # + # + # + def _create(self): """Create this directory, silently and without worrying about whether the builder is the default or not.""" @@ -1562,13 +1593,12 @@ class Dir(Base): contents = map(lambda n: n.get_contents(), self.children()) return string.join(contents, '') - def prepare(self): - pass - def do_duplicate(self, src): pass - def current(self, calc=None): + changed_since_last_build = SCons.Node.Node.state_has_changed + + def is_up_to_date(self): """If any child is not up-to-date, then this directory isn't, either.""" if not self.builder is MkdirBuilder and not self.exists(): @@ -1616,17 +1646,15 @@ class Dir(Base): def entry_abspath(self, name): return self.abspath + os.sep + name + def entry_labspath(self, name): + return self.labspath + '/' + name + def entry_path(self, name): return self.path + os.sep + name def entry_tpath(self, name): return self.tpath + os.sep + name - def must_be_a_Dir(self): - """Called to make sure a Node is a Dir. Since we're already - one, this is a no-op for us.""" - return self - def entry_exists_on_disk(self, name): try: d = self.on_disk_entries @@ -1656,13 +1684,7 @@ class Dir(Base): dir = self while dir: if dir.srcdir: - d = dir.srcdir.Dir(dirname) - if d.is_under(dir): - # Shouldn't source from something in the build path: - # build_dir is probably under src_dir, in which case - # we are reflecting. - break - result.append(d) + result.append(dir.srcdir.Dir(dirname)) dirname = dir.name + os.sep + dirname dir = dir.up() @@ -1672,10 +1694,15 @@ class Dir(Base): def srcdir_duplicate(self, name): for dir in self.srcdir_list(): + if self.is_under(dir): + # We shouldn't source from something in the build path; + # build_dir is probably under src_dir, in which case + # we are reflecting. + break if dir.entry_exists_on_disk(name): - srcnode = dir.File(name) + srcnode = dir.Entry(name).disambiguate() if self.duplicate: - node = self.File(name) + node = self.Entry(name).disambiguate() node.do_duplicate(srcnode) return node else: @@ -1701,7 +1728,7 @@ class Dir(Base): def func(node): if (isinstance(node, File) or isinstance(node, Entry)) and \ - (node.is_derived() or node.is_pseudo_derived() or node.exists()): + (node.is_derived() or node.exists()): return node return None @@ -1742,7 +1769,149 @@ class Dir(Base): diskcheck_sccs(self, name): try: return self.File(name) except TypeError: pass - return self.srcdir_duplicate(name) + node = self.srcdir_duplicate(name) + if isinstance(node, Dir): + node = None + return node + + def walk(self, func, arg): + """ + Walk this directory tree by calling the specified function + for each directory in the tree. + + This behaves like the os.path.walk() function, but for in-memory + Node.FS.Dir objects. The function takes the same arguments as + the functions passed to os.path.walk(): + + func(arg, dirname, fnames) + + Except that "dirname" will actually be the directory *Node*, + not the string. The '.' and '..' entries are excluded from + fnames. The fnames list may be modified in-place to filter the + subdirectories visited or otherwise impose a specific order. + The "arg" argument is always passed to func() and may be used + in any way (or ignored, passing None is common). + """ + entries = self.entries + names = entries.keys() + names.remove('.') + names.remove('..') + func(arg, self, names) + select_dirs = lambda n, e=entries: isinstance(e[n], Dir) + for dirname in filter(select_dirs, names): + entries[dirname].walk(func, arg) + + def glob(self, pathname, ondisk=True, source=False, strings=False): + """ + Returns a list of Nodes (or strings) matching a specified + pathname pattern. + + Pathname patterns follow UNIX shell semantics: * matches + any-length strings of any characters, ? matches any character, + and [] can enclose lists or ranges of characters. Matches do + not span directory separators. + + The matches take into account Repositories, returning local + Nodes if a corresponding entry exists in a Repository (either + an in-memory Node or something on disk). + + By defafult, the glob() function matches entries that exist + on-disk, in addition to in-memory Nodes. Setting the "ondisk" + argument to False (or some other non-true value) causes the glob() + function to only match in-memory Nodes. The default behavior is + to return both the on-disk and in-memory Nodes. + + The "source" argument, when true, specifies that corresponding + source Nodes must be returned if you're globbing in a build + directory (initialized with BuildDir()). The default behavior + is to return Nodes local to the BuildDir(). + + The "strings" argument, when true, returns the matches as strings, + not Nodes. The strings are path names relative to this directory. + + The underlying algorithm is adapted from the glob.glob() function + in the Python library (but heavily modified), and uses fnmatch() + under the covers. + """ + dirname, basename = os.path.split(pathname) + if not dirname: + return self._glob1(basename, ondisk, source, strings) + if has_glob_magic(dirname): + list = self.glob(dirname, ondisk, source, strings=False) + else: + list = [self.Dir(dirname, create=True)] + result = [] + for dir in list: + r = dir._glob1(basename, ondisk, source, strings) + if strings: + r = map(lambda x, d=str(dir): os.path.join(d, x), r) + result.extend(r) + return result + + def _glob1(self, pattern, ondisk=True, source=False, strings=False): + """ + Globs for and returns a list of entry names matching a single + pattern in this directory. + + This searches any repositories and source directories for + corresponding entries and returns a Node (or string) relative + to the current directory if an entry is found anywhere. + + TODO: handle pattern with no wildcard + """ + search_dir_list = self.get_all_rdirs() + for srcdir in self.srcdir_list(): + search_dir_list.extend(srcdir.get_all_rdirs()) + + names = [] + for dir in search_dir_list: + # We use the .name attribute from the Node because the keys of + # the dir.entries dictionary are normalized (that is, all upper + # case) on case-insensitive systems like Windows. + #node_names = [ v.name for k, v in dir.entries.items() if k not in ('.', '..') ] + entry_names = filter(lambda n: n not in ('.', '..'), dir.entries.keys()) + node_names = map(lambda n, e=dir.entries: e[n].name, entry_names) + names.extend(node_names) + if ondisk: + try: + disk_names = os.listdir(dir.abspath) + except os.error: + pass + else: + names.extend(disk_names) + if not strings: + # We're going to return corresponding Nodes in + # the local directory, so we need to make sure + # those Nodes exist. We only want to create + # Nodes for the entries that will match the + # specified pattern, though, which means we + # need to filter the list here, even though + # the overall list will also be filtered later, + # after we exit this loop. + if pattern[0] != '.': + #disk_names = [ d for d in disk_names if d[0] != '.' ] + disk_names = filter(lambda x: x[0] != '.', disk_names) + disk_names = fnmatch.filter(disk_names, pattern) + rep_nodes = map(dir.Entry, disk_names) + #rep_nodes = [ n.disambiguate() for n in rep_nodes ] + rep_nodes = map(lambda n: n.disambiguate(), rep_nodes) + for node, name in zip(rep_nodes, disk_names): + n = self.Entry(name) + if n.__class__ != node.__class__: + n.__class__ = node.__class__ + n._morph() + + names = set(names) + if pattern[0] != '.': + #names = [ n for n in names if n[0] != '.' ] + names = filter(lambda x: x[0] != '.', names) + names = fnmatch.filter(names, pattern) + + if strings: + return names + + #return [ self.entries[_my_normcase(n)] for n in names ] + return map(lambda n, e=self.entries: e[_my_normcase(n)], names) class RootDir(Dir): """A class for the root directory of a file system. @@ -1758,25 +1927,89 @@ class RootDir(Dir): # attribute) so we have to set up some values so Base.__init__() # won't gag won't it calls some of our methods. self.abspath = '' + self.labspath = '' self.path = '' self.tpath = '' self.path_elements = [] self.duplicate = 0 + self.root = self Base.__init__(self, name, self, fs) # Now set our paths to what we really want them to be: the - # initial drive letter (the name) plus the directory separator. + # initial drive letter (the name) plus the directory separator, + # except for the "lookup abspath," which does not have the + # drive letter. self.abspath = name + os.sep + self.labspath = '/' self.path = name + os.sep self.tpath = name + os.sep self._morph() + self._lookupDict = {} + + # The // and os.sep + os.sep entries are necessary because + # os.path.normpath() seems to preserve double slashes at the + # beginning of a path (presumably for UNC path names), but + # collapses triple slashes to a single slash. + self._lookupDict['/'] = self + self._lookupDict['//'] = self + self._lookupDict[os.sep] = self + self._lookupDict[os.sep + os.sep] = self + + def must_be_same(self, klass): + if klass is Dir: + return + Base.must_be_same(self, klass) + + def _lookup_abs(self, p, klass, create=1): + """ + Fast (?) lookup of a *normalized* absolute path. + + This method is intended for use by internal lookups with + already-normalized path data. For general-purpose lookups, + use the FS.Entry(), FS.Dir() or FS.File() methods. + + The caller is responsible for making sure we're passed a + normalized absolute path; we merely let Python's dictionary look + up and return the One True Node.FS object for the path. + + If no Node for the specified "p" doesn't already exist, and + "create" is specified, the Node may be created after recursive + invocation to find or create the parent directory or directories. + """ + k = _my_normcase(p) + try: + result = self._lookupDict[k] + except KeyError: + if not create: + raise SCons.Errors.UserError + # There is no Node for this path name, and we're allowed + # to create it. + dir_name, file_name = os.path.split(p) + dir_node = self._lookup_abs(dir_name, Dir) + result = klass(file_name, dir_node, self.fs) + self._lookupDict[k] = result + dir_node.entries[_my_normcase(file_name)] = result + dir_node.implicit = None + + # Double-check on disk (as configured) that the Node we + # created matches whatever is out there in the real world. + result.diskcheck_match() + else: + # There is already a Node for this path name. Allow it to + # complain if we were looking for an inappropriate type. + result.must_be_same(klass) + return result + def __str__(self): return self.abspath def entry_abspath(self, name): return self.abspath + name + def entry_labspath(self, name): + return self.labspath + name + def entry_path(self, name): return self.path + name @@ -1799,79 +2032,98 @@ class RootDir(Dir): return _null class FileNodeInfo(SCons.Node.NodeInfoBase): - def __init__(self, node): - SCons.Node.NodeInfoBase.__init__(self, node) - self.update(node) - def __cmp__(self, other): - try: return cmp(self.bsig, other.bsig) - except AttributeError: return 1 - def update(self, node): - self.timestamp = node.get_timestamp() - self.size = node.getsize() + current_version_id = 1 + + field_list = ['csig', 'timestamp', 'size'] + + # This should get reset by the FS initialization. + fs = None + + def str_to_node(self, s): + top = self.fs.Top + root = top.root + if do_splitdrive: + drive, s = os.path.splitdrive(s) + if drive: + root = self.fs.get_root(drive) + if not os.path.isabs(s): + s = top.labspath + '/' + s + return root._lookup_abs(s, Entry) class FileBuildInfo(SCons.Node.BuildInfoBase): - def __init__(self, node): - SCons.Node.BuildInfoBase.__init__(self, node) - self.node = node + current_version_id = 1 + def convert_to_sconsign(self): - """Convert this FileBuildInfo object for writing to a .sconsign file - - We hung onto the node that we refer to so that we can translate - the lists of bsources, bdepends and bimplicit Nodes into strings - relative to the node, but we don't want to write out that Node - itself to the .sconsign file, so we delete the attribute in - preparation. """ - rel_path = self.node.rel_path - delattr(self, 'node') + Converts this FileBuildInfo object for writing to a .sconsign file + + This replaces each Node in our various dependency lists with its + usual string representation: relative to the top-level SConstruct + directory, or an absolute path if it's outside. + """ + if os.sep == '/': + node_to_str = str + else: + def node_to_str(n): + try: + s = n.path + except AttributeError: + s = str(n) + else: + s = string.replace(s, os.sep, '/') + return s for attr in ['bsources', 'bdepends', 'bimplicit']: try: val = getattr(self, attr) except AttributeError: pass else: - setattr(self, attr, map(rel_path, val)) + setattr(self, attr, map(node_to_str, val)) def convert_from_sconsign(self, dir, name): - """Convert a newly-read FileBuildInfo object for in-SCons use - - An on-disk BuildInfo comes without a reference to the node for - which it's intended, so we have to convert the arguments and add - back a self.node attribute. We don't worry here about converting - the bsources, bdepends and bimplicit lists from strings to Nodes - because they're not used in the normal case of just deciding - whether or not to rebuild things. """ - self.node = dir.Entry(name) + Converts a newly-read FileBuildInfo object for in-SCons use + + For normal up-to-date checking, we don't have any conversion to + perform--but we're leaving this method here to make that clear. + """ + pass def prepare_dependencies(self): - """Prepare a FileBuildInfo object for explaining what changed - - The bsources, bdepends and bimplicit lists have all been stored - on disk as paths relative to the Node for which they're stored - as dependency info. Convert the strings to actual Nodes (for - use by the --debug=explain code and --implicit-cache). """ - Entry_func = self.node.dir.Entry - for attr in ['bsources', 'bdepends', 'bimplicit']: + Prepares a FileBuildInfo object for explaining what changed + + The bsources, bdepends and bimplicit lists have all been + stored on disk as paths relative to the top-level SConstruct + directory. Convert the strings to actual Nodes (for use by the + --debug=explain code and --implicit-cache). + """ + attrs = [ + ('bsources', 'bsourcesigs'), + ('bdepends', 'bdependsigs'), + ('bimplicit', 'bimplicitsigs'), + ] + for (nattr, sattr) in attrs: try: - val = getattr(self, attr) + strings = getattr(self, nattr) + nodeinfos = getattr(self, sattr) except AttributeError: pass else: - setattr(self, attr, map(Entry_func, val)) - def format(self): - result = [ self.ninfo.format() ] + nodes = [] + for s, ni in zip(strings, nodeinfos): + if not isinstance(s, SCons.Node.Node): + s = ni.str_to_node(s) + nodes.append(s) + setattr(self, nattr, nodes) + def format(self, names=0): + result = [] bkids = self.bsources + self.bdepends + self.bimplicit bkidsigs = self.bsourcesigs + self.bdependsigs + self.bimplicitsigs - for i in xrange(len(bkids)): - result.append(str(bkids[i]) + ': ' + bkidsigs[i].format()) + for bkid, bkidsig in zip(bkids, bkidsigs): + result.append(str(bkid) + ': ' + + string.join(bkidsig.format(names=names), ' ')) + result.append('%s [%s]' % (self.bactsig, self.bact)) return string.join(result, '\n') -class NodeInfo(FileNodeInfo): - pass - -class BuildInfo(FileBuildInfo): - pass - class File(Base): """A class for files in a file system. """ @@ -1893,12 +2145,12 @@ class File(Base): def Entry(self, name): """Create an entry node named 'name' relative to the SConscript directory of this file.""" - return self.fs.Entry(name, self.cwd) + return self.cwd.Entry(name) - def Dir(self, name): + def Dir(self, name, create=True): """Create a directory node named 'name' relative to the SConscript directory of this file.""" - return self.fs.Dir(name, self.cwd) + return self.cwd.Dir(name, create) def Dirs(self, pathlist): """Create a list of directories relative to the SConscript @@ -1908,7 +2160,7 @@ class File(Base): def File(self, name): """Create a file node named 'name' relative to the SConscript directory of this file.""" - return self.fs.File(name, self.cwd) + return self.cwd.File(name) #def generate_build_dict(self): # """Return an appropriate dictionary of values for building @@ -1923,6 +2175,19 @@ class File(Base): if not hasattr(self, '_local'): self._local = 0 + # If there was already a Builder set on this entry, then + # we need to make sure we call the target-decider function, + # not the source-decider. Reaching in and doing this by hand + # is a little bogus. We'd prefer to handle this by adding + # an Entry.builder_set() method that disambiguates like the + # other methods, but that starts running into problems with the + # fragile way we initialize Dir Nodes with their Mkdir builders, + # yet still allow them to be overridden by the user. Since it's + # not clear right now how to fix that, stick with what works + # until it becomes clear... + if self.has_builder(): + self.changed_since_last_build = self.decide_target + def scanner_key(self): return self.get_suffix() @@ -1938,41 +2203,192 @@ class File(Base): raise return r - def get_timestamp(self): - if self.rexists(): - return self.rfile().getmtime() - else: - return 0 + memoizer_counters.append(SCons.Memoize.CountValue('get_size')) - def store_info(self, obj): + def get_size(self): + try: + return self._memo['get_size'] + except KeyError: + pass + + if self.rexists(): + size = self.rfile().getsize() + else: + size = 0 + + self._memo['get_size'] = size + + return size + + memoizer_counters.append(SCons.Memoize.CountValue('get_timestamp')) + + def get_timestamp(self): + try: + return self._memo['get_timestamp'] + except KeyError: + pass + + if self.rexists(): + timestamp = self.rfile().getmtime() + else: + timestamp = 0 + + self._memo['get_timestamp'] = timestamp + + return timestamp + + def store_info(self): # Merge our build information into the already-stored entry. # This accomodates "chained builds" where a file that's a target # in one build (SConstruct file) is a source in a different build. # See test/chained-build.py for the use case. - entry = self.get_stored_info() - entry.merge(obj) - self.dir.sconsign().set_entry(self.name, entry) + self.dir.sconsign().store_info(self.name, self) + + convert_copy_attrs = [ + 'bsources', + 'bimplicit', + 'bdepends', + 'bact', + 'bactsig', + 'ninfo', + ] + + + convert_sig_attrs = [ + 'bsourcesigs', + 'bimplicitsigs', + 'bdependsigs', + ] + + def convert_old_entry(self, old_entry): + # Convert a .sconsign entry from before the Big Signature + # Refactoring, doing what we can to convert its information + # to the new .sconsign entry format. + # + # The old format looked essentially like this: + # + # BuildInfo + # .ninfo (NodeInfo) + # .bsig + # .csig + # .timestamp + # .size + # .bsources + # .bsourcesigs ("signature" list) + # .bdepends + # .bdependsigs ("signature" list) + # .bimplicit + # .bimplicitsigs ("signature" list) + # .bact + # .bactsig + # + # The new format looks like this: + # + # .ninfo (NodeInfo) + # .bsig + # .csig + # .timestamp + # .size + # .binfo (BuildInfo) + # .bsources + # .bsourcesigs (NodeInfo list) + # .bsig + # .csig + # .timestamp + # .size + # .bdepends + # .bdependsigs (NodeInfo list) + # .bsig + # .csig + # .timestamp + # .size + # .bimplicit + # .bimplicitsigs (NodeInfo list) + # .bsig + # .csig + # .timestamp + # .size + # .bact + # .bactsig + # + # The basic idea of the new structure is that a NodeInfo always + # holds all available information about the state of a given Node + # at a certain point in time. The various .b*sigs lists can just + # be a list of pointers to the .ninfo attributes of the different + # dependent nodes, without any copying of information until it's + # time to pickle it for writing out to a .sconsign file. + # + # The complicating issue is that the *old* format only stored one + # "signature" per dependency, based on however the *last* build + # was configured. We don't know from just looking at it whether + # it was a build signature, a content signature, or a timestamp + # "signature". Since we no longer use build signatures, the + # best we can do is look at the length and if it's thirty two, + # assume that it was (or might have been) a content signature. + # If it was actually a build signature, then it will cause a + # rebuild anyway when it doesn't match the new content signature, + # but that's probably the best we can do. + import SCons.SConsign + new_entry = SCons.SConsign.SConsignEntry() + new_entry.binfo = self.new_binfo() + binfo = new_entry.binfo + for attr in self.convert_copy_attrs: + try: + value = getattr(old_entry, attr) + except AttributeError: + pass + else: + setattr(binfo, attr, value) + delattr(old_entry, attr) + for attr in self.convert_sig_attrs: + try: + sig_list = getattr(old_entry, attr) + except AttributeError: + pass + else: + value = [] + for sig in sig_list: + ninfo = self.new_ninfo() + if len(sig) == 32: + ninfo.csig = sig + else: + ninfo.timestamp = sig + value.append(ninfo) + setattr(binfo, attr, value) + delattr(old_entry, attr) + return new_entry + + memoizer_counters.append(SCons.Memoize.CountValue('get_stored_info')) def get_stored_info(self): try: - stored = self.dir.sconsign().get_entry(self.name) + return self._memo['get_stored_info'] + except KeyError: + pass + + try: + sconsign_entry = self.dir.sconsign().get_entry(self.name) except (KeyError, OSError): - return self.new_binfo() + import SCons.SConsign + sconsign_entry = SCons.SConsign.SConsignEntry() + sconsign_entry.binfo = self.new_binfo() + sconsign_entry.ninfo = self.new_ninfo() else: - if not hasattr(stored, 'ninfo'): - # Transition: The .sconsign file entry has no NodeInfo - # object, which means it's a slightly older BuildInfo. - # Copy over the relevant attributes. - ninfo = stored.ninfo = self.new_ninfo() - for attr in ninfo.__dict__.keys(): - try: - setattr(ninfo, attr, getattr(stored, attr)) - except AttributeError: - pass - return stored + if isinstance(sconsign_entry, FileBuildInfo): + # This is a .sconsign file from before the Big Signature + # Refactoring; convert it as best we can. + sconsign_entry = self.convert_old_entry(sconsign_entry) + try: + delattr(sconsign_entry.ninfo, 'bsig') + except AttributeError: + pass + + self._memo['get_stored_info'] = sconsign_entry + + return sconsign_entry def get_stored_implicit(self): - binfo = self.get_stored_info() + binfo = self.get_stored_info().binfo binfo.prepare_dependencies() try: return binfo.bimplicit except AttributeError: return None @@ -2024,53 +2440,17 @@ class File(Base): so only do thread safe stuff here. Do thread unsafe stuff in built(). - Note that there's a special trick here with the execute flag - (one that's not normally done for other actions). Basically - if the user requested a noexec (-n) build, then - SCons.Action.execute_actions is set to 0 and when any action - is called, it does its showing but then just returns zero - instead of actually calling the action execution operation. - The problem for caching is that if the file does NOT exist in - cache then the CacheRetrieveString won't return anything to - show for the task, but the Action.__call__ won't call - CacheRetrieveFunc; instead it just returns zero, which makes - the code below think that the file *was* successfully - retrieved from the cache, therefore it doesn't do any - subsequent building. However, the CacheRetrieveString didn't - print anything because it didn't actually exist in the cache, - and no more build actions will be performed, so the user just - sees nothing. The fix is to tell Action.__call__ to always - execute the CacheRetrieveFunc and then have the latter - explicitly check SCons.Action.execute_actions itself. - Returns true iff the node was successfully retrieved. """ if self.nocache: return None - b = self.is_derived() - if not b and not self.has_src_builder(): + if not self.is_derived(): return None - - retrieved = None - if b and self.fs.CachePath: - if self.fs.cache_show: - if CacheRetrieveSilent(self, [], None, execute=1) == 0: - self.build(presub=0, execute=0) - retrieved = 1 - else: - if CacheRetrieve(self, [], None, execute=1) == 0: - retrieved = 1 - if retrieved: - # Record build signature information, but don't - # push it out to cache. (We just got it from there!) - self.set_state(SCons.Node.executed) - SCons.Node.Node.built(self) - - return retrieved - + return self.get_build_env().get_CacheDir().retrieve(self) def built(self): - """Called just after this node is successfully built. + """ + Called just after this node is successfully built. """ # Push this file out to cache before the superclass Node.built() # method has a chance to clear the build signature, which it @@ -2080,13 +2460,70 @@ class File(Base): # cache so that the memoization of the self.exists() return # value doesn't interfere. self.clear_memoized_values() - if self.fs.CachePath and self.exists(): - CachePush(self, [], None) + if self.exists(): + self.get_build_env().get_CacheDir().push(self) SCons.Node.Node.built(self) def visited(self): - if self.fs.CachePath and self.fs.cache_force and self.exists(): - CachePush(self, None, None) + if self.exists(): + self.get_build_env().get_CacheDir().push_if_forced(self) + + ninfo = self.get_ninfo() + old = self.get_stored_info() + + csig = None + mtime = self.get_timestamp() + size = self.get_size() + + max_drift = self.fs.max_drift + if max_drift > 0: + if (time.time() - mtime) > max_drift: + try: + n = old.ninfo + if n.timestamp and n.csig and n.timestamp == mtime: + csig = n.csig + except AttributeError: + pass + elif max_drift == 0: + try: + csig = old.ninfo.csig + except AttributeError: + pass + + if csig: + ninfo.csig = csig + + ninfo.timestamp = mtime + ninfo.size = size + + if not self.has_builder(): + # This is a source file, but it might have been a target file + # in another build that included more of the DAG. Copy + # any build information that's stored in the .sconsign file + # into our binfo object so it doesn't get lost. + self.get_binfo().__dict__.update(old.binfo.__dict__) + + self.store_info() + + def find_src_builder(self): + if self.rexists(): + return None + scb = self.dir.src_builder() + if scb is _null: + if diskcheck_sccs(self.dir, self.name): + scb = get_DefaultSCCSBuilder() + elif diskcheck_rcs(self.dir, self.name): + scb = get_DefaultRCSBuilder() + else: + scb = None + if scb is not None: + try: + b = self.builder + except AttributeError: + b = None + if b is None: + self.builder_set(scb) + return scb def has_src_builder(self): """Return whether this Node has a source builder or not. @@ -2102,20 +2539,7 @@ class File(Base): try: scb = self.sbuilder except AttributeError: - if self.rexists(): - scb = None - else: - scb = self.dir.src_builder() - if scb is _null: - if diskcheck_sccs(self.dir, self.name): - scb = get_DefaultSCCSBuilder() - elif diskcheck_rcs(self.dir, self.name): - scb = get_DefaultRCSBuilder() - else: - scb = None - if scb is not None: - self.builder_set(scb) - self.sbuilder = scb + scb = self.sbuilder = self.find_src_builder() return not scb is None def alter_targets(self): @@ -2125,13 +2549,20 @@ class File(Base): return [], None return self.fs.build_dir_target_climb(self, self.dir, [self.name]) - def is_pseudo_derived(self): - return self.has_src_builder() - def _rmv_existing(self): self.clear_memoized_values() - Unlink(self, [], None) - + e = Unlink(self, [], None) + if isinstance(e, SCons.Errors.BuildError): + raise e + + # + # Taskmaster interface subsystem + # + + def make_ready(self): + self.has_src_builder() + self.get_binfo() + def prepare(self): """Prepare for this file to be created.""" SCons.Node.Node.prepare(self) @@ -2147,6 +2578,10 @@ class File(Base): desc = "No drive `%s' for target `%s'." % (drive, self) raise SCons.Errors.StopError, desc + # + # + # + def remove(self): """Remove this file.""" if self.exists() or self.islink(): @@ -2156,13 +2591,9 @@ class File(Base): def do_duplicate(self, src): self._createDir() - try: - Unlink(self, None, None) - except SCons.Errors.BuildError: - pass - try: - Link(self, src, None) - except SCons.Errors.BuildError, e: + Unlink(self, None, None) + e = Link(self, src, None) + if isinstance(e, SCons.Errors.BuildError): desc = "Cannot duplicate `%s' in `%s': %s." % (src.path, self.dir.path, e.errstr) raise SCons.Errors.StopError, desc self.linked = 1 @@ -2207,7 +2638,7 @@ class File(Base): # SIGNATURE SUBSYSTEM # - def get_csig(self, calc=None): + def get_csig(self): """ Generate a node's content signature, the digested signature of its content. @@ -2216,76 +2647,103 @@ class File(Base): cache - alternate node to use for the signature cache returns - the content signature """ + ninfo = self.get_ninfo() try: - return self.binfo.ninfo.csig + return ninfo.csig except AttributeError: pass - if calc is None: - calc = self.calculator() + try: + contents = self.get_contents() + except IOError: + # This can happen if there's actually a directory on-disk, + # which can be the case if they've disabled disk checks, + # or if an action with a File target actually happens to + # create a same-named directory by mistake. + csig = '' + else: + csig = SCons.Util.MD5signature(contents) - max_drift = self.fs.max_drift - mtime = self.get_timestamp() - use_stored = max_drift >= 0 and (time.time() - mtime) > max_drift - - csig = None - if use_stored: - old = self.get_stored_info().ninfo - try: - if old.timestamp and old.csig and old.timestamp == mtime: - csig = old.csig - except AttributeError: - pass - if csig is None: - csig = calc.module.signature(self) - - binfo = self.get_binfo() - ninfo = binfo.ninfo ninfo.csig = csig - ninfo.update(self) - - if use_stored: - self.store_info(binfo) return csig # - # + # DECISION SUBSYSTEM # - def is_up_to_date(self, node=None, bi=None): - """Returns if the node is up-to-date with respect to stored - BuildInfo. The default is to compare it against our own - previously stored BuildInfo, but the stored BuildInfo from another - Node (typically one in a Repository) can be used instead.""" - if bi is None: - if node is None: - node = self - bi = node.get_stored_info() - new = self.get_binfo() - return new == bi + def builder_set(self, builder): + SCons.Node.Node.builder_set(self, builder) + self.changed_since_last_build = self.decide_target - def current(self, calc=None): - self.binfo = self.gen_binfo(calc) - return self._cur2() - def _cur2(self): - if self.always_build: - return None + def changed_content(self, target, prev_ni): + cur_csig = self.get_csig() + try: + return cur_csig != prev_ni.csig + except AttributeError: + return 1 + + def changed_state(self, target, prev_ni): + return (self.state != SCons.Node.up_to_date) + + def changed_timestamp_then_content(self, target, prev_ni): + if not self.changed_timestamp_match(target, prev_ni): + try: + self.get_ninfo().csig = prev_ni.csig + except AttributeError: + pass + return False + return self.changed_content(target, prev_ni) + + def changed_timestamp_newer(self, target, prev_ni): + try: + return self.get_timestamp() > target.get_timestamp() + except AttributeError: + return 1 + + def changed_timestamp_match(self, target, prev_ni): + try: + return self.get_timestamp() != prev_ni.timestamp + except AttributeError: + return 1 + + def decide_source(self, target, prev_ni): + return target.get_build_env().decide_source(self, target, prev_ni) + + def decide_target(self, target, prev_ni): + return target.get_build_env().decide_target(self, target, prev_ni) + + # Initialize this Node's decider function to decide_source() because + # every file is a source file until it has a Builder attached... + changed_since_last_build = decide_source + + def is_up_to_date(self): + T = 0 + if T: Trace('is_up_to_date(%s):' % self) if not self.exists(): + if T: Trace(' not self.exists():') # The file doesn't exist locally... r = self.rfile() if r != self: # ...but there is one in a Repository... - if self.is_up_to_date(r): + if not self.changed(r): + if T: Trace(' changed(%s):' % r) # ...and it's even up-to-date... if self._local: # ...and they'd like a local copy. - LocalCopy(self, r, None) - self.store_info(self.get_binfo()) + e = LocalCopy(self, r, None) + if isinstance(e, SCons.Errors.BuildError): + raise + self.store_info() + if T: Trace(' 1\n') return 1 + self.changed() + if T: Trace(' None\n') return None else: - return self.is_up_to_date() + r = self.changed() + if T: Trace(' self.exists(): %s\n' % r) + return not r memoizer_counters.append(SCons.Memoize.CountValue('rfile')) @@ -2311,32 +2769,58 @@ class File(Base): def rstr(self): return str(self.rfile()) - def cachepath(self): - if self.nocache or not self.fs.CachePath: - return None, None - ninfo = self.get_binfo().ninfo - if not hasattr(ninfo, 'bsig'): - import SCons.Errors - raise SCons.Errors.InternalError, "cachepath(%s) found no bsig" % self.path - elif ninfo.bsig is None: - import SCons.Errors - raise SCons.Errors.InternalError, "cachepath(%s) found a bsig of None" % self.path + def get_cachedir_csig(self): + """ + Fetch a Node's content signature for purposes of computing + another Node's cachesig. + + This is a wrapper around the normal get_csig() method that handles + the somewhat obscure case of using CacheDir with the -n option. + Any files that don't exist would normally be "built" by fetching + them from the cache, but the normal get_csig() method will try + to open up the local file, which doesn't exist because the -n + option meant we didn't actually pull the file from cachedir. + But since the file *does* actually exist in the cachedir, we + can use its contents for the csig. + """ + try: + return self.cachedir_csig + except AttributeError: + pass + + cachedir, cachefile = self.get_build_env().get_CacheDir().cachepath(self) + if not self.exists() and cachefile and os.path.exists(cachefile): + contents = open(cachefile, 'rb').read() + self.cachedir_csig = SCons.Util.MD5signature(contents) + else: + self.cachedir_csig = self.get_csig() + return self.cachedir_csig + + def get_cachedir_bsig(self): + try: + return self.cachesig + except AttributeError: + pass + # Add the path to the cache signature, because multiple # targets built by the same action will all have the same # build signature, and we have to differentiate them somehow. - import SCons.Sig.MD5 - cache_sig = SCons.Sig.MD5.collect([ninfo.bsig, self.path]) - subdir = string.upper(cache_sig[0]) - dir = os.path.join(self.fs.CachePath, subdir) - return dir, os.path.join(dir, cache_sig) - - def must_be_a_Dir(self): - """Called to make sure a Node is a Dir. Since we're already a - File, this is a TypeError...""" - raise TypeError, "Tried to lookup File '%s' as a Dir." % self.path + children = self.children() + sigs = map(lambda n: n.get_cachedir_csig(), children) + executor = self.get_executor() + sigs.append(SCons.Util.MD5signature(executor.get_contents())) + sigs.append(self.path) + self.cachesig = SCons.Util.MD5collect(sigs) + return self.cachesig default_fs = None +def get_default_fs(): + global default_fs + if not default_fs: + default_fs = FS() + return default_fs + class FileFinder: """ """ @@ -2348,6 +2832,39 @@ class FileFinder: def __init__(self): self._memo = {} + def filedir_lookup(self, p, fd=None): + """ + A helper method for find_file() that looks up a directory for + a file we're trying to find. This only creates the Dir Node if + it exists on-disk, since if the directory doesn't exist we know + we won't find any files in it... :-) + + It would be more compact to just use this as a nested function + with a default keyword argument (see the commented-out version + below), but that doesn't work unless you have nested scopes, + so we define it here just this works work under Python 1.5.2. + """ + if fd is None: + fd = self.default_filedir + dir, name = os.path.split(fd) + drive, d = os.path.splitdrive(dir) + if d in ('/', os.sep): + return p + if dir: + p = self.filedir_lookup(p, dir) + if not p: + return None + norm_name = _my_normcase(name) + try: + node = p.entries[norm_name] + except KeyError: + return p.dir_on_disk(name) + # Once we move to Python 2.2 we can do: + #if isinstance(node, (Dir, Entry)): + if isinstance(node, Dir) or isinstance(node, Entry): + return node + return None + def _find_file_key(self, filename, paths, verbose=None): return (filename, paths) @@ -2393,14 +2910,35 @@ class FileFinder: filedir, filename = os.path.split(filename) if filedir: - def filedir_lookup(p, fd=filedir): - try: - return p.Dir(fd) - except TypeError: - # We tried to look up a Dir, but it seems there's - # already a File (or something else) there. No big. - return None - paths = filter(None, map(filedir_lookup, paths)) + # More compact code that we can't use until we drop + # support for Python 1.5.2: + # + #def filedir_lookup(p, fd=filedir): + # """ + # A helper function that looks up a directory for a file + # we're trying to find. This only creates the Dir Node + # if it exists on-disk, since if the directory doesn't + # exist we know we won't find any files in it... :-) + # """ + # dir, name = os.path.split(fd) + # if dir: + # p = filedir_lookup(p, dir) + # if not p: + # return None + # norm_name = _my_normcase(name) + # try: + # node = p.entries[norm_name] + # except KeyError: + # return p.dir_on_disk(name) + # # Once we move to Python 2.2 we can do: + # #if isinstance(node, (Dir, Entry)): + # if isinstance(node, Dir) or isinstance(node, Entry): + # return node + # return None + #paths = filter(None, map(filedir_lookup, paths)) + + self.default_filedir = filedir + paths = filter(None, map(self.filedir_lookup, paths)) result = None for dir in paths: diff --git a/scons/scons-local-0.97/SCons/Node/Python.py b/scons/scons-local-0.97.0d20071212/SCons/Node/Python.py similarity index 83% rename from scons/scons-local-0.97/SCons/Node/Python.py rename to scons/scons-local-0.97.0d20071212/SCons/Node/Python.py index 211a11934..8b5774a91 100644 --- a/scons/scons-local-0.97/SCons/Node/Python.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Node/Python.py @@ -27,15 +27,20 @@ Python nodes. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Node/Python.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Node/Python.py 2523 2007/12/12 09:37:41 knight" import SCons.Node class ValueNodeInfo(SCons.Node.NodeInfoBase): - pass + current_version_id = 1 + + field_list = ['csig'] + + def str_to_node(self, s): + return Value(s) class ValueBuildInfo(SCons.Node.BuildInfoBase): - pass + current_version_id = 1 class Value(SCons.Node.Node): """A class for Python variables, typically passed on the command line @@ -54,11 +59,14 @@ class Value(SCons.Node.Node): def __str__(self): return repr(self.value) + def make_ready(self): + self.get_csig() + def build(self, **kw): if not hasattr(self, 'built_value'): apply (SCons.Node.Node.build, (self,), kw) - current = SCons.Node.Node.children_are_up_to_date + is_up_to_date = SCons.Node.Node.children_are_up_to_date def is_under(self, dir): # Make Value nodes get built regardless of @@ -88,17 +96,21 @@ class Value(SCons.Node.Node): contents = contents + kid.get_contents() return contents + def changed_since_last_build(self, target, prev_ni): + cur_csig = self.get_csig() + try: + return cur_csig != prev_ni.csig + except AttributeError: + return 1 + def get_csig(self, calc=None): """Because we're a Python value node and don't have a real timestamp, we get to ignore the calculator and just use the value contents.""" try: - binfo = self.binfo + return self.ninfo.csig except AttributeError: - binfo = self.binfo = self.new_binfo() - try: - return binfo.ninfo.csig - except AttributeError: - binfo.ninfo.csig = self.get_contents() - self.store_info(binfo) - return binfo.ninfo.csig + pass + contents = self.get_contents() + self.get_ninfo().csig = contents + return contents diff --git a/scons/scons-local-0.97/SCons/Node/__init__.py b/scons/scons-local-0.97.0d20071212/SCons/Node/__init__.py similarity index 76% rename from scons/scons-local-0.97/SCons/Node/__init__.py rename to scons/scons-local-0.97.0d20071212/SCons/Node/__init__.py index 81d267150..769cbe333 100644 --- a/scons/scons-local-0.97/SCons/Node/__init__.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Node/__init__.py @@ -42,7 +42,7 @@ be able to depend on any other type of "thing." # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Node/__init__.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Node/__init__.py 2523 2007/12/12 09:37:41 knight" import SCons.compat @@ -53,9 +53,13 @@ import UserList from SCons.Debug import logInstanceCreation import SCons.Executor import SCons.Memoize -import SCons.SConsign import SCons.Util +from SCons.Debug import Trace + +def classname(obj): + return string.split(str(obj.__class__), '.')[-1] + # Node states # # These are in "priority" order, so that the maximum value for any @@ -103,38 +107,53 @@ class NodeInfoBase: Node subclasses should subclass NodeInfoBase to provide their own logic for dealing with their own Node-specific signature information. """ + current_version_id = 1 def __init__(self, node): - """A null initializer so that subclasses have a superclass - initialization method to call for future use. - """ - pass - def __cmp__(self, other): - return cmp(self.__dict__, other.__dict__) + # Create an object attribute from the class attribute so it ends up + # in the pickled data in the .sconsign file. + self._version_id = self.current_version_id def update(self, node): - pass - def merge(self, other): - for key, val in other.__dict__.items(): - self.__dict__[key] = val - def prepare_dependencies(self): - pass - def format(self): try: field_list = self.field_list except AttributeError: - field_list = self.__dict__.keys() - field_list.sort() + return + for f in field_list: + try: + delattr(self, f) + except AttributeError: + pass + try: + func = getattr(node, 'get_' + f) + except AttributeError: + pass + else: + setattr(self, f, func()) + def convert(self, node, val): + pass + def merge(self, other): + self.__dict__.update(other.__dict__) + def format(self, field_list=None, names=0): + if field_list is None: + try: + field_list = self.field_list + except AttributeError: + field_list = self.__dict__.keys() + field_list.sort() fields = [] for field in field_list: try: f = getattr(self, field) except AttributeError: f = None - fields.append(str(f)) - return string.join(fields, " ") + f = str(f) + if names: + f = field + ': ' + f + fields.append(f) + return fields class BuildInfoBase: """ - The generic base clasee for build information for a Node. + The generic base class for build information for a Node. This is what gets stored in a .sconsign file for each target file. It contains a NodeInfo instance for this node (signature information @@ -142,22 +161,17 @@ class BuildInfoBase: generic build stuff we have to track: sources, explicit dependencies, implicit dependencies, and action information. """ + current_version_id = 1 def __init__(self, node): - self.ninfo = node.NodeInfo(node) + # Create an object attribute from the class attribute so it ends up + # in the pickled data in the .sconsign file. + self._version_id = self.current_version_id self.bsourcesigs = [] self.bdependsigs = [] self.bimplicitsigs = [] self.bactsig = None - def __cmp__(self, other): - return cmp(self.ninfo, other.ninfo) def merge(self, other): - for key, val in other.__dict__.items(): - try: - merge = self.__dict__[key].merge - except (AttributeError, KeyError): - self.__dict__[key] = val - else: - merge(val) + self.__dict__.update(other.__dict__) class Node: """The base Node class, for entities that we know how to @@ -193,6 +207,7 @@ class Node: self.depends_dict = {} self.ignore = [] # dependencies to ignore self.ignore_dict = {} + self.prerequisites = SCons.Util.UniqueList() self.implicit = None # implicit (scanned) dependencies (None means not scanned yet) self.waiting_parents = {} self.waiting_s_e = {} @@ -225,10 +240,18 @@ class Node: def get_suffix(self): return '' + memoizer_counters.append(SCons.Memoize.CountValue('get_build_env')) + def get_build_env(self): """Fetch the appropriate Environment to build this node. """ - return self.get_executor().get_build_env() + try: + return self._memo['get_build_env'] + except KeyError: + pass + result = self.get_executor().get_build_env() + self._memo['get_build_env'] = result + return result def get_build_scanner_path(self, scanner): """Fetch the appropriate scanner path for this node.""" @@ -286,19 +309,64 @@ class Node: """ return 0 + # + # Taskmaster interface subsystem + # + + def make_ready(self): + """Get a Node ready for evaluation. + + This is called before the Taskmaster decides if the Node is + up-to-date or not. Overriding this method allows for a Node + subclass to be disambiguated if necessary, or for an implicit + source builder to be attached. + """ + pass + + def prepare(self): + """Prepare for this Node to be built. + + This is called after the Taskmaster has decided that the Node + is out-of-date and must be rebuilt, but before actually calling + the method to build the Node. + + This default implemenation checks that all children either exist + or are derived, and initializes the BuildInfo structure that + will hold the information about how this node is, uh, built. + + Overriding this method allows for for a Node subclass to remove + the underlying file from the file system. Note that subclass + methods should call this base class method to get the child + check and the BuildInfo structure. + """ + l = self.depends + if not self.implicit is None: + l = l + self.implicit + missing_sources = self.get_executor().get_missing_sources() \ + + filter(lambda c: c.missing(), l) + if missing_sources: + desc = "Source `%s' not found, needed by target `%s'." % (missing_sources[0], self) + raise SCons.Errors.StopError, desc + + self.binfo = self.get_binfo() + def build(self, **kw): """Actually build the node. + This is called by the Taskmaster after it's decided that the + Node is out-of-date and must be rebuilt, and after the prepare() + method has gotten everything, uh, prepared. + This method is called from multiple threads in a parallel build, - so only do thread safe stuff here. Do thread unsafe stuff in - built(). + so only do thread safe stuff here. Do thread unsafe stuff + in built(). + """ - def exitstatfunc(stat, node=self): - if stat: - msg = "Error %d" % stat - raise SCons.Errors.BuildError(node=node, errstr=msg) - executor = self.get_executor() - apply(executor, (self, exitstatfunc), kw) + try: + apply(self.get_executor(), (self,), kw) + except SCons.Errors.BuildError, e: + e.node = self + raise def built(self): """Called just after this node is successfully built.""" @@ -309,28 +377,26 @@ class Node: parent.implicit = None parent.del_binfo() - try: - new = self.binfo - except AttributeError: - # Node arrived here without build info; apparently it - # doesn't need it, so don't bother calculating or storing - # it. - new = None - - # Reset this Node's cached state since it was just built and - # various state has changed. self.clear() - if new: - # It had build info, so it should be stored in the signature - # cache. However, if the build info included a content - # signature then it must be recalculated before being stored. - if hasattr(new.ninfo, 'csig'): - self.get_csig() - else: - new.ninfo.update(self) - self.binfo = new - self.store_info(self.binfo) + self.ninfo.update(self) + + def visited(self): + """Called just after this node has been visited (with or + without a build).""" + try: + binfo = self.binfo + except AttributeError: + # Apparently this node doesn't need build info, so + # don't bother calculating or storing it. + pass + else: + self.ninfo.update(self) + self.store_info() + + # + # + # def add_to_waiting_s_e(self, node): self.waiting_s_e[node] = 1 @@ -367,27 +433,33 @@ class Node: can be re-evaluated by interfaces that do continuous integration builds). """ + # Note in case it's important in the future: We also used to clear + # the build information (the lists of dependencies) here like this: + # + # self.del_binfo() + # + # But we now rely on the fact that we're going to look at that + # once before the build, and then store the results in the + # .sconsign file after the build. self.clear_memoized_values() + self.ninfo = self.new_ninfo() self.executor_cleanup() - self.del_binfo() try: delattr(self, '_calculated_sig') except AttributeError: pass self.includes = None self.found_includes = {} - self.implicit = None def clear_memoized_values(self): self._memo = {} - def visited(self): - """Called just after this node has been visited - without requiring a build..""" - pass - def builder_set(self, builder): self.builder = builder + try: + del self.executor + except AttributeError: + pass def has_builder(self): """Return whether this Node has a builder or not. @@ -405,8 +477,7 @@ class Node: except AttributeError: # There was no explicit builder for this Node, so initialize # the self.builder attribute to None now. - self.builder = None - b = self.builder + b = self.builder = None return not b is None def set_explicit(self, is_explicit): @@ -446,14 +517,6 @@ class Node: """ return self.has_builder() or self.side_effect - def is_pseudo_derived(self): - """ - Returns true iff this node is built, but should use a source path - when duplicate=0 and should contribute a content signature (i.e. - source signature) when used as a source for other derived files. - """ - return 0 - def alter_targets(self): """Return a list of alternate targets for this Node. """ @@ -552,40 +615,33 @@ class Node: return build_env = self.get_build_env() + executor = self.get_executor() # Here's where we implement --implicit-cache. if implicit_cache and not implicit_deps_changed: implicit = self.get_stored_implicit() if implicit is not None: - factory = build_env.get_factory(self.builder.source_factory) - nodes = [] - for i in implicit: - try: - n = factory(i) - except TypeError: - # The implicit dependency was cached as one type - # of Node last time, but the configuration has - # changed (probably) and it's a different type - # this time. Just ignore the mismatch and go - # with what our current configuration says the - # Node is. - pass - else: - nodes.append(n) - self._add_child(self.implicit, self.implicit_dict, nodes) - calc = build_env.get_calculator() - if implicit_deps_unchanged or self.current(calc): + # We now add the implicit dependencies returned from the + # stored .sconsign entry to have already been converted + # to Nodes for us. (We used to run them through a + # source_factory function here.) + + # Update all of the targets with them. This + # essentially short-circuits an N*M scan of the + # sources for each individual target, which is a hell + # of a lot more efficient. + for tgt in executor.targets: + tgt.add_to_implicit(implicit) + + if implicit_deps_unchanged or self.is_up_to_date(): return - # one of this node's sources has changed, so - # we need to recalculate the implicit deps, - # and the bsig: + # one of this node's sources has changed, + # so we must recalculate the implicit deps: self.implicit = [] self.implicit_dict = {} self._children_reset() self.del_binfo() - executor = self.get_executor() - # Have the executor scan the sources. executor.scan_sources(self.builder.source_scanner) @@ -620,65 +676,24 @@ class Node: NodeInfo = NodeInfoBase BuildInfo = BuildInfoBase - def calculator(self): - import SCons.Defaults - - env = self.env or SCons.Defaults.DefaultEnvironment() - return env.get_calculator() - - memoizer_counters.append(SCons.Memoize.CountValue('calc_signature')) - - def calc_signature(self, calc=None): - """ - Select and calculate the appropriate build signature for a node. - - self - the node - calc - the signature calculation module - returns - the signature - """ - try: - return self._memo['calc_signature'] - except KeyError: - pass - if self.is_derived(): - import SCons.Defaults - - env = self.env or SCons.Defaults.DefaultEnvironment() - if env.use_build_signature(): - result = self.get_bsig(calc) - else: - result = self.get_csig(calc) - elif not self.rexists(): - result = None - else: - result = self.get_csig(calc) - self._memo['calc_signature'] = result - return result - def new_ninfo(self): - return self.NodeInfo(self) + ninfo = self.NodeInfo(self) + return ninfo + + def get_ninfo(self): + try: + return self.ninfo + except AttributeError: + self.ninfo = self.new_ninfo() + return self.ninfo def new_binfo(self): - return self.BuildInfo(self) + binfo = self.BuildInfo(self) + return binfo def get_binfo(self): - try: - return self.binfo - except AttributeError: - self.binfo = self.new_binfo() - return self.binfo - - def del_binfo(self): - """Delete the build info from this node.""" - try: - delattr(self, 'binfo') - except AttributeError: - pass - - def gen_binfo(self, calc=None, scan=1): """ - Generate a node's build signature, the digested signatures - of its dependency files and build information. + Fetch a node's build information. node - the node whose sources will be collected cache - alternate node to use for the signature cache @@ -689,21 +704,17 @@ class Node: already built and updated by someone else, if that's what's wanted. """ + try: + return self.binfo + except AttributeError: + pass - if calc is None: - calc = self.calculator() - - binfo = self.get_binfo() - - if scan: - self.scan() + binfo = self.new_binfo() + self.binfo = binfo executor = self.get_executor() - def calc_signature(node, calc=calc): - return node.calc_signature(calc) sources = executor.get_unignored_sources(self.ignore) - sourcesigs = executor.process_sources(calc_signature, self.ignore) depends = self.depends implicit = self.implicit or [] @@ -712,15 +723,16 @@ class Node: depends = filter(self.do_not_ignore, depends) implicit = filter(self.do_not_ignore, implicit) - dependsigs = map(calc_signature, depends) - implicitsigs = map(calc_signature, implicit) + def get_ninfo(node): + return node.get_ninfo() - sigs = sourcesigs + dependsigs + implicitsigs + sourcesigs = map(get_ninfo, sources) + dependsigs = map(get_ninfo, depends) + implicitsigs = map(get_ninfo, implicit) if self.has_builder(): binfo.bact = str(executor) - binfo.bactsig = calc.module.signature(executor) - sigs.append(binfo.bactsig) + binfo.bactsig = SCons.Util.MD5signature(executor.get_contents()) binfo.bsources = sources binfo.bdepends = depends @@ -730,33 +742,34 @@ class Node: binfo.bdependsigs = dependsigs binfo.bimplicitsigs = implicitsigs - binfo.ninfo.bsig = calc.module.collect(filter(None, sigs)) - return binfo - def get_bsig(self, calc=None): - binfo = self.get_binfo() + def del_binfo(self): + """Delete the build info from this node.""" try: - return binfo.ninfo.bsig + delattr(self, 'binfo') except AttributeError: - self.binfo = self.gen_binfo(calc) - return self.binfo.ninfo.bsig + pass - def get_csig(self, calc=None): - binfo = self.get_binfo() + def get_csig(self): try: - return binfo.ninfo.csig + return self.ninfo.csig except AttributeError: - if calc is None: - calc = self.calculator() - csig = binfo.ninfo.csig = calc.module.signature(self) - return csig + ninfo = self.get_ninfo() + ninfo.csig = SCons.Util.MD5signature(self.get_contents()) + return self.ninfo.csig - def store_info(self, obj): + def get_cachedir_csig(self): + return self.get_csig() + + def store_info(self): """Make the build signature permanent (that is, store it in the .sconsign file or equivalent).""" pass + def do_not_store_info(self): + pass + def get_stored_info(self): return None @@ -800,23 +813,8 @@ class Node: def missing(self): return not self.is_derived() and \ - not self.is_pseudo_derived() and \ not self.linked and \ not self.rexists() - - def prepare(self): - """Prepare for this Node to be created. - The default implemenation checks that all children either exist - or are derived. - """ - l = self.depends - if not self.implicit is None: - l = l + self.implicit - missing_sources = self.get_executor().get_missing_sources() \ - + filter(lambda c: c.missing(), l) - if missing_sources: - desc = "Source `%s' not found, needed by target `%s'." % (missing_sources[0], self) - raise SCons.Errors.StopError, desc def remove(self): """Remove this Node: no-op by default.""" @@ -834,6 +832,11 @@ class Node: s = str(e) raise SCons.Errors.UserError("attempted to add a non-Node dependency to %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e))) + def add_prerequisite(self, prerequisite): + """Adds prerequisites""" + self.prerequisites.extend(prerequisite) + self._children_reset() + def add_ignore(self, depend): """Adds dependencies to ignore.""" try: @@ -861,11 +864,11 @@ class Node: def _add_child(self, collection, dict, child): """Adds 'child' to 'collection', first checking 'dict' to see if it's already present.""" - if type(child) is not type([]): - child = [child] - for c in child: - if not isinstance(c, Node): - raise TypeError, c + #if type(child) is not type([]): + # child = [child] + #for c in child: + # if not isinstance(c, Node): + # raise TypeError, c added = None for c in child: if not dict.has_key(c): @@ -883,7 +886,7 @@ class Node: def _children_reset(self): self.clear_memoized_values() # We need to let the Executor clear out any calculated - # bsig info that it's cached so we can re-calculate it. + # build info that it's cached so we can re-calculate it. self.executor_cleanup() def do_not_ignore(self, node): @@ -944,19 +947,107 @@ class Node: def get_state(self): return self.state - def current(self, calc=None): + def state_has_changed(self, target, prev_ni): + return (self.state != SCons.Node.up_to_date) + + def get_env(self): + env = self.env + if not env: + import SCons.Defaults + env = SCons.Defaults.DefaultEnvironment() + return env + + def changed_since_last_build(self, target, prev_ni): + """ + + Must be overridden in a specific subclass to return True if this + Node (a dependency) has changed since the last time it was used + to build the specified target. prev_ni is this Node's state (for + example, its file timestamp, length, maybe content signature) + as of the last time the target was built. + + Note that this method is called through the dependency, not the + target, because a dependency Node must be able to use its own + logic to decide if it changed. For example, File Nodes need to + obey if we're configured to use timestamps, but Python Value Nodes + never use timestamps and always use the content. If this method + were called through the target, then each Node's implementation + of this method would have to have more complicated logic to + handle all the different Node types on which it might depend. + """ + raise NotImplementedError + + def Decider(self, function): + SCons.Util.AddMethod(self, function, 'changed_since_last_build') + + def changed(self, node=None): + """ + Returns if the node is up-to-date with respect to the BuildInfo + stored last time it was built. The default behavior is to compare + it against our own previously stored BuildInfo, but the stored + BuildInfo from another Node (typically one in a Repository) + can be used instead. + + Note that we now *always* check every dependency. We used to + short-circuit the check by returning as soon as we detected + any difference, but we now rely on checking every dependency + to make sure that any necessary Node information (for example, + the content signature of an #included .h file) is updated. + """ + t = 0 + if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node)) + if node is None: + node = self + + result = False + + bi = node.get_stored_info().binfo + then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs + children = self.children() + + diff = len(children) - len(then) + if diff: + # The old and new dependency lists are different lengths. + # This always indicates that the Node must be rebuilt. + # We also extend the old dependency list with enough None + # entries to equal the new dependency list, for the benefit + # of the loop below that updates node information. + then.extend([None] * diff) + result = True + + for child, prev_ni in zip(children, then): + if child.changed_since_last_build(self, prev_ni): + if t: Trace(': %s changed' % child) + result = True + + contents = self.get_executor().get_contents() + if self.has_builder(): + import SCons.Util + newsig = SCons.Util.MD5signature(contents) + if bi.bactsig != newsig: + if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig)) + result = True + + if not result: + if t: Trace(': up to date') + + if t: Trace('\n') + + return result + + def is_up_to_date(self): """Default check for whether the Node is current: unknown Node subtypes are always out of date, so they will always get built.""" return None - def children_are_up_to_date(self, calc=None): + def children_are_up_to_date(self): """Alternate check for whether the Node is current: If all of our children were up-to-date, then this Node was up-to-date, too. The SCons.Node.Alias and SCons.Node.Python.Value subclasses rebind their current() method to this method.""" # Allow the children to calculate their signatures. - self.binfo = self.gen_binfo(calc) + self.binfo = self.get_binfo() if self.always_build: return None state = 0 @@ -1046,32 +1137,29 @@ class Node: if not self.exists(): return "building `%s' because it doesn't exist\n" % self + if self.always_build: + return "rebuilding `%s' because AlwaysBuild() is specified\n" % self + old = self.get_stored_info() if old is None: return None + + old = old.binfo old.prepare_dependencies() - def dictify(result, kids, sigs): - for k, s in zip(kids, sigs): - result[k] = s - try: - osig = {} - dictify(osig, old.bsources, old.bsourcesigs) - dictify(osig, old.bdepends, old.bdependsigs) - dictify(osig, old.bimplicit, old.bimplicitsigs) + old_bkids = old.bsources + old.bdepends + old.bimplicit + old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs except AttributeError: return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self new = self.get_binfo() - nsig = {} - dictify(nsig, new.bsources, new.bsourcesigs) - dictify(nsig, new.bdepends, new.bdependsigs) - dictify(nsig, new.bimplicit, new.bimplicitsigs) + new_bkids = new.bsources + new.bdepends + new.bimplicit + new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs - old_bkids = old.bsources + old.bdepends + old.bimplicit - new_bkids = new.bsources + new.bdepends + new.bimplicit + osig = dict(zip(old_bkids, old_bkidsigs)) + nsig = dict(zip(new_bkids, new_bkidsigs)) # The sources and dependencies we'll want to report are all stored # as relative paths to this target's directory, but we want to @@ -1092,7 +1180,7 @@ class Node: for k in new_bkids: if not k in old_bkids: lines.append("`%s' is a new dependency\n" % stringify(k)) - elif osig[k] != nsig[k]: + elif k.changed_since_last_build(self, osig[k]): lines.append("`%s' changed\n" % stringify(k)) if len(lines) == 0 and old_bkids != new_bkids: @@ -1124,19 +1212,18 @@ class Node: lines = ["%s:\n" % preamble] + lines return string.join(lines, ' '*11) -l = [1] -ul = UserList.UserList([2]) try: - l.extend(ul) + [].extend(UserList.UserList([])) except TypeError: + # Python 1.5.2 doesn't allow a list to be extended by list-like + # objects (such as UserList instances), so just punt and use + # real lists. def NodeList(l): return l else: class NodeList(UserList.UserList): def __str__(self): return str(map(str, self.data)) -del l -del ul def get_children(node, parent): return node.children() def ignore_cycle(node, stack): pass diff --git a/scons/scons-local-0.97/SCons/Options/BoolOption.py b/scons/scons-local-0.97.0d20071212/SCons/Options/BoolOption.py similarity index 95% rename from scons/scons-local-0.97/SCons/Options/BoolOption.py rename to scons/scons-local-0.97.0d20071212/SCons/Options/BoolOption.py index 23a13f53c..91d5a9d56 100644 --- a/scons/scons-local-0.97/SCons/Options/BoolOption.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Options/BoolOption.py @@ -34,7 +34,7 @@ Usage example: # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/BoolOption.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Options/BoolOption.py 2523 2007/12/12 09:37:41 knight" __all__ = ('BoolOption') diff --git a/scons/scons-local-0.97/SCons/Options/EnumOption.py b/scons/scons-local-0.97.0d20071212/SCons/Options/EnumOption.py similarity index 96% rename from scons/scons-local-0.97/SCons/Options/EnumOption.py rename to scons/scons-local-0.97.0d20071212/SCons/Options/EnumOption.py index bda363e63..3a028e3f6 100644 --- a/scons/scons-local-0.97/SCons/Options/EnumOption.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Options/EnumOption.py @@ -37,7 +37,7 @@ Usage example: # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/EnumOption.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Options/EnumOption.py 2523 2007/12/12 09:37:41 knight" __all__ = ('EnumOption',) diff --git a/scons/scons-local-0.97/SCons/Options/ListOption.py b/scons/scons-local-0.97.0d20071212/SCons/Options/ListOption.py similarity index 97% rename from scons/scons-local-0.97/SCons/Options/ListOption.py rename to scons/scons-local-0.97.0d20071212/SCons/Options/ListOption.py index c74cb8068..0f92ba977 100644 --- a/scons/scons-local-0.97/SCons/Options/ListOption.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Options/ListOption.py @@ -47,7 +47,7 @@ Usage example: # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/ListOption.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Options/ListOption.py 2523 2007/12/12 09:37:41 knight" # Know Bug: This should behave like a Set-Type, but does not really, # since elements can occur twice. diff --git a/scons/scons-local-0.97/SCons/Options/PackageOption.py b/scons/scons-local-0.97.0d20071212/SCons/Options/PackageOption.py similarity index 96% rename from scons/scons-local-0.97/SCons/Options/PackageOption.py rename to scons/scons-local-0.97.0d20071212/SCons/Options/PackageOption.py index 9a8550c17..2c81aca91 100644 --- a/scons/scons-local-0.97/SCons/Options/PackageOption.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Options/PackageOption.py @@ -50,7 +50,7 @@ Usage example: # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/PackageOption.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Options/PackageOption.py 2523 2007/12/12 09:37:41 knight" __all__ = ('PackageOption') diff --git a/scons/scons-local-0.97/SCons/Options/PathOption.py b/scons/scons-local-0.97.0d20071212/SCons/Options/PathOption.py similarity index 93% rename from scons/scons-local-0.97/SCons/Options/PathOption.py rename to scons/scons-local-0.97.0d20071212/SCons/Options/PathOption.py index c9cb04d8b..d1cc06580 100644 --- a/scons/scons-local-0.97/SCons/Options/PathOption.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Options/PathOption.py @@ -68,7 +68,7 @@ Usage example: # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/PathOption.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Options/PathOption.py 2523 2007/12/12 09:37:41 knight" import os import os.path @@ -128,7 +128,12 @@ class _PathOptionClass: """ if validator is None: validator = self.PathExists - return (key, '%s ( /path/to/%s )' % (help, key), default, - validator, None) + + if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): + return (key, '%s ( /path/to/%s )' % (help, key[0]), default, + validator, None) + else: + return (key, '%s ( /path/to/%s )' % (help, key), default, + validator, None) PathOption = _PathOptionClass() diff --git a/scons/scons-local-0.97/SCons/Options/__init__.py b/scons/scons-local-0.97.0d20071212/SCons/Options/__init__.py similarity index 75% rename from scons/scons-local-0.97/SCons/Options/__init__.py rename to scons/scons-local-0.97.0d20071212/SCons/Options/__init__.py index 47f1ffba9..28557cec2 100644 --- a/scons/scons-local-0.97/SCons/Options/__init__.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Options/__init__.py @@ -27,10 +27,13 @@ customizable variables to an SCons build. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Options/__init__.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Options/__init__.py 2523 2007/12/12 09:37:41 knight" + +import SCons.compat import os.path import string +import sys import SCons.Errors import SCons.Util @@ -44,31 +47,49 @@ from PathOption import PathOption # okay class Options: + instance=None + """ Holds all the options, updates the environment with the variables, and renders the help text. """ - def __init__(self, files=None, args={}): + def __init__(self, files=[], args={}, is_global=1): """ files - [optional] List of option configuration files to load - (backward compatibility) If a single string is passed it is + (backward compatibility) If a single string is passed it is automatically placed in a file list """ - self.options = [] self.args = args - self.files = None - if SCons.Util.is_String(files): - self.files = [ files ] - elif files: - self.files = files + if not SCons.Util.is_List(files): + if files: + files = [ files ] + else: + files = [] + self.files = files + self.unknown = {} + + # create the singleton instance + if is_global: + self=Options.instance + + if not Options.instance: + Options.instance=self def _do_add(self, key, help="", default=None, validator=None, converter=None): class Option: pass option = Option() - option.key = key + + # if we get a list or a tuple, we take the first element as the + # option key and store the remaining in aliases. + if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): + option.key = key[0] + option.aliases = key[1:] + else: + option.key = key + option.aliases = [ key ] option.help = help option.default = default option.validator = validator @@ -111,7 +132,7 @@ class Options: Each list element is a tuple/list of arguments to be passed on to the underlying method for adding options. - + Example: opt.AddOptions( ('debug', '', 0), @@ -139,19 +160,34 @@ class Options: values[option.key] = option.default # next set the value specified in the options file - if self.files: - for filename in self.files: - if os.path.exists(filename): - execfile(filename, values) + for filename in self.files: + if os.path.exists(filename): + dir = os.path.split(os.path.abspath(filename))[0] + if dir: + sys.path.insert(0, dir) + try: + values['__name__'] = filename + execfile(filename, {}, values) + finally: + if dir: + del sys.path[0] + del values['__name__'] - # finally set the values specified on the command line + # set the values specified on the command line if args is None: args = self.args - values.update(args) + + for arg, value in args.items(): + added = False + for option in self.options: + if arg in option.aliases + [ option.key ]: + values[option.key] = value + added = True + if not added: + self.unknown[arg] = value # put the variables in the environment: - # (don't copy over variables that are not declared - # as options) + # (don't copy over variables that are not declared as options) for option in self.options: try: env[option.key] = values[option.key] @@ -176,6 +212,13 @@ class Options: if option.validator and values.has_key(option.key): option.validator(option.key, env.subst('${%s}'%option.key), env) + def UnknownOptions(self): + """ + Returns any options in the specified arguments lists that + were not known, declared options in this object. + """ + return self.unknown + def Save(self, filename, env): """ Saves all the options in the given file. This file can @@ -204,7 +247,7 @@ class Options: # Convert stuff that has a repr() that # cannot be evaluated into a string value = SCons.Util.to_String(value) - + defaultVal = env.subst(SCons.Util.to_String(option.default)) if option.converter: defaultVal = option.converter(defaultVal) @@ -238,12 +281,19 @@ class Options: actual = env.subst('${%s}' % opt.key) else: actual = None - return self.FormatOptionHelpText(env, opt.key, opt.help, opt.default, actual) + return self.FormatOptionHelpText(env, opt.key, opt.help, opt.default, actual, opt.aliases) lines = filter(None, map(format, options)) return string.join(lines, '') - format = '\n%s: %s\n default: %s\n actual: %s\n' + format = '\n%s: %s\n default: %s\n actual: %s\n' + format_ = '\n%s: %s\n default: %s\n actual: %s\n aliases: %s\n' + + def FormatOptionHelpText(self, env, key, help, default, actual, aliases=[]): + # Don't display the key name itself as an alias. + aliases = filter(lambda a, k=key: a != k, aliases) + if len(aliases)==0: + return self.format % (key, help, default, actual) + else: + return self.format_ % (key, help, default, actual, aliases) - def FormatOptionHelpText(self, env, key, help, default, actual): - return self.format % (key, help, default, actual) diff --git a/scons/scons-local-0.97/SCons/PathList.py b/scons/scons-local-0.97.0d20071212/SCons/PathList.py similarity index 98% rename from scons/scons-local-0.97/SCons/PathList.py rename to scons/scons-local-0.97.0d20071212/SCons/PathList.py index 2ebdd0f17..355d06c94 100644 --- a/scons/scons-local-0.97/SCons/PathList.py +++ b/scons/scons-local-0.97.0d20071212/SCons/PathList.py @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/PathList.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/PathList.py 2523 2007/12/12 09:37:41 knight" __doc__ = """SCons.PathList @@ -138,7 +138,8 @@ class _PathList: value = string.join(map(str, value), '') elif type == TYPE_OBJECT: value = node_conv(value) - result.append(value) + if value: + result.append(value) return tuple(result) diff --git a/scons/scons-local-0.97/SCons/Platform/__init__.py b/scons/scons-local-0.97.0d20071212/SCons/Platform/__init__.py similarity index 98% rename from scons/scons-local-0.97/SCons/Platform/__init__.py rename to scons/scons-local-0.97.0d20071212/SCons/Platform/__init__.py index b6660a0d1..61e529931 100644 --- a/scons/scons-local-0.97/SCons/Platform/__init__.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Platform/__init__.py @@ -42,7 +42,7 @@ their own platform definition. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/__init__.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Platform/__init__.py 2523 2007/12/12 09:37:41 knight" import imp import os diff --git a/scons/scons-local-0.97/SCons/Platform/aix.py b/scons/scons-local-0.97.0d20071212/SCons/Platform/aix.py similarity index 95% rename from scons/scons-local-0.97/SCons/Platform/aix.py rename to scons/scons-local-0.97.0d20071212/SCons/Platform/aix.py index fcc1bcbfa..e054abee2 100644 --- a/scons/scons-local-0.97/SCons/Platform/aix.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Platform/aix.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/aix.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Platform/aix.py 2523 2007/12/12 09:37:41 knight" import os import string diff --git a/scons/scons-local-0.97/SCons/Platform/cygwin.py b/scons/scons-local-0.97.0d20071212/SCons/Platform/cygwin.py similarity index 93% rename from scons/scons-local-0.97/SCons/Platform/cygwin.py rename to scons/scons-local-0.97.0d20071212/SCons/Platform/cygwin.py index 3a1de0970..0e32e7a5a 100644 --- a/scons/scons-local-0.97/SCons/Platform/cygwin.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Platform/cygwin.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/cygwin.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Platform/cygwin.py 2523 2007/12/12 09:37:41 knight" import posix from SCons.Platform import TempFileMunge diff --git a/scons/scons-local-0.97/SCons/Platform/darwin.py b/scons/scons-local-0.97.0d20071212/SCons/Platform/darwin.py similarity index 92% rename from scons/scons-local-0.97/SCons/Platform/darwin.py rename to scons/scons-local-0.97.0d20071212/SCons/Platform/darwin.py index 124c8cd78..bcd57b223 100644 --- a/scons/scons-local-0.97/SCons/Platform/darwin.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Platform/darwin.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/darwin.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Platform/darwin.py 2523 2007/12/12 09:37:41 knight" import posix diff --git a/scons/scons-local-0.97/SCons/Platform/hpux.py b/scons/scons-local-0.97.0d20071212/SCons/Platform/hpux.py similarity index 92% rename from scons/scons-local-0.97/SCons/Platform/hpux.py rename to scons/scons-local-0.97.0d20071212/SCons/Platform/hpux.py index 1e98472bd..e69403fe4 100644 --- a/scons/scons-local-0.97/SCons/Platform/hpux.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Platform/hpux.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/hpux.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Platform/hpux.py 2523 2007/12/12 09:37:41 knight" import posix diff --git a/scons/scons-local-0.97/SCons/Platform/irix.py b/scons/scons-local-0.97.0d20071212/SCons/Platform/irix.py similarity index 92% rename from scons/scons-local-0.97/SCons/Platform/irix.py rename to scons/scons-local-0.97.0d20071212/SCons/Platform/irix.py index be952ec99..ca09b62a3 100644 --- a/scons/scons-local-0.97/SCons/Platform/irix.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Platform/irix.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/irix.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Platform/irix.py 2523 2007/12/12 09:37:41 knight" import posix diff --git a/scons/scons-local-0.97/SCons/Platform/os2.py b/scons/scons-local-0.97.0d20071212/SCons/Platform/os2.py similarity index 93% rename from scons/scons-local-0.97/SCons/Platform/os2.py rename to scons/scons-local-0.97.0d20071212/SCons/Platform/os2.py index 86a8fadf4..0e9597c24 100644 --- a/scons/scons-local-0.97/SCons/Platform/os2.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Platform/os2.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/os2.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Platform/os2.py 2523 2007/12/12 09:37:41 knight" def generate(env): if not env.has_key('ENV'): diff --git a/scons/scons-local-0.97/SCons/Platform/posix.py b/scons/scons-local-0.97.0d20071212/SCons/Platform/posix.py similarity index 98% rename from scons/scons-local-0.97/SCons/Platform/posix.py rename to scons/scons-local-0.97.0d20071212/SCons/Platform/posix.py index 258d22cf4..ab6c7d9bc 100644 --- a/scons/scons-local-0.97/SCons/Platform/posix.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Platform/posix.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/posix.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Platform/posix.py 2523 2007/12/12 09:37:41 knight" import os import os.path diff --git a/scons/scons-local-0.97/SCons/Platform/sunos.py b/scons/scons-local-0.97.0d20071212/SCons/Platform/sunos.py similarity index 89% rename from scons/scons-local-0.97/SCons/Platform/sunos.py rename to scons/scons-local-0.97.0d20071212/SCons/Platform/sunos.py index 87e2ebb5a..cfa638466 100644 --- a/scons/scons-local-0.97/SCons/Platform/sunos.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Platform/sunos.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/sunos.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Platform/sunos.py 2523 2007/12/12 09:37:41 knight" import posix @@ -41,4 +41,4 @@ def generate(env): env['MAXLINELENGTH'] = 1045320 env['PKGINFO'] = 'pkginfo' env['PKGCHK'] = '/usr/sbin/pkgchk' - env['ENV']['PATH'] = env['ENV']['PATH'] + ':/usr/ccs/bin' + env['ENV']['PATH'] = env['ENV']['PATH'] + ':/opt/SUNWspro/bin:/usr/ccs/bin' diff --git a/scons/scons-local-0.97/SCons/Platform/win32.py b/scons/scons-local-0.97.0d20071212/SCons/Platform/win32.py similarity index 88% rename from scons/scons-local-0.97/SCons/Platform/win32.py rename to scons/scons-local-0.97.0d20071212/SCons/Platform/win32.py index 258e692b0..2e10ca3ea 100644 --- a/scons/scons-local-0.97/SCons/Platform/win32.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Platform/win32.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/win32.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Platform/win32.py 2523 2007/12/12 09:37:41 knight" import os import os.path @@ -40,13 +40,53 @@ import tempfile from SCons.Platform.posix import exitvalmap from SCons.Platform import TempFileMunge - -# XXX See note below about why importing SCons.Action should be -# eventually refactored. -import SCons.Action import SCons.Util + +try: + import msvcrt + import win32api + import win32con + + msvcrt.get_osfhandle + win32api.SetHandleInformation + win32con.HANDLE_FLAG_INHERIT +except ImportError: + parallel_msg = \ + "you do not seem to have the pywin32 extensions installed;\n" + \ + "\tparallel (-j) builds may not work reliably with open Python files." +except AttributeError: + parallel_msg = \ + "your pywin32 extensions do not support file handle operations;\n" + \ + "\tparallel (-j) builds may not work reliably with open Python files." +else: + parallel_msg = None + + import __builtin__ + + _builtin_file = __builtin__.file + _builtin_open = __builtin__.open + + def _scons_file(*args, **kw): + fp = apply(_builtin_file, args, kw) + win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()), + win32con.HANDLE_FLAG_INHERIT, + 0) + return fp + + def _scons_open(*args, **kw): + fp = apply(_builtin_open, args, kw) + win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()), + win32con.HANDLE_FLAG_INHERIT, + 0) + return fp + + __builtin__.file = _scons_file + __builtin__.open = _scons_open + + + # The upshot of all this is that, if you are using Python 1.5.2, # you had better have cmd or command.com in your PATH when you run # scons. diff --git a/scons/scons-local-0.97/SCons/SConf.py b/scons/scons-local-0.97.0d20071212/SCons/SConf.py similarity index 87% rename from scons/scons-local-0.97/SCons/SConf.py rename to scons/scons-local-0.97.0d20071212/SCons/SConf.py index f8c5a73d0..e0c16080e 100644 --- a/scons/scons-local-0.97/SCons/SConf.py +++ b/scons/scons-local-0.97.0d20071212/SCons/SConf.py @@ -26,7 +26,9 @@ Autoconf-like configuration support. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/SConf.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/SConf.py 2523 2007/12/12 09:37:41 knight" + +import SCons.compat import os import re @@ -46,10 +48,20 @@ import SCons.Util import SCons.Warnings import SCons.Conftest +from SCons.Debug import Trace + # Turn off the Conftest error logging SCons.Conftest.LogInputFiles = 0 SCons.Conftest.LogErrorMessages = 0 +# Set +build_type = None +build_types = ['clean', 'help'] + +def SetBuildType(type): + global build_type + build_type = type + # to be set, if we are in dry-run mode dryrun = 0 @@ -158,12 +170,10 @@ class SConfBuildInfo(SCons.Node.FS.FileBuildInfo): """ result = None # -> 0/None -> no error, != 0 error string = None # the stdout / stderr output when building the target - - def __init__(self, node, result, string, sig): - SCons.Node.FS.FileBuildInfo.__init__(self, node) + + def set_build_result(self, result, string): self.result = result self.string = string - self.ninfo.bsig = sig class Streamer: @@ -211,7 +221,7 @@ class SConfBuildTask(SCons.Taskmaster.Task): """ if not isinstance(bi, SConfBuildInfo): SCons.Warnings.warn(SConfWarning, - "The stored build information has an unexpected class.") + "The stored build information has an unexpected class: %s" % bi.__class__) else: self.display("The original builder output was:\n" + string.replace(" |" + str(bi.string), @@ -245,30 +255,39 @@ class SConfBuildTask(SCons.Taskmaster.Task): # cached_error is 1, if the node(s) are up_to_date, but the # build will fail # cachable is 0, if some nodes are not in our cache - is_up_to_date = 1 - cached_error = 0 - cachable = 1 + T = 0 + changed = False + cached_error = False + cachable = True for t in self.targets: - bi = t.get_stored_info() + if T: Trace('%s' % (t)) + bi = t.get_stored_info().binfo if isinstance(bi, SConfBuildInfo): + if T: Trace(': SConfBuildInfo') if cache_mode == CACHE: t.set_state(SCons.Node.up_to_date) + if T: Trace(': set_state(up_to-date)') else: - new_bsig = t.calc_signature(sconf_global.calc) - if t.env.use_build_signature(): - old_bsig = bi.ninfo.bsig - else: - old_bsig = bi.ninfo.csig - is_up_to_date = (is_up_to_date and new_bsig == old_bsig) + if T: Trace(': get_state() %s' % t.get_state()) + if T: Trace(': changed() %s' % t.changed()) + if (t.get_state() != SCons.Node.up_to_date and t.changed()): + changed = True + if T: Trace(': changed %s' % changed) cached_error = cached_error or bi.result else: + if T: Trace(': else') # the node hasn't been built in a SConf context or doesn't # exist - cachable = 0 - is_up_to_date = 0 - return (is_up_to_date, cached_error, cachable) + cachable = False + changed = ( t.get_state() != SCons.Node.up_to_date ) + if T: Trace(': changed %s' % changed) + if T: Trace('\n') + return (not changed, cached_error, cachable) def execute(self): + if not self.targets[0].has_builder(): + return + sconf = sconf_global is_up_to_date, cached_error, cachable = self.collect_node_states() @@ -281,11 +300,13 @@ class SConfBuildTask(SCons.Taskmaster.Task): if cached_error and is_up_to_date: self.display("Building \"%s\" failed in a previous run and all " "its sources are up to date." % str(self.targets[0])) - self.display_cached_string(self.targets[0].get_stored_info()) + binfo = self.targets[0].get_stored_info().binfo + self.display_cached_string(binfo) raise SCons.Errors.BuildError # will be 'caught' in self.failed elif is_up_to_date: self.display("\"%s\" is up to date." % str(self.targets[0])) - self.display_cached_string(self.targets[0].get_stored_info()) + binfo = self.targets[0].get_stored_info().binfo + self.display_cached_string(binfo) elif dryrun: raise ConfigureDryRunError(self.targets[0]) else: @@ -305,21 +326,43 @@ class SConfBuildTask(SCons.Taskmaster.Task): except SystemExit: exc_value = sys.exc_info()[1] raise SCons.Errors.ExplicitExit(self.targets[0],exc_value.code) - except: + except Exception, e: for t in self.targets: - sig = t.calc_signature(sconf.calc) - string = s.getvalue() - binfo = SConfBuildInfo(t,1,string,sig) - t.dir.sconsign().set_entry(t.name, binfo) - raise + binfo = t.get_binfo() + binfo.__class__ = SConfBuildInfo + binfo.set_build_result(1, s.getvalue()) + sconsign_entry = SCons.SConsign.SConsignEntry() + sconsign_entry.binfo = binfo + #sconsign_entry.ninfo = self.get_ninfo() + # We'd like to do this as follows: + # t.store_info(binfo) + # However, we need to store it as an SConfBuildInfo + # object, and store_info() will turn it into a + # regular FileNodeInfo if the target is itself a + # regular File. + sconsign = t.dir.sconsign() + sconsign.set_entry(t.name, sconsign_entry) + sconsign.merge() + raise e else: for t in self.targets: - sig = t.calc_signature(sconf.calc) - string = s.getvalue() - binfo = SConfBuildInfo(t,0,string,sig) - t.dir.sconsign().set_entry(t.name, binfo) + binfo = t.get_binfo() + binfo.__class__ = SConfBuildInfo + binfo.set_build_result(0, s.getvalue()) + sconsign_entry = SCons.SConsign.SConsignEntry() + sconsign_entry.binfo = binfo + #sconsign_entry.ninfo = self.get_ninfo() + # We'd like to do this as follows: + # t.store_info(binfo) + # However, we need to store it as an SConfBuildInfo + # object, and store_info() will turn it into a + # regular FileNodeInfo if the target is itself a + # regular File. + sconsign = t.dir.sconsign() + sconsign.set_entry(t.name, sconsign_entry) + sconsign.merge() -class SConf: +class SConfBase: """This is simply a class to represent a configure context. After creating a SConf object, you can call any tests. After finished with your tests, be sure to call the Finish() method, which returns the modified @@ -360,6 +403,7 @@ class SConf: default_tests = { 'CheckFunc' : CheckFunc, 'CheckType' : CheckType, + 'CheckTypeSize' : CheckTypeSize, 'CheckHeader' : CheckHeader, 'CheckCHeader' : CheckCHeader, 'CheckCXXHeader' : CheckCXXHeader, @@ -369,7 +413,6 @@ class SConf: self.AddTests(default_tests) self.AddTests(custom_tests) self.confdir = SConfFS.Dir(env.subst(conf_dir)) - self.calc = None if not config_h is None: config_h = SConfFS.File(config_h) self.config_h = config_h @@ -377,7 +420,8 @@ class SConf: def Finish(self): """Call this method after finished with your tests: - env = sconf.Finish()""" + env = sconf.Finish() + """ self._shutdown() return self.env @@ -398,6 +442,13 @@ class SConf: old_os_dir = os.getcwd() SConfFS.chdir(SConfFS.Top, change_os_dir=1) + # Because we take responsibility here for writing out our + # own .sconsign info (see SConfBuildTask.execute(), above), + # we override the store_info() method with a null place-holder + # so we really control how it gets written. + for n in nodes: + n.store_info = n.do_not_store_info + ret = 1 try: @@ -561,7 +612,7 @@ class SConf: def AddTest(self, test_name, test_instance): """Adds test_class to this SConf instance. It can be called with self.test_name(...)""" - setattr(self, test_name, SConf.TestWrapper(test_instance, self)) + setattr(self, test_name, SConfBase.TestWrapper(test_instance, self)) def AddTests(self, tests): """Adds all the tests given in the tests dictionary to this SConf @@ -773,6 +824,19 @@ class CheckContext: #### End of stuff used by Conftest.py. +def SConf(*args, **kw): + if kw.get(build_type, True): + kw['_depth'] = kw.get('_depth', 0) + 1 + for bt in build_types: + try: + del kw[bt] + except KeyError: + pass + return apply(SConfBase, args, kw) + else: + return SCons.Util.Null() + + def CheckFunc(context, function_name, header = None, language = None): res = SCons.Conftest.CheckFunc(context, function_name, header = header, language = language) context.did_show_result = 1 @@ -784,6 +848,13 @@ def CheckType(context, type_name, includes = "", language = None): context.did_show_result = 1 return not res +def CheckTypeSize(context, type_name, includes = "", language = None, expect = None): + res = SCons.Conftest.CheckTypeSize(context, type_name, + header = includes, language = language, + expect = expect) + context.did_show_result = 1 + return res + def createIncludesFromHeaders(headers, leaveLast, include_quotes = '""'): # used by CheckHeader and CheckLibWithHeader to produce C - #include # statements from the specified header (list) diff --git a/scons/scons-local-0.97/SCons/SConsign.py b/scons/scons-local-0.97.0d20071212/SCons/SConsign.py similarity index 68% rename from scons/scons-local-0.97/SCons/SConsign.py rename to scons/scons-local-0.97.0d20071212/SCons/SConsign.py index df4f72d8b..0e26f73ca 100644 --- a/scons/scons-local-0.97/SCons/SConsign.py +++ b/scons/scons-local-0.97.0d20071212/SCons/SConsign.py @@ -27,14 +27,15 @@ Writing and reading information to the .sconsign file or files. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/SConsign.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/SConsign.py 2523 2007/12/12 09:37:41 knight" + +import SCons.compat import cPickle import os import os.path import SCons.dblite -import SCons.Sig import SCons.Warnings def corrupt_dblite_warning(filename): @@ -107,6 +108,24 @@ def write(): else: syncmethod() +class SConsignEntry: + """ + Wrapper class for the generic entry in a .sconsign file. + The Node subclass populates it with attributes as it pleases. + + XXX As coded below, we do expect a '.binfo' attribute to be added, + but we'll probably generalize this in the next refactorings. + """ + current_version_id = 1 + def __init__(self): + # Create an object attribute from the class attribute so it ends up + # in the pickled data in the .sconsign file. + _version_id = self.current_version_id + def convert_to_sconsign(self): + self.binfo.convert_to_sconsign() + def convert_from_sconsign(self, dir, name): + self.binfo.convert_from_sconsign(dir, name) + class Base: """ This is the controlling class for the signatures for the collection of @@ -116,14 +135,10 @@ class Base: methods for fetching and storing the individual bits of information that make up signature entry. """ - def __init__(self, module=None): - """ - module - the signature module being used - """ - - self.module = module or SCons.Sig.default_calc.module + def __init__(self): self.entries = {} - self.dirty = 0 + self.dirty = False + self.to_be_merged = {} def get_entry(self, filename): """ @@ -136,19 +151,43 @@ class Base: Set the entry. """ self.entries[filename] = obj - self.dirty = 1 + self.dirty = True def do_not_set_entry(self, filename, obj): pass + def store_info(self, filename, node): + entry = node.get_stored_info() + entry.binfo.merge(node.get_binfo()) + self.to_be_merged[filename] = node + self.dirty = True + + def do_not_store_info(self, filename, node): + pass + + def merge(self): + for key, node in self.to_be_merged.items(): + entry = node.get_stored_info() + try: + ninfo = entry.ninfo + except AttributeError: + # This happens with SConf Nodes, because the configuration + # subsystem takes direct control over how the build decision + # is made and its information stored. + pass + else: + ninfo.merge(node.get_ninfo()) + self.entries[key] = entry + self.to_be_merged = {} + class DB(Base): """ A Base subclass that reads and writes signature information from a global .sconsign.db* file--the actual file suffix is - determined by the specified database module. + determined by the database module. """ - def __init__(self, dir, module=None): - Base.__init__(self, module) + def __init__(self, dir): + Base.__init__(self) self.dir = dir @@ -182,6 +221,7 @@ class DB(Base): # a file there. Don't actually set any entry info, so we # won't try to write to that .sconsign.dblite file. self.set_entry = self.do_not_set_entry + self.store_info = self.do_not_store_info global sig_files sig_files.append(self) @@ -190,6 +230,8 @@ class DB(Base): if not self.dirty: return + self.merge() + db, mode = Get_DataBase(self.dir) # Write using the path relative to the top of the SConstruct @@ -211,27 +253,31 @@ class DB(Base): syncmethod() class Dir(Base): - def __init__(self, fp=None, module=None): + def __init__(self, fp=None, dir=None): """ fp - file pointer to read entries from - module - the signature module being used """ - Base.__init__(self, module) + Base.__init__(self) - if fp: - self.entries = cPickle.load(fp) - if type(self.entries) is not type({}): - self.entries = {} - raise TypeError + if not fp: + return + + self.entries = cPickle.load(fp) + if type(self.entries) is not type({}): + self.entries = {} + raise TypeError + + if dir: + for key, entry in self.entries.items(): + entry.convert_from_sconsign(dir, key) class DirFile(Dir): """ Encapsulates reading and writing a per-directory .sconsign file. """ - def __init__(self, dir, module=None): + def __init__(self, dir): """ dir - the directory for the file - module - the signature module being used """ self.dir = dir @@ -243,7 +289,7 @@ class DirFile(Dir): fp = None try: - Dir.__init__(self, fp, module) + Dir.__init__(self, fp, dir) except KeyboardInterrupt: raise except: @@ -253,15 +299,6 @@ class DirFile(Dir): global sig_files sig_files.append(self) - def get_entry(self, filename): - """ - Fetch the specified entry attribute, converting from .sconsign - format to in-memory format. - """ - entry = Dir.get_entry(self, filename) - entry.convert_from_sconsign(self.dir, filename) - return entry - def write(self, sync=1): """ Write the .sconsign file to disk. @@ -275,48 +312,52 @@ class DirFile(Dir): to the .sconsign file. Either way, always try to remove the temporary file at the end. """ - if self.dirty: - temp = os.path.join(self.dir.path, '.scons%d' % os.getpid()) + if not self.dirty: + return + + self.merge() + + temp = os.path.join(self.dir.path, '.scons%d' % os.getpid()) + try: + file = open(temp, 'wb') + fname = temp + except IOError: try: - file = open(temp, 'wb') - fname = temp + file = open(self.sconsign, 'wb') + fname = self.sconsign except IOError: - try: - file = open(self.sconsign, 'wb') - fname = self.sconsign - except IOError: - return - for key, entry in self.entries.items(): - entry.convert_to_sconsign() - cPickle.dump(self.entries, file, 1) - file.close() - if fname != self.sconsign: - try: - mode = os.stat(self.sconsign)[0] - os.chmod(self.sconsign, 0666) - os.unlink(self.sconsign) - except (IOError, OSError): - # Try to carry on in the face of either OSError - # (things like permission issues) or IOError (disk - # or network issues). If there's a really dangerous - # issue, it should get re-raised by the calls below. - pass - try: - os.rename(fname, self.sconsign) - except OSError: - # An OSError failure to rename may indicate something - # like the directory has no write permission, but - # the .sconsign file itself might still be writable, - # so try writing on top of it directly. An IOError - # here, or in any of the following calls, would get - # raised, indicating something like a potentially - # serious disk or network issue. - open(self.sconsign, 'wb').write(open(fname, 'rb').read()) - os.chmod(self.sconsign, mode) + return + for key, entry in self.entries.items(): + entry.convert_to_sconsign() + cPickle.dump(self.entries, file, 1) + file.close() + if fname != self.sconsign: try: - os.unlink(temp) + mode = os.stat(self.sconsign)[0] + os.chmod(self.sconsign, 0666) + os.unlink(self.sconsign) except (IOError, OSError): + # Try to carry on in the face of either OSError + # (things like permission issues) or IOError (disk + # or network issues). If there's a really dangerous + # issue, it should get re-raised by the calls below. pass + try: + os.rename(fname, self.sconsign) + except OSError: + # An OSError failure to rename may indicate something + # like the directory has no write permission, but + # the .sconsign file itself might still be writable, + # so try writing on top of it directly. An IOError + # here, or in any of the following calls, would get + # raised, indicating something like a potentially + # serious disk or network issue. + open(self.sconsign, 'wb').write(open(fname, 'rb').read()) + os.chmod(self.sconsign, mode) + try: + os.unlink(temp) + except (IOError, OSError): + pass ForDirectory = DB diff --git a/scons/scons-local-0.97/SCons/Scanner/C.py b/scons/scons-local-0.97.0d20071212/SCons/Scanner/C.py similarity index 93% rename from scons/scons-local-0.97/SCons/Scanner/C.py rename to scons/scons-local-0.97.0d20071212/SCons/Scanner/C.py index a253db9b1..a79bea7c4 100644 --- a/scons/scons-local-0.97/SCons/Scanner/C.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Scanner/C.py @@ -27,7 +27,7 @@ This module implements the depenency scanner for C/C++ code. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/C.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Scanner/C.py 2523 2007/12/12 09:37:41 knight" import SCons.Node.FS import SCons.Scanner diff --git a/scons/scons-local-0.97/SCons/Scanner/D.py b/scons/scons-local-0.97.0d20071212/SCons/Scanner/D.py similarity index 93% rename from scons/scons-local-0.97/SCons/Scanner/D.py rename to scons/scons-local-0.97.0d20071212/SCons/Scanner/D.py index 59c9eee33..1abfaa04f 100644 --- a/scons/scons-local-0.97/SCons/Scanner/D.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Scanner/D.py @@ -30,7 +30,7 @@ Coded by Andy Friesen # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/D.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Scanner/D.py 2523 2007/12/12 09:37:41 knight" import string diff --git a/scons/scons-local-0.97/SCons/Scanner/Dir.py b/scons/scons-local-0.97.0d20071212/SCons/Scanner/Dir.py similarity index 96% rename from scons/scons-local-0.97/SCons/Scanner/Dir.py rename to scons/scons-local-0.97.0d20071212/SCons/Scanner/Dir.py index c2e6f405d..7a6a55f39 100644 --- a/scons/scons-local-0.97/SCons/Scanner/Dir.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Scanner/Dir.py @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/Dir.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Scanner/Dir.py 2523 2007/12/12 09:37:41 knight" import SCons.Node.FS import SCons.Scanner diff --git a/scons/scons-local-0.97/SCons/Scanner/Fortran.py b/scons/scons-local-0.97.0d20071212/SCons/Scanner/Fortran.py similarity index 99% rename from scons/scons-local-0.97/SCons/Scanner/Fortran.py rename to scons/scons-local-0.97.0d20071212/SCons/Scanner/Fortran.py index fa6b82c4d..b3ebd0086 100644 --- a/scons/scons-local-0.97/SCons/Scanner/Fortran.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Scanner/Fortran.py @@ -27,7 +27,7 @@ This module implements the dependency scanner for Fortran code. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/Fortran.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Scanner/Fortran.py 2523 2007/12/12 09:37:41 knight" import re import string diff --git a/scons/scons-local-0.97/SCons/Scanner/IDL.py b/scons/scons-local-0.97.0d20071212/SCons/Scanner/IDL.py similarity index 93% rename from scons/scons-local-0.97/SCons/Scanner/IDL.py rename to scons/scons-local-0.97.0d20071212/SCons/Scanner/IDL.py index ddb149054..aee4b8f02 100644 --- a/scons/scons-local-0.97/SCons/Scanner/IDL.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Scanner/IDL.py @@ -28,7 +28,7 @@ Definition Language) files. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/IDL.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Scanner/IDL.py 2523 2007/12/12 09:37:41 knight" import SCons.Node.FS import SCons.Scanner diff --git a/scons/scons-local-0.97/SCons/Scanner/LaTeX.py b/scons/scons-local-0.97.0d20071212/SCons/Scanner/LaTeX.py similarity index 94% rename from scons/scons-local-0.97/SCons/Scanner/LaTeX.py rename to scons/scons-local-0.97.0d20071212/SCons/Scanner/LaTeX.py index 83dde2657..59a88a27f 100644 --- a/scons/scons-local-0.97/SCons/Scanner/LaTeX.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Scanner/LaTeX.py @@ -27,19 +27,19 @@ This module implements the dependency scanner for LaTeX code. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/LaTeX.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Scanner/LaTeX.py 2523 2007/12/12 09:37:41 knight" +import os.path +import string import SCons.Scanner -import string -import os.path -def LaTeXScanner(fs = SCons.Node.FS.default_fs): +def LaTeXScanner(): """Return a prototype Scanner instance for scanning LaTeX source files""" ds = LaTeX(name = "LaTeXScanner", suffixes = '$LATEXSUFFIXES', path_variable = 'TEXINPUTS', - regex = '\\\\(include|includegraphics(?:\[[^\]]+\])?|input|bibliography){([^}]*)}', + regex = '\\\\(include|includegraphics(?:\[[^\]]+\])?|input|bibliography|usepackage){([^}]*)}', recursive = 0) return ds @@ -72,6 +72,10 @@ class LaTeX(SCons.Scanner.Classic): base, ext = os.path.splitext( filename ) if ext == "": filename = filename + '.bib' + if include[0] == 'usepackage': + base, ext = os.path.splitext( filename ) + if ext == "": + filename = filename + '.sty' return filename def sort_key(self, include): return SCons.Node.FS._my_normcase(self.latex_name(include)) diff --git a/scons/scons-local-0.97/SCons/Scanner/Prog.py b/scons/scons-local-0.97.0d20071212/SCons/Scanner/Prog.py similarity index 96% rename from scons/scons-local-0.97/SCons/Scanner/Prog.py rename to scons/scons-local-0.97.0d20071212/SCons/Scanner/Prog.py index d3259c4a4..aa7685f16 100644 --- a/scons/scons-local-0.97/SCons/Scanner/Prog.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Scanner/Prog.py @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/Prog.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Scanner/Prog.py 2523 2007/12/12 09:37:41 knight" import string diff --git a/scons/scons-local-0.97/SCons/Scanner/__init__.py b/scons/scons-local-0.97.0d20071212/SCons/Scanner/__init__.py similarity index 98% rename from scons/scons-local-0.97/SCons/Scanner/__init__.py rename to scons/scons-local-0.97.0d20071212/SCons/Scanner/__init__.py index 69d98b3c6..07243c89a 100644 --- a/scons/scons-local-0.97/SCons/Scanner/__init__.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Scanner/__init__.py @@ -27,13 +27,12 @@ The Scanner package for the SCons software construction utility. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Scanner/__init__.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Scanner/__init__.py 2523 2007/12/12 09:37:41 knight" import re import string import SCons.Node.FS -import SCons.Sig import SCons.Util @@ -306,8 +305,7 @@ class Current(Base): def __init__(self, *args, **kw): def current_check(node, env): - c = not node.has_builder() or node.current(env.get_calculator()) - return c + return not node.has_builder() or node.is_up_to_date() kw['scan_check'] = current_check apply(Base.__init__, (self,) + args, kw) diff --git a/scons/scons-local-0.97/SCons/Script/Main.py b/scons/scons-local-0.97.0d20071212/SCons/Script/Main.py similarity index 57% rename from scons/scons-local-0.97/SCons/Script/Main.py rename to scons/scons-local-0.97.0d20071212/SCons/Script/Main.py index b18b4d983..764cba67c 100644 --- a/scons/scons-local-0.97/SCons/Script/Main.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Script/Main.py @@ -34,13 +34,12 @@ it goes here. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Script/Main.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Script/Main.py 2523 2007/12/12 09:37:41 knight" import SCons.compat import os import os.path -import random import string import sys import time @@ -55,6 +54,7 @@ import traceback # 'lib', # 'scons-%d' % SCons.__version__)] + sys.path[1:] +import SCons.CacheDir import SCons.Debug import SCons.Defaults import SCons.Environment @@ -62,28 +62,100 @@ import SCons.Errors import SCons.Job import SCons.Node import SCons.Node.FS -from SCons.Optik import OptionParser, SUPPRESS_HELP, OptionValueError import SCons.SConf import SCons.Script -import SCons.Sig import SCons.Taskmaster import SCons.Util import SCons.Warnings # + +class SConsPrintHelpException(Exception): + pass + display = SCons.Util.display progress_display = SCons.Util.DisplayEngine() first_command_start = None last_command_end = None +class Progressor: + prev = '' + count = 0 + target_string = '$TARGET' + + def __init__(self, obj, interval=1, file=None, overwrite=False): + if file is None: + file = sys.stdout + + self.obj = obj + self.file = file + self.interval = interval + self.overwrite = overwrite + + if callable(obj): + self.func = obj + elif SCons.Util.is_List(obj): + self.func = self.spinner + elif string.find(obj, self.target_string) != -1: + self.func = self.replace_string + else: + self.func = self.string + + def write(self, s): + self.file.write(s) + self.file.flush() + self.prev = s + + def erase_previous(self): + if self.prev: + length = len(self.prev) + if self.prev[-1] in ('\n', '\r'): + length = length - 1 + self.write(' ' * length + '\r') + self.prev = '' + + def spinner(self, node): + self.write(self.obj[self.count % len(self.obj)]) + + def string(self, node): + self.write(self.obj) + + def replace_string(self, node): + self.write(string.replace(self.obj, self.target_string, str(node))) + + def __call__(self, node): + self.count = self.count + 1 + if (self.count % self.interval) == 0: + if self.overwrite: + self.erase_previous() + self.func(node) + +ProgressObject = SCons.Util.Null() + +def Progress(*args, **kw): + global ProgressObject + ProgressObject = apply(Progressor, args, kw) + # Task control. # + +_BuildFailures = [] + +def GetBuildFailures(): + return _BuildFailures + class BuildTask(SCons.Taskmaster.Task): """An SCons build task.""" + progress = ProgressObject + def display(self, message): display('scons: ' + message) + def prepare(self): + self.progress(self.targets[0]) + return SCons.Taskmaster.Task.prepare(self) + def execute(self): for target in self.targets: if target.get_state() == SCons.Node.up_to_date: @@ -108,10 +180,11 @@ class BuildTask(SCons.Taskmaster.Task): display("scons: `%s' is up to date." % str(self.node)) def do_failed(self, status=2): + _BuildFailures.append(self.exception[1]) global exit_status - if ignore_errors: + if self.options.ignore_errors: SCons.Taskmaster.Task.executed(self) - elif keep_going_on_error: + elif self.options.keep_going: SCons.Taskmaster.Task.fail_continue(self) exit_status = status else: @@ -123,7 +196,7 @@ class BuildTask(SCons.Taskmaster.Task): if self.top and not t.has_builder() and not t.side_effect: if not t.exists(): sys.stderr.write("scons: *** Do not know how to make target `%s'." % t) - if not keep_going_on_error: + if not self.options.keep_going: sys.stderr.write(" Stop.") sys.stderr.write("\n") self.do_failed() @@ -176,7 +249,7 @@ class BuildTask(SCons.Taskmaster.Task): if e is None: e = t s = str(e) - if t == SCons.Errors.StopError and not keep_going_on_error: + if t == SCons.Errors.StopError and not self.options.keep_going: s = s + ' Stop.' sys.stderr.write("scons: *** %s\n" % s) @@ -191,9 +264,9 @@ class BuildTask(SCons.Taskmaster.Task): def postprocess(self): if self.top: t = self.targets[0] - for tp in tree_printers: + for tp in self.options.tree_printers: tp.display(t) - if print_includes: + if self.options.debug_includes: tree = t.render_include_tree() if tree: print @@ -203,41 +276,38 @@ class BuildTask(SCons.Taskmaster.Task): def make_ready(self): """Make a task ready for execution""" SCons.Taskmaster.Task.make_ready(self) - if self.out_of_date and print_explanations: + if self.out_of_date and self.options.debug_explain: explanation = self.out_of_date[0].explain() if explanation: sys.stdout.write("scons: " + explanation) class CleanTask(SCons.Taskmaster.Task): """An SCons clean task.""" - def dir_index(self, directory): - dirname = lambda f, d=directory: os.path.join(d, f) - files = map(dirname, os.listdir(directory)) - - # os.listdir() isn't guaranteed to return files in any specific order, - # but some of the test code expects sorted output. - files.sort() - return files - - def fs_delete(self, path, remove=1): + def fs_delete(self, path, pathstr, remove=1): try: if os.path.exists(path): if os.path.isfile(path): if remove: os.unlink(path) - display("Removed " + path) + display("Removed " + pathstr) elif os.path.isdir(path) and not os.path.islink(path): # delete everything in the dir - for p in self.dir_index(path): + entries = os.listdir(path) + # Sort for deterministic output (os.listdir() Can + # return entries in a random order). + entries.sort() + for e in entries: + p = os.path.join(path, e) + s = os.path.join(pathstr, e) if os.path.isfile(p): if remove: os.unlink(p) - display("Removed " + p) + display("Removed " + s) else: - self.fs_delete(p, remove) + self.fs_delete(p, s, remove) # then delete dir itself if remove: os.rmdir(path) - display("Removed directory " + path) + display("Removed directory " + pathstr) except (IOError, OSError), e: - print "scons: Could not remove '%s':" % str(path), e.strerror + print "scons: Could not remove '%s':" % pathstr, e.strerror def show(self): target = self.targets[0] @@ -248,7 +318,7 @@ class CleanTask(SCons.Taskmaster.Task): if SCons.Environment.CleanTargets.has_key(target): files = SCons.Environment.CleanTargets[target] for f in files: - self.fs_delete(str(f), 0) + self.fs_delete(f.abspath, str(f), 0) def remove(self): target = self.targets[0] @@ -269,10 +339,16 @@ class CleanTask(SCons.Taskmaster.Task): if SCons.Environment.CleanTargets.has_key(target): files = SCons.Environment.CleanTargets[target] for f in files: - self.fs_delete(str(f)) + self.fs_delete(f.abspath, str(f)) execute = remove + # We want the Taskmaster to update the Node states (and therefore + # handle reference counts, etc.), but we don't want to call + # back to the Node's post-build methods, which would do things + # we don't want, like store .sconsign information. + executed = SCons.Taskmaster.Task.executed_without_callbacks + # Have the taskmaster arrange to "execute" all of the targets, because # we'll figure out ourselves (in remove() or show() above) whether # anything really needs to be done. @@ -287,7 +363,8 @@ class QuestionTask(SCons.Taskmaster.Task): pass def execute(self): - if self.targets[0].get_state() != SCons.Node.up_to_date: + if self.targets[0].get_state() != SCons.Node.up_to_date or \ + (self.top and not self.targets[0].exists()): global exit_status exit_status = 1 self.tm.stop() @@ -317,43 +394,49 @@ class TreePrinter: # Global variables -tree_printers = [] - -keep_going_on_error = 0 -print_explanations = 0 -print_includes = 0 print_objects = 0 print_memoizer = 0 print_stacktrace = 0 print_time = 0 -ignore_errors = 0 sconscript_time = 0 cumulative_command_time = 0 exit_status = 0 # exit status, assume success by default -repositories = [] num_jobs = None delayed_warnings = [] -diskcheck_all = SCons.Node.FS.diskcheck_types() -diskcheck_option_set = None +class FakeOptionParser: + """ + A do-nothing option parser, used for the initial OptionsParser variable. -def diskcheck_convert(value): - if value is None: - return [] - if not SCons.Util.is_List(value): - value = string.split(value, ',') - result = [] - for v in map(string.lower, value): - if v == 'all': - result = diskcheck_all - elif v == 'none': - result = [] - elif v in diskcheck_all: - result.append(v) - else: - raise ValueError, v + During normal SCons operation, the OptionsParser is created right + away by the main() function. Certain tests scripts however, can + introspect on different Tool modules, the initialization of which + can try to add a new, local option to an otherwise uninitialized + OptionsParser object. This allows that introspection to happen + without blowing up. + + """ + class FakeOptionValues: + def __getattr__(self, attr): + return None + values = FakeOptionValues() + def add_local_option(self, *args, **kw): + pass + +OptionsParser = FakeOptionParser() + +def AddOption(*args, **kw): + if not kw.has_key('default'): + kw['default'] = None + result = apply(OptionsParser.add_local_option, args, kw) return result +def GetOption(name): + return getattr(OptionsParser.values, name) + +def SetOption(name, value): + return OptionsParser.values.set_option(name, value) + # class Stats: def __init__(self): @@ -483,15 +566,6 @@ def _scons_internal_error(): traceback.print_exc() sys.exit(2) -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 or no-. @@ -537,12 +611,11 @@ def _setup_warn(arg): else: SCons.Warnings.suppressWarningClass(clazz) -def _SConstruct_exists(dirname=''): +def _SConstruct_exists(dirname='', repositories=[]): """This function checks that an SConstruct file exists in a directory. If so, it returns the path of the file. By default, it checks the current directory. """ - global repositories for file in ['SConstruct', 'Sconstruct', 'sconstruct']: sfile = os.path.join(dirname, file) if os.path.isfile(sfile): @@ -553,49 +626,44 @@ def _SConstruct_exists(dirname=''): return sfile return None -def _set_globals(options): - global keep_going_on_error, ignore_errors - global count_stats - global print_explanations, print_includes, print_memoizer - global print_objects, print_stacktrace, print_time - global tree_printers - global memory_stats +def _set_debug_values(options): + global print_memoizer, print_objects, print_stacktrace, print_time - keep_going_on_error = options.keep_going - try: - debug_values = options.debug - if debug_values is None: - debug_values = [] - except AttributeError: - pass - else: - if "count" in debug_values: + debug_values = options.debug + + if "count" in debug_values: + # All of the object counts are within "if __debug__:" blocks, + # which get stripped when running optimized (with python -O or + # from compiled *.pyo files). Provide a warning if __debug__ is + # stripped, so it doesn't just look like --debug=count is broken. + enable_count = False + if __debug__: enable_count = True + if enable_count: count_stats.enable(sys.stdout) - if "dtree" in debug_values: - tree_printers.append(TreePrinter(derived=True)) - if "explain" in debug_values: - print_explanations = 1 - if "findlibs" in debug_values: - SCons.Scanner.Prog.print_find_libs = "findlibs" - if "includes" in debug_values: - print_includes = 1 - if "memoizer" in debug_values: - print_memoizer = 1 - if "memory" in debug_values: - memory_stats.enable(sys.stdout) - if "objects" in debug_values: - print_objects = 1 - if "presub" in debug_values: - SCons.Action.print_actions_presub = 1 - if "stacktrace" in debug_values: - print_stacktrace = 1 - if "stree" in debug_values: - tree_printers.append(TreePrinter(status=True)) - if "time" in debug_values: - print_time = 1 - if "tree" in debug_values: - tree_printers.append(TreePrinter()) - ignore_errors = options.ignore_errors + else: + msg = "--debug=count is not supported when running SCons\n" + \ + "\twith the python -O option or optimized (.pyo) modules." + SCons.Warnings.warn(SCons.Warnings.NoObjectCountWarning, msg) + if "dtree" in debug_values: + options.tree_printers.append(TreePrinter(derived=True)) + options.debug_explain = ("explain" in debug_values) + if "findlibs" in debug_values: + SCons.Scanner.Prog.print_find_libs = "findlibs" + options.debug_includes = ("includes" in debug_values) + print_memoizer = ("memoizer" in debug_values) + if "memory" in debug_values: + memory_stats.enable(sys.stdout) + print_objects = ("objects" in debug_values) + if "presub" in debug_values: + SCons.Action.print_actions_presub = 1 + if "stacktrace" in debug_values: + print_stacktrace = 1 + if "stree" in debug_values: + options.tree_printers.append(TreePrinter(status=True)) + if "time" in debug_values: + print_time = 1 + if "tree" in debug_values: + options.tree_printers.append(TreePrinter()) def _create_path(plist): path = '.' @@ -648,413 +716,39 @@ def _load_site_scons_dir(topdir, site_dir_name=None): SCons.Tool.DefaultToolpath.append(os.path.abspath(site_tools_dir)) def version_string(label, module): - fmt = "\t%s: v%s.%s, %s, by %s on %s\n" + version = module.__version__ + build = module.__build__ + if build: + if build[0] != '.': + build = '.' + build + version = version + build + fmt = "\t%s: v%s, %s, by %s on %s\n" return fmt % (label, - module.__version__, - module.__build__, + version, module.__date__, module.__developer__, module.__buildsys__) -class OptParser(OptionParser): - def __init__(self): - import __main__ - - parts = ["SCons by Steven Knight et al.:\n"] - try: - parts.append(version_string("script", __main__)) - except KeyboardInterrupt: - raise - except: - # On Windows there is no scons.py, so there is no - # __main__.__version__, hence there is no script version. - pass - parts.append(version_string("engine", SCons)) - parts.append("Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation") - 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.") - - self.add_option('-c', '--clean', '--remove', action="store_true", - dest="clean", - help="Remove specified targets and dependencies.") - - self.add_option('-C', '--directory', type="string", action = "append", - metavar="DIR", - help="Change to DIR before doing anything.") - - self.add_option('--cache-debug', action="store", - dest="cache_debug", metavar="FILE", - help="Print CacheDir debug info to FILE.") - - self.add_option('--cache-disable', '--no-cache', - action="store_true", dest='cache_disable', default=0, - help="Do not retrieve built targets from CacheDir.") - - self.add_option('--cache-force', '--cache-populate', - action="store_true", dest='cache_force', default=0, - help="Copy already-built targets into the CacheDir.") - - self.add_option('--cache-show', - action="store_true", dest='cache_show', default=0, - help="Print build actions for files from CacheDir.") - - config_options = ["auto", "force" ,"cache"] - - def opt_config(option, opt, value, parser, c_options=config_options): - if value in c_options: - parser.values.config = value - else: - raise OptionValueError("Warning: %s is not a valid config type" % value) - self.add_option('--config', action="callback", type="string", - callback=opt_config, nargs=1, dest="config", - metavar="MODE", default="auto", - help="Controls Configure subsystem: " - "%s." % string.join(config_options, ", ")) - - 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.") - - debug_options = ["count", "dtree", "explain", "findlibs", - "includes", "memoizer", "memory", "objects", - "pdb", "presub", "stacktrace", "stree", - "time", "tree"] - - deprecated_debug_options = { - "nomemoizer" : ' and has no effect', - } - - def opt_debug(option, opt, value, parser, debug_options=debug_options, deprecated_debug_options=deprecated_debug_options): - if value in debug_options: - try: - if parser.values.debug is None: - parser.values.debug = [] - except AttributeError: - parser.values.debug = [] - parser.values.debug.append(value) - elif value in deprecated_debug_options.keys(): - msg = deprecated_debug_options[value] - w = "The --debug=%s option is deprecated%s." % (value, msg) - delayed_warnings.append((SCons.Warnings.DeprecatedWarning, w)) - 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", - metavar="TYPE", - help="Print various types of debugging information: " - "%s." % string.join(debug_options, ", ")) - - def opt_diskcheck(option, opt, value, parser): - try: - global diskcheck_option_set - diskcheck_option_set = diskcheck_convert(value) - SCons.Node.FS.set_diskcheck(diskcheck_option_set) - except ValueError, e: - raise OptionValueError("Warning: `%s' is not a valid diskcheck type" % e) - - - self.add_option('--diskcheck', action="callback", type="string", - callback=opt_diskcheck, dest='diskcheck', - metavar="TYPE", - help="Enable specific on-disk checks.") - - def opt_duplicate(option, opt, value, parser): - if not value in SCons.Node.FS.Valid_Duplicates: - raise OptionValueError("`%s' is not a valid duplication style." % value) - parser.values.duplicate = value - # Set the duplicate style right away so it can affect linking - # of SConscript files. - SCons.Node.FS.set_duplicate(value) - self.add_option('--duplicate', action="callback", type="string", - callback=opt_duplicate, nargs=1, dest="duplicate", - help="Set the preferred duplication methods. Must be one of " - + string.join(SCons.Node.FS.Valid_Duplicates, ", ")) - - 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="DIR", - help="Search DIR for imported Python modules.") - - self.add_option('--implicit-cache', action="store_true", - dest='implicit_cache', - help="Cache implicit dependencies") - - self.add_option('--implicit-deps-changed', action="store_true", - default=0, dest='implicit_deps_changed', - help="Ignore cached implicit dependencies.") - self.add_option('--implicit-deps-unchanged', action="store_true", - default=0, dest='implicit_deps_unchanged', - help="Ignore changes in implicit dependencies.") - - def opt_j(option, opt, value, parser): - value = int(value) - 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', metavar="N", - help="Set maximum system clock drift to N 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.") - - self.add_option('--no-site-dir', action="store_true", - dest='no_site_dir', default=0, - help="Don't search or use the usual site_scons dir.") - - self.add_option('--profile', action="store", - dest="profile_file", metavar="FILE", - help="Profile SCons and put results in FILE.") - - 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="Suppress \"Reading/Building\" progress messages.") - - self.add_option('--random', dest="random", action="store_true", - default=0, help="Build dependencies in random order.") - - self.add_option('-s', '--silent', '--quiet', action="store_true", - default=0, help="Don't print commands.") - - self.add_option('--site-dir', action="store", - dest='site_dir', metavar="DIR", - help="Use DIR instead of the usual site_scons dir.") - - self.add_option('--taskmastertrace', action="store", - dest="taskmastertrace_file", metavar="FILE", - help="Trace Node evaluation to FILE.") - - tree_options = ["all", "derived", "prune", "status"] - - def opt_tree(option, opt, value, parser, tree_options=tree_options): - tp = TreePrinter() - for o in string.split(value, ','): - if o == 'all': - tp.derived = False - elif o == 'derived': - tp.derived = True - elif o == 'prune': - tp.prune = True - elif o == 'status': - tp.status = True - else: - raise OptionValueError("Warning: %s is not a valid --tree option" % o) - tree_printers.append(tp) - - self.add_option('--tree', action="callback", type="string", - callback=opt_tree, nargs=1, metavar="OPTIONS", - help="Print a dependency tree in various formats: " - "%s." % string.join(tree_options, ", ")) - - 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', '--srcdir', - nargs=1, action="append", - help="Search REPOSITORY for source and target files.") - - 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('-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 - return opt, arglist - -class SConscriptSettableOptions: - """This class wraps an OptParser instance and provides - uniform access to options that can be either set on the command - line or from a SConscript file. A value specified on the command - line always overrides a value set in a SConscript file. - Not all command line options are SConscript settable, and the ones - that are must be explicitly added to settable dictionary and optionally - validated and coerced in the set() method.""" - - def __init__(self, options): - self.options = options - - # This dictionary stores the defaults for all the SConscript - # settable options, as well as indicating which options - # are SConscript settable. - self.settable = {'num_jobs':1, - 'max_drift':SCons.Node.FS.default_max_drift, - 'implicit_cache':0, - 'clean':0, - 'duplicate':'hard-soft-copy', - 'diskcheck':diskcheck_all} - - def get(self, name): - if not self.settable.has_key(name): - raise SCons.Errors.UserError, "This option is not settable from a SConscript file: %s"%name - if hasattr(self.options, name) and getattr(self.options, name) is not None: - return getattr(self.options, name) - else: - return self.settable[name] - - def set(self, name, value): - if not self.settable.has_key(name): - raise SCons.Errors.UserError, "This option is not settable from a SConscript file: %s"%name - - if name == 'num_jobs': - try: - value = int(value) - if value < 1: - raise ValueError - except ValueError: - raise SCons.Errors.UserError, "A positive integer is required: %s"%repr(value) - elif name == 'max_drift': - try: - value = int(value) - except ValueError: - raise SCons.Errors.UserError, "An integer is required: %s"%repr(value) - elif name == 'duplicate': - try: - value = str(value) - except ValueError: - raise SCons.Errors.UserError, "A string is required: %s"%repr(value) - if not value in SCons.Node.FS.Valid_Duplicates: - raise SCons.Errors.UserError, "Not a valid duplication style: %s" % value - # Set the duplicate stye right away so it can affect linking - # of SConscript files. - SCons.Node.FS.set_duplicate(value) - elif name == 'diskcheck': - try: - value = diskcheck_convert(value) - except ValueError, v: - raise SCons.Errors.UserError, "Not a valid diskcheck value: %s"%v - if not diskcheck_option_set: - SCons.Node.FS.set_diskcheck(value) - - self.settable[name] = value - - -def _main(args, parser): +def _main(parser): + import SCons global exit_status + options = parser.values + # Here's where everything really happens. - # First order of business: set up default warnings and and then - # handle the user's warning options, so we can warn about anything - # that happens appropriately. + # First order of business: set up default warnings and then + # handle the user's warning options, so that we can issue (or + # suppress) appropriate warnings about anything that might happen, + # as configured by the user. + default_warnings = [ SCons.Warnings.CorruptSConsignWarning, SCons.Warnings.DeprecatedWarning, SCons.Warnings.DuplicateEnvironmentWarning, SCons.Warnings.MissingSConscriptWarning, SCons.Warnings.NoMD5ModuleWarning, SCons.Warnings.NoMetaclassSupportWarning, + SCons.Warnings.NoObjectCountWarning, SCons.Warnings.NoParallelSupportWarning, SCons.Warnings.MisleadingKeywordsWarning, ] for warning in default_warnings: @@ -1063,9 +757,21 @@ def _main(args, parser): if options.warn: _setup_warn(options.warn) + # Now that we have the warnings configuration set up, we can actually + # issue (or suppress) any warnings about warning-worthy things that + # occurred while the command-line options were getting parsed. + try: + dw = options.delayed_warnings + except AttributeError: + pass + else: + delayed_warnings.extend(dw) for warning_type, message in delayed_warnings: SCons.Warnings.warn(warning_type, message) + if options.diskcheck: + SCons.Node.FS.set_diskcheck(options.diskcheck) + # Next, we want to create the FS object that represents the outside # world's file system, as that's central to a lot of initialization. # To do this, however, we need to be in the directory from which we @@ -1078,17 +784,11 @@ def _main(args, parser): except OSError: sys.stderr.write("Could not change directory to %s\n" % cdir) - # The SConstruct file may be in a repository, so initialize those - # before we start the search up our path for one. - global repositories - if options.repository: - repositories.extend(options.repository) - 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): + while script_dir and not _SConstruct_exists(script_dir, options.repository): script_dir, last_part = os.path.split(script_dir) if last_part: target_top = os.path.join(last_part, target_top) @@ -1101,9 +801,9 @@ def _main(args, parser): # Now that we're in the top-level SConstruct directory, go ahead # and initialize the FS object that represents the file system, # and make it the build engine default. - fs = SCons.Node.FS.default_fs = SCons.Node.FS.FS() + fs = SCons.Node.FS.get_default_fs() - for rep in repositories: + for rep in options.repository: fs.Repository(rep) # Now that we have the FS object, the next order of business is to @@ -1113,18 +813,16 @@ def _main(args, parser): if options.file: scripts.extend(options.file) if not scripts: - sfile = _SConstruct_exists() + sfile = _SConstruct_exists(repositories=options.repository) if sfile: scripts.append(sfile) if not scripts: - if options.help_msg: + if options.help: # 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. - parser.print_help() - exit_status = 0 - return + raise SConsPrintHelpException raise SCons.Errors.UserError, "No SConstruct file found." if scripts[0] == "-": @@ -1133,21 +831,20 @@ def _main(args, parser): d = fs.File(scripts[0]).dir fs.set_SConstruct_dir(d) - # Now that we have the FS object and it's intialized, set up (most - # of) the rest of the options. - global ssoptions - ssoptions = SConscriptSettableOptions(options) - - _set_globals(options) + _set_debug_values(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.noexec: + if options.no_exec: SCons.SConf.dryrun = 1 SCons.Action.execute_actions = None CleanTask.execute = CleanTask.show if options.question: SCons.SConf.dryrun = 1 + if options.clean: + SCons.SConf.SetBuildType('clean') + if options.help: + SCons.SConf.SetBuildType('help') SCons.SConf.SetCacheMode(options.config) SCons.SConf.SetProgressDisplay(progress_display) @@ -1158,15 +855,14 @@ def _main(args, parser): if options.silent: SCons.Action.print_actions = None - if options.cache_debug: - fs.CacheDebugEnable(options.cache_debug) if options.cache_disable: - def disable(self): pass - fs.CacheDir = disable + SCons.CacheDir.CacheDir = SCons.Util.Null() + if options.cache_debug: + SCons.CacheDir.cache_debug = options.cache_debug if options.cache_force: - fs.cache_force = 1 + SCons.CacheDir.cache_force = True if options.cache_show: - fs.cache_show = 1 + SCons.CacheDir.cache_show = True if options.site_dir: _load_site_scons_dir(d, options.site_dir) @@ -1181,12 +877,14 @@ def _main(args, parser): # read and execute have access to them. targets = [] xmit_args = [] - for a in args: + for a in parser.largs: + if a[0] == '-': + continue if '=' in a: xmit_args.append(a) else: targets.append(a) - SCons.Script._Add_Targets(targets) + SCons.Script._Add_Targets(targets + parser.rargs) SCons.Script._Add_Arguments(xmit_args) sys.stdout = SCons.Util.Unbuffered(sys.stdout) @@ -1194,6 +892,8 @@ def _main(args, parser): memory_stats.append('before reading SConscript files:') count_stats.append(('pre-', 'read')) + # And here's where we (finally) read the SConscript files. + progress_display("scons: Reading SConscript files ...") start_time = time.time() @@ -1211,37 +911,51 @@ def _main(args, parser): sys.exit(exit_status) global sconscript_time sconscript_time = time.time() - start_time - SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment()) - progress_display("scons: done reading SConscript files.") - # Tell the Node.FS subsystem that we're all done reading the - # SConscript files and calling Repository() and BuildDir() and the - # like, so it can go ahead and start memoizing the string values of - # file system nodes. - SCons.Node.FS.save_strings(1) + progress_display("scons: done reading SConscript files.") memory_stats.append('after reading SConscript files:') count_stats.append(('post-', 'read')) - fs.chdir(fs.Top) + if not options.help: + SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment()) - if options.help_msg: + # Now re-parse the command-line options (any to the left of a '--' + # argument, that is) with any user-defined command-line options that + # the SConscript files may have added to the parser object. This will + # emit the appropriate error message and exit if any unknown option + # was specified on the command line. + + parser.preserve_unknown_options = False + parser.parse_args(parser.largs, options) + + if options.help: help_text = SCons.Script.help_text if help_text is None: # They specified -h, but there was no Help() inside the # SConscript files. Give them the options usage. - parser.print_help(sys.stdout) + raise SConsPrintHelpException else: print help_text print "Use scons -H for help about command-line options." exit_status = 0 return + # Change directory to the top-level SConstruct directory, then tell + # the Node.FS subsystem that we're all done reading the SConscript + # files and calling Repository() and BuildDir() and changing + # directories and the like, so it can go ahead and start memoizing + # the string values of file system nodes. + + fs.chdir(fs.Top) + + SCons.Node.FS.save_strings(1) + # Now that we've read the SConscripts we can set the options # that are SConscript settable: - SCons.Node.implicit_cache = ssoptions.get('implicit_cache') - SCons.Node.FS.set_duplicate(ssoptions.get('duplicate')) - fs.set_max_drift(ssoptions.get('max_drift')) + SCons.Node.implicit_cache = options.implicit_cache + SCons.Node.FS.set_duplicate(options.duplicate) + fs.set_max_drift(options.max_drift) lookup_top = None if targets or SCons.Script.BUILD_TARGETS != SCons.Script._build_plus_default: @@ -1320,27 +1034,30 @@ def _main(args, parser): task_class = BuildTask # default action is to build targets opening_message = "Building targets ..." closing_message = "done building targets." - if keep_going_on_error: + if options.keep_going: failure_message = "done building targets (errors occurred during build)." else: failure_message = "building terminated because of errors." if options.question: task_class = QuestionTask try: - if ssoptions.get('clean'): + if options.clean: task_class = CleanTask opening_message = "Cleaning targets ..." closing_message = "done cleaning targets." - if keep_going_on_error: + if options.keep_going: closing_message = "done cleaning targets (errors occurred during clean)." else: failure_message = "cleaning terminated because of errors." except AttributeError: pass + task_class.progress = ProgressObject + if options.random: def order(dependencies): """Randomize the dependencies.""" + import random # This is cribbed from the implementation of # random.shuffle() in Python 2.X. d = dependencies @@ -1353,7 +1070,6 @@ def _main(args, parser): """Leave the order of dependencies alone.""" return dependencies - progress_display("scons: " + opening_message) if options.taskmastertrace_file == '-': tmtrace = sys.stdout elif options.taskmastertrace_file: @@ -1362,40 +1078,51 @@ def _main(args, parser): tmtrace = None taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace) + # Let the BuildTask objects get at the options to respond to the + # various print_* settings, tree_printer list, etc. + BuildTask.options = options + global num_jobs - num_jobs = ssoptions.get('num_jobs') + num_jobs = options.num_jobs jobs = SCons.Job.Jobs(num_jobs, taskmaster) - if num_jobs > 1 and jobs.num_jobs == 1: - msg = "parallel builds are unsupported by this version of Python;\n" + \ - "\tignoring -j or num_jobs option.\n" - SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg) + if num_jobs > 1: + msg = None + if jobs.num_jobs == 1: + msg = "parallel builds are unsupported by this version of Python;\n" + \ + "\tignoring -j or num_jobs option.\n" + elif sys.platform == 'win32': + import SCons.Platform.win32 + msg = SCons.Platform.win32.parallel_msg + if msg: + SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg) memory_stats.append('before building targets:') count_stats.append(('pre-', 'build')) try: + progress_display("scons: " + opening_message) jobs.run() finally: + jobs.cleanup() if exit_status: progress_display("scons: " + failure_message) else: progress_display("scons: " + closing_message) - if not options.noexec: + if not options.no_exec: SCons.SConsign.write() memory_stats.append('after building targets:') count_stats.append(('post-', 'build')) -def _exec_main(): +def _exec_main(parser, values): sconsflags = os.environ.get('SCONSFLAGS', '') all_args = string.split(sconsflags) + sys.argv[1:] - parser = OptParser() - global options - options, args = parser.parse_args(all_args) + options, args = parser.parse_args(all_args, values) + if type(options.debug) == type([]) and "pdb" in options.debug: import pdb - pdb.Pdb().runcall(_main, args, parser) + pdb.Pdb().runcall(_main, parser) elif options.profile_file: from profile import Profile @@ -1413,19 +1140,42 @@ def _exec_main(): prof = Profile() try: - prof.runcall(_main, args, parser) + prof.runcall(_main, parser) + except SConsPrintHelpException, e: + prof.dump_stats(options.profile_file) + raise e except SystemExit: pass prof.dump_stats(options.profile_file) else: - _main(args, parser) + _main(parser) def main(): + global OptionsParser global exit_status global first_command_start + + parts = ["SCons by Steven Knight et al.:\n"] + try: + parts.append(version_string("script", __main__)) + except KeyboardInterrupt: + raise + except: + # On Windows there is no scons.py, so there is no + # __main__.__version__, hence there is no script version. + pass + parts.append(version_string("engine", SCons)) + parts.append("Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation") + version = string.join(parts, '') + + import SConsOptions + parser = SConsOptions.Parser(version) + values = SConsOptions.SConsValues(parser.get_default_values()) + + OptionsParser = parser try: - _exec_main() + _exec_main(parser, values) except SystemExit, s: if s: exit_status = s @@ -1438,6 +1188,9 @@ def main(): _scons_internal_error() except SCons.Errors.UserError, e: _scons_user_error(e) + except SConsPrintHelpException: + parser.print_help() + exit_status = 0 except: # An exception here is likely a builtin Python exception Python # code in an SConscript file. Show them precisely what the @@ -1467,7 +1220,10 @@ def main(): if num_jobs == 1: ct = cumulative_command_time else: - ct = last_command_end - first_command_start + if last_command_end is None or first_command_start is None: + ct = 0.0 + else: + ct = last_command_end - first_command_start scons_time = total_time - sconscript_time - ct print "Total build time: %f seconds"%total_time print "Total SConscript file execution time: %f seconds"%sconscript_time diff --git a/scons/scons-local-0.97.0d20071212/SCons/Script/SConsOptions.py b/scons/scons-local-0.97.0d20071212/SCons/Script/SConsOptions.py new file mode 100644 index 000000000..d466d43d8 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Script/SConsOptions.py @@ -0,0 +1,884 @@ +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Script/SConsOptions.py 2523 2007/12/12 09:37:41 knight" + +import SCons.compat + +import optparse +import string +import sys +import textwrap + +try: + from gettext import gettext +except ImportError: + def gettext(message): + return message +_ = gettext + +import SCons.Node.FS + +OptionValueError = optparse.OptionValueError +SUPPRESS_HELP = optparse.SUPPRESS_HELP + +diskcheck_all = SCons.Node.FS.diskcheck_types() + +def diskcheck_convert(value): + if value is None: + return [] + if not SCons.Util.is_List(value): + value = string.split(value, ',') + result = [] + for v in map(string.lower, value): + if v == 'all': + result = diskcheck_all + elif v == 'none': + result = [] + elif v in diskcheck_all: + result.append(v) + else: + raise ValueError, v + return result + +class SConsValues(optparse.Values): + """ + Holder class for uniform access to SCons options, regardless + of whether or not they can be set on the command line or in the + SConscript files (using the SetOption() function). + + A SCons option value can originate three different ways: + + 1) set on the command line; + 2) set in an SConscript file; + 3) the default setting (from the the op.add_option() + calls in the Parser() function, below). + + The command line always overrides a value set in a SConscript file, + which in turn always overrides default settings. Because we want + to support user-specified options in the SConscript file itself, + though, we may not know about all of the options when the command + line is first parsed, so we can't make all the necessary precedence + decisions at the time the option is configured. + + The solution implemented in this class is to keep these different sets + of settings separate (command line, SConscript file, and default) + and to override the __getattr__() method to check them in turn. + This should allow the rest of the code to just fetch values as + attributes of an instance of this class, without having to worry + about where they came from. + + Note that not all command line options are settable from SConscript + files, and the ones that are must be explicitly added to the + "settable" list in this class, and optionally validated and coerced + in the set_option() method. + """ + + def __init__(self, defaults): + self.__dict__['__defaults__'] = defaults + self.__dict__['__SConscript_settings__'] = {} + + def __getattr__(self, attr): + """ + Fetches an options value, checking first for explicit settings + from the command line (which are direct attributes), then the + SConscript file settings, then the default values. + """ + try: + return self.__dict__[attr] + except KeyError: + try: + return self.__dict__['__SConscript_settings__'][attr] + except KeyError: + return getattr(self.__dict__['__defaults__'], attr) + + settable = [ + 'clean', + 'diskcheck', + 'duplicate', + 'help', + 'implicit_cache', + 'max_drift', + 'no_exec', + 'num_jobs', + 'random', + ] + + def set_option(self, name, value): + """ + Sets an option from an SConscript file. + """ + if not name in self.settable: + raise SCons.Errors.UserError, "This option is not settable from a SConscript file: %s"%name + + if name == 'num_jobs': + try: + value = int(value) + if value < 1: + raise ValueError + except ValueError: + raise SCons.Errors.UserError, "A positive integer is required: %s"%repr(value) + elif name == 'max_drift': + try: + value = int(value) + except ValueError: + raise SCons.Errors.UserError, "An integer is required: %s"%repr(value) + elif name == 'duplicate': + try: + value = str(value) + except ValueError: + raise SCons.Errors.UserError, "A string is required: %s"%repr(value) + if not value in SCons.Node.FS.Valid_Duplicates: + raise SCons.Errors.UserError, "Not a valid duplication style: %s" % value + # Set the duplicate style right away so it can affect linking + # of SConscript files. + SCons.Node.FS.set_duplicate(value) + elif name == 'diskcheck': + try: + value = diskcheck_convert(value) + except ValueError, v: + raise SCons.Errors.UserError, "Not a valid diskcheck value: %s"%v + if not self.__dict__.has_key('diskcheck'): + # No --diskcheck= option was specified on the command line. + # Set this right away so it can affect the rest of the + # file/Node lookups while processing the SConscript files. + SCons.Node.FS.set_diskcheck(value) + + self.__SConscript_settings__[name] = value + +class SConsOption(optparse.Option): + def convert_value(self, opt, value): + if value is not None: + if self.nargs in (1, '?'): + return self.check_value(opt, value) + else: + return tuple(map(lambda v, o=opt, s=self: s.check_value(o, v), value)) + + def process(self, opt, value, values, parser): + + # First, convert the value(s) to the right type. Howl if any + # value(s) are bogus. + value = self.convert_value(opt, 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 _check_nargs_optional(self): + if self.nargs == '?' and self._short_opts: + fmt = "option %s: nargs='?' is incompatible with short options" + raise SCons.Errors.UserError, fmt % self._short_opts[0] + + try: + _orig_CONST_ACTIONS = optparse.Option.CONST_ACTIONS + + _orig_CHECK_METHODS = optparse.Option.CHECK_METHODS + + except AttributeError: + # optparse.Option had no CONST_ACTIONS before Python 2.5. + + _orig_CONST_ACTIONS = ("store_const",) + + def _check_const(self): + if self.action not in self.CONST_ACTIONS and self.const is not None: + raise OptionError( + "'const' must not be supplied for action %r" % self.action, + self) + + # optparse.Option collects its list of unbound check functions + # up front. This sucks because it means we can't just override + # the _check_const() function like a normal method, we have to + # actually replace it in the list. This seems to be the most + # straightforward way to do that. + + _orig_CHECK_METHODS = [optparse.Option._check_action, + optparse.Option._check_type, + optparse.Option._check_choice, + optparse.Option._check_dest, + _check_const, + optparse.Option._check_nargs, + optparse.Option._check_callback] + + CHECK_METHODS = _orig_CHECK_METHODS + [_check_nargs_optional] + + CONST_ACTIONS = _orig_CONST_ACTIONS + optparse.Option.TYPED_ACTIONS + +class SConsOptionGroup(optparse.OptionGroup): + """ + A subclass for SCons-specific option groups. + + The only difference between this and the base class is that we print + the group's help text flush left, underneath their own title but + lined up with the normal "SCons Options". + """ + def format_help(self, formatter): + """ + Format an option group's help text, outdenting the title so it's + flush with the "SCons Options" title we print at the top. + """ + formatter.dedent() + result = formatter.format_heading(self.title) + formatter.indent() + result = result + optparse.OptionContainer.format_help(self, formatter) + return result + +class SConsOptionParser(optparse.OptionParser): + preserve_unknown_options = False + + def error(self, msg): + self.print_usage(sys.stderr) + sys.stderr.write("SCons error: %s\n" % msg) + sys.exit(2) + + def _process_long_opt(self, rargs, values): + """ + SCons-specific processing of long options. + + This is copied directly from the normal + optparse._process_long_opt() method, except that, if configured + to do so, we catch the exception thrown when an unknown option + is encountered and just stick it back on the "leftover" arguments + for later (re-)processing. + """ + 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 = True + else: + opt = arg + had_explicit_value = False + + try: + opt = self._match_long_opt(opt) + except optparse.BadOptionError: + if self.preserve_unknown_options: + # SCons-specific: if requested, add unknown options to + # the "leftover arguments" list for later processing. + self.largs.append(arg) + if had_explicit_value: + # The unknown option will be re-processed later, + # so undo the insertion of the explicit value. + rargs.pop(0) + return + raise + + option = self._long_opt[opt] + if option.takes_value(): + nargs = option.nargs + if nargs == '?': + if had_explicit_value: + value = rargs.pop(0) + else: + value = option.const + elif len(rargs) < nargs: + if nargs == 1: + self.error(_("%s option requires an argument") % opt) + else: + self.error(_("%s option requires %d arguments") + % (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 add_local_option(self, *args, **kw): + """ + Adds a local option to the parser. + + This is initiated by a SetOption() call to add a user-defined + command-line option. We add the option to a separate option + group for the local options, creating the group if necessary. + """ + try: + group = self.local_option_group + except AttributeError: + group = SConsOptionGroup(self, 'Local Options') + group = self.add_option_group(group) + self.local_option_group = group + + result = apply(group.add_option, args, kw) + + if result: + # The option was added succesfully. We now have to add the + # default value to our object that holds the default values + # (so that an attempt to fetch the option's attribute will + # yield the default value when not overridden) and then + # we re-parse the leftover command-line options, so that + # any value overridden on the command line is immediately + # 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) + + return result + +class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter): + def format_usage(self, usage): + return "usage: %s\n" % usage + + def format_heading(self, heading): + """ + This translates any heading of "options" or "Options" into + "SCons Options." Unfortunately, we have to do this here, + because those titles are hard-coded in the optparse calls. + """ + if heading == 'options': + # The versions of optparse.py shipped with Pythons 2.3 and + # 2.4 pass this in uncapitalized; override that so we get + # consistent output on all versions. + heading = "Options" + if heading == 'Options': + heading = "SCons Options" + return optparse.IndentedHelpFormatter.format_heading(self, heading) + + def format_option(self, option): + """ + A copy of the normal optparse.IndentedHelpFormatter.format_option() + method, snarfed so we can set the subsequent_indent on the + textwrap.wrap() call below... + """ + # 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 + result = [] + + try: + opts = self.option_strings[option] + except AttributeError: + # The Python 2.3 version of optparse attaches this to + # to the option argument, not to this object. + opts = option.option_strings + + opt_width = self.help_position - self.current_indent - 2 + if len(opts) > opt_width: + opts = "%*s%s\n" % (self.current_indent, "", opts) + indent_first = self.help_position + else: # start help on same line as opts + opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts) + indent_first = 0 + result.append(opts) + if option.help: + + try: + expand_default = self.expand_default + except AttributeError: + # The HelpFormatter base class in the Python 2.3 version + # of optparse has no expand_default() method. + help_text = option.help + else: + help_text = expand_default(option) + + # SCons: indent every line of the help text but the first. + help_lines = textwrap.wrap(help_text, self.help_width, + subsequent_indent = ' ') + result.append("%*s%s\n" % (indent_first, "", help_lines[0])) + for line in help_lines[1:]: + result.append("%*s%s\n" % (self.help_position, "", line)) + elif opts[-1] != "\n": + result.append("\n") + return string.join(result, "") + + # For consistent help output across Python versions, we provide a + # subclass copy of format_option_strings() and these two variables. + # This is necessary (?) for Python2.3, which otherwise concatenates + # a short option with its metavar. + _short_opt_fmt = "%s %s" + _long_opt_fmt = "%s=%s" + + def format_option_strings(self, option): + """Return a comma-separated list of option strings & metavariables.""" + if option.takes_value(): + metavar = option.metavar or string.upper(option.dest) + short_opts = [] + for sopt in option._short_opts: + short_opts.append(self._short_opt_fmt % (sopt, metavar)) + long_opts = [] + for lopt in option._long_opts: + long_opts.append(self._long_opt_fmt % (lopt, metavar)) + else: + short_opts = option._short_opts + long_opts = option._long_opts + + if self.short_first: + opts = short_opts + long_opts + else: + opts = long_opts + short_opts + + return string.join(opts, ", ") + +def Parser(version): + """ + Returns an options parser object initialized with the standard + SCons options. + """ + + formatter = SConsIndentedHelpFormatter(max_help_position=30) + + op = SConsOptionParser(option_class=SConsOption, + add_help_option=False, + formatter=formatter, + usage="usage: scons [OPTION] [TARGET] ...",) + + op.preserve_unknown_options = True + + # Add the options to the parser we just created. + # + # These are in the order we want them to show up in the -H help + # text, basically alphabetical. Each op.add_option() call below + # should have a consistent format: + # + # op.add_option("-L", "--long-option-name", + # nargs=1, type="string", + # dest="long_option_name", default='foo', + # action="callback", callback=opt_long_option, + # help="help text goes here", + # metavar="VAR") + # + # Even though the optparse module constructs reasonable default + # destination names from the long option names, we're going to be + # explicit about each one for easier readability and so this code + # will at least show up when grepping the source for option attribute + # names, or otherwise browsing the source code. + + # options ignored for compatibility + def opt_ignore(option, opt, value, parser): + sys.stderr.write("Warning: ignoring %s option\n" % opt) + op.add_option("-b", "-m", "-S", "-t", + "--no-keep-going", "--stop", "--touch", + action="callback", callback=opt_ignore, + help="Ignored for compatibility.") + + op.add_option('-c', '--clean', '--remove', + dest="clean", default=False, + action="store_true", + help="Remove specified targets and dependencies.") + + op.add_option('-C', '--directory', + nargs=1, type="string", + dest="directory", default=[], + action="append", + help="Change to DIR before doing anything.", + metavar="DIR") + + op.add_option('--cache-debug', + nargs=1, + dest="cache_debug", default=None, + action="store", + help="Print CacheDir debug info to FILE.", + metavar="FILE") + + op.add_option('--cache-disable', '--no-cache', + dest='cache_disable', default=False, + action="store_true", + help="Do not retrieve built targets from CacheDir.") + + op.add_option('--cache-force', '--cache-populate', + dest='cache_force', default=False, + action="store_true", + help="Copy already-built targets into the CacheDir.") + + op.add_option('--cache-show', + dest='cache_show', default=False, + action="store_true", + help="Print build actions for files from CacheDir.") + + config_options = ["auto", "force" ,"cache"] + + def opt_config(option, opt, value, parser, c_options=config_options): + if not value in c_options: + raise OptionValueError("Warning: %s is not a valid config type" % value) + setattr(parser.values, option.dest, value) + opt_config_help = "Controls Configure subsystem: %s." \ + % string.join(config_options, ", ") + op.add_option('--config', + nargs=1, type="string", + dest="config", default="auto", + action="callback", callback=opt_config, + help = opt_config_help, + metavar="MODE") + + def opt_not_yet(option, opt, value, parser): + sys.stderr.write("Warning: the %s option is not yet implemented\n" % opt) + sys.exit(0) + op.add_option('-d', + action="callback", callback=opt_not_yet, + help = "Print file dependency information.") + + op.add_option('-D', + dest="climb_up", default=None, + action="store_const", const=2, + help="Search up directory tree for SConstruct, " + "build all Default() targets.") + + debug_options = ["count", "dtree", "explain", "findlibs", + "includes", "memoizer", "memory", "objects", + "pdb", "presub", "stacktrace", "stree", + "time", "tree"] + + deprecated_debug_options = { + "nomemoizer" : ' and has no effect', + } + + def opt_debug(option, opt, value, parser, + debug_options=debug_options, + deprecated_debug_options=deprecated_debug_options): + if value in debug_options: + parser.values.debug.append(value) + elif value in deprecated_debug_options.keys(): + try: + parser.values.delayed_warnings + except AttributeError: + parser.values.delayed_warnings = [] + msg = deprecated_debug_options[value] + w = "The --debug=%s option is deprecated%s." % (value, msg) + t = (SCons.Warnings.DeprecatedWarning, w) + parser.values.delayed_warnings.append(t) + else: + raise OptionValueError("Warning: %s is not a valid debug type" % value) + opt_debug_help = "Print various types of debugging information: %s." \ + % string.join(debug_options, ", ") + op.add_option('--debug', + nargs=1, type="string", + dest="debug", default=[], + action="callback", callback=opt_debug, + help=opt_debug_help, + metavar="TYPE") + + def opt_diskcheck(option, opt, value, parser): + try: + diskcheck_value = diskcheck_convert(value) + except ValueError, e: + raise OptionValueError("Warning: `%s' is not a valid diskcheck type" % e) + setattr(parser.values, option.dest, diskcheck_value) + + op.add_option('--diskcheck', + nargs=1, type="string", + dest='diskcheck', default=None, + action="callback", callback=opt_diskcheck, + help="Enable specific on-disk checks.", + metavar="TYPE") + + def opt_duplicate(option, opt, value, parser): + if not value in SCons.Node.FS.Valid_Duplicates: + raise OptionValueError("`%s' is not a valid duplication style." % value) + setattr(parser.values, option.dest, value) + # Set the duplicate style right away so it can affect linking + # of SConscript files. + SCons.Node.FS.set_duplicate(value) + + opt_duplicate_help = "Set the preferred duplication methods. Must be one of " \ + + string.join(SCons.Node.FS.Valid_Duplicates, ", ") + + op.add_option('--duplicate', + nargs=1, type="string", + dest="duplicate", default='hard-soft-copy', + action="callback", callback=opt_duplicate, + help=opt_duplicate_help) + + op.add_option('-f', '--file', '--makefile', '--sconstruct', + nargs=1, type="string", + dest="file", default=[], + action="append", + help="Read FILE as the top-level SConstruct file.") + + op.add_option('-h', '--help', + dest="help", default=False, + action="store_true", + help="Print defined help message, or this one.") + + op.add_option("-H", "--help-options", + action="help", + help="Print this message and exit.") + + op.add_option('-i', '--ignore-errors', + dest='ignore_errors', default=False, + action="store_true", + help="Ignore errors from build actions.") + + op.add_option('-I', '--include-dir', + nargs=1, + dest='include_dir', default=[], + action="append", + help="Search DIR for imported Python modules.", + metavar="DIR") + + op.add_option('--implicit-cache', + dest='implicit_cache', default=False, + action="store_true", + help="Cache implicit dependencies") + + def opt_implicit_deps(option, opt, value, parser): + setattr(parser.values, 'implicit_cache', True) + setattr(parser.values, option.dest, True) + + op.add_option('--implicit-deps-changed', + dest="implicit_deps_changed", default=False, + action="callback", callback=opt_implicit_deps, + help="Ignore cached implicit dependencies.") + + op.add_option('--implicit-deps-unchanged', + dest="implicit_deps_unchanged", default=False, + action="callback", callback=opt_implicit_deps, + help="Ignore changes in implicit dependencies.") + + op.add_option('-j', '--jobs', + nargs=1, type="int", + dest="num_jobs", default=1, + action="store", + help="Allow N jobs at once.", + metavar="N") + + op.add_option('-k', '--keep-going', + dest='keep_going', default=False, + action="store_true", + help="Keep going when a target can't be made.") + + op.add_option('--max-drift', + nargs=1, type="int", + dest='max_drift', default=SCons.Node.FS.default_max_drift, + action="store", + help="Set maximum system clock drift to N seconds.", + metavar="N") + + op.add_option('-n', '--no-exec', '--just-print', '--dry-run', '--recon', + dest='no_exec', default=False, + action="store_true", + help="Don't build; just print commands.") + + op.add_option('--no-site-dir', + dest='no_site_dir', default=False, + action="store_true", + help="Don't search or use the usual site_scons dir.") + + op.add_option('--profile', + nargs=1, + dest="profile_file", default=None, + action="store", + help="Profile SCons and put results in FILE.", + metavar="FILE") + + op.add_option('-q', '--question', + dest="question", default=False, + action="store_true", + help="Don't build; exit status says if up to date.") + + op.add_option('-Q', + dest='no_progress', default=False, + action="store_true", + help="Suppress \"Reading/Building\" progress messages.") + + op.add_option('--random', + dest="random", default=False, + action="store_true", + help="Build dependencies in random order.") + + op.add_option('-s', '--silent', '--quiet', + dest="silent", default=False, + action="store_true", + help="Don't print commands.") + + op.add_option('--site-dir', + nargs=1, + dest='site_dir', default=None, + action="store", + help="Use DIR instead of the usual site_scons dir.", + metavar="DIR") + + op.add_option('--taskmastertrace', + nargs=1, + dest="taskmastertrace_file", default=None, + action="store", + help="Trace Node evaluation to FILE.", + metavar="FILE") + + tree_options = ["all", "derived", "prune", "status"] + + def opt_tree(option, opt, value, parser, tree_options=tree_options): + import Main + tp = Main.TreePrinter() + for o in string.split(value, ','): + if o == 'all': + tp.derived = False + elif o == 'derived': + tp.derived = True + elif o == 'prune': + tp.prune = True + elif o == 'status': + tp.status = True + else: + raise OptionValueError("Warning: %s is not a valid --tree option" % o) + parser.values.tree_printers.append(tp) + + opt_tree_help = "Print a dependency tree in various formats: %s." \ + % string.join(tree_options, ", ") + + op.add_option('--tree', + nargs=1, type="string", + dest="tree_printers", default=[], + action="callback", callback=opt_tree, + help=opt_tree_help, + metavar="OPTIONS") + + op.add_option('-u', '--up', '--search-up', + dest="climb_up", default=0, + action="store_const", const=1, + help="Search up directory tree for SConstruct, " + "build targets at or below current directory.") + + op.add_option('-U', + dest="climb_up", default=0, + action="store_const", const=3, + help="Search up directory tree for SConstruct, " + "build Default() targets from local SConscript.") + + def opt_version(option, opt, value, parser, version=version): + sys.stdout.write(version + '\n') + sys.exit(0) + op.add_option("-v", "--version", + action="callback", callback=opt_version, + help="Print the SCons version number and exit.") + + op.add_option('--warn', '--warning', + nargs=1, + dest="warn", default=None, + action="store", + help="Enable or disable warnings.", + metavar="WARNING-SPEC") + + op.add_option('-Y', '--repository', '--srcdir', + nargs=1, + dest="repository", default=[], + action="append", + help="Search REPOSITORY for source and target files.") + + # Options from Make and Cons classic that we do not yet support, + # but which we may support someday and whose (potential) meanings + # we don't want to change. These all get a "the -X option is not + # yet implemented" message and don't show up in the help output. + + op.add_option('-e', '--environment-overrides', + dest="environment_overrides", + action="callback", callback=opt_not_yet, + # help="Environment variables override makefiles." + help=SUPPRESS_HELP) + op.add_option('-l', '--load-average', '--max-load', + nargs=1, type="int", + dest="load_average", default=0, + action="callback", callback=opt_not_yet, + # action="store", + # help="Don't start multiple jobs unless load is below " + # "LOAD-AVERAGE." + help=SUPPRESS_HELP) + op.add_option('--list-actions', + dest="list_actions", + action="callback", callback=opt_not_yet, + # help="Don't build; list files and build actions." + help=SUPPRESS_HELP) + op.add_option('--list-derived', + dest="list_derived", + action="callback", callback=opt_not_yet, + # help="Don't build; list files that would be built." + help=SUPPRESS_HELP) + op.add_option('--list-where', + dest="list_where", + action="callback", callback=opt_not_yet, + # help="Don't build; list files and where defined." + help=SUPPRESS_HELP) + op.add_option('-o', '--old-file', '--assume-old', + nargs=1, type="string", + dest="old_file", default=[], + action="callback", callback=opt_not_yet, + # action="append", + # help = "Consider FILE to be old; don't rebuild it." + help=SUPPRESS_HELP) + op.add_option('--override', + nargs=1, type="string", + action="callback", callback=opt_not_yet, + dest="override", + # help="Override variables as specified in FILE." + help=SUPPRESS_HELP) + op.add_option('-p', + action="callback", callback=opt_not_yet, + dest="p", + # help="Print internal environments/objects." + help=SUPPRESS_HELP) + op.add_option('-r', '-R', '--no-builtin-rules', '--no-builtin-variables', + action="callback", callback=opt_not_yet, + dest="no_builtin_rules", + # help="Clear default environments and variables." + help=SUPPRESS_HELP) + op.add_option('-w', '--print-directory', + action="callback", callback=opt_not_yet, + dest="print_directory", + # help="Print the current directory." + help=SUPPRESS_HELP) + op.add_option('--no-print-directory', + action="callback", callback=opt_not_yet, + dest="no_print_directory", + # help="Turn off -w, even if it was turned on implicitly." + help=SUPPRESS_HELP) + op.add_option('--write-filenames', + nargs=1, type="string", + dest="write_filenames", + action="callback", callback=opt_not_yet, + # help="Write all filenames examined into FILE." + help=SUPPRESS_HELP) + op.add_option('-W', '--new-file', '--assume-new', '--what-if', + nargs=1, type="string", + dest="new_file", + action="callback", callback=opt_not_yet, + # help="Consider FILE to be changed." + help=SUPPRESS_HELP) + op.add_option('--warn-undefined-variables', + dest="warn_undefined_variables", + action="callback", callback=opt_not_yet, + # help="Warn when an undefined variable is referenced." + help=SUPPRESS_HELP) + + return op diff --git a/scons/scons-local-0.97/SCons/Script/SConscript.py b/scons/scons-local-0.97.0d20071212/SCons/Script/SConscript.py similarity index 97% rename from scons/scons-local-0.97/SCons/Script/SConscript.py rename to scons/scons-local-0.97.0d20071212/SCons/Script/SConscript.py index 3a1c1474a..42350d384 100644 --- a/scons/scons-local-0.97/SCons/Script/SConscript.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Script/SConscript.py @@ -28,7 +28,7 @@ files. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Script/SConscript.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Script/SConscript.py 2523 2007/12/12 09:37:41 knight" import SCons import SCons.Action @@ -65,6 +65,9 @@ import UserList #CommandLineTargets = [] #DefaultTargets = [] +class SConscriptReturn(Exception): + pass + launch_dir = os.path.abspath(os.curdir) GlobalDict = None @@ -125,6 +128,8 @@ class Frame: # make sure the sconscript attr is a Node. if isinstance(sconscript, SCons.Node.Node): self.sconscript = sconscript + elif sconscript == '-': + self.sconscript = None else: self.sconscript = fs.File(str(sconscript)) @@ -133,7 +138,7 @@ call_stack = [] # For documentation on the methods in this file, see the scons man-page -def Return(*vars): +def Return(*vars, **kw): retval = [] try: for var in vars: @@ -147,6 +152,11 @@ def Return(*vars): else: call_stack[-1].retval = tuple(retval) + stop = kw.get('stop', True) + + if stop: + raise SConscriptReturn + stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :) @@ -242,7 +252,10 @@ def _SConscript(fs, *files, **kw): except KeyError: pass try: - exec _file_ in call_stack[-1].globals + try: + exec _file_ in call_stack[-1].globals + except SConscriptReturn: + pass finally: if old_file is not None: call_stack[-1].globals.update({__file__:old_file}) @@ -469,7 +482,7 @@ class SConsEnvironment(SCons.Environment.Base): def GetOption(self, name): name = self.subst(name) - return SCons.Script.Main.ssoptions.get(name) + return SCons.Script.Main.GetOption(name) def Help(self, text): text = self.subst(text, raw=1) @@ -525,7 +538,7 @@ class SConsEnvironment(SCons.Environment.Base): def SetOption(self, name, value): name = self.subst(name) - SCons.Script.Main.ssoptions.set(name, value) + SCons.Script.Main.SetOption(name, value) # # diff --git a/scons/scons-local-0.97/SCons/Script/__init__.py b/scons/scons-local-0.97.0d20071212/SCons/Script/__init__.py similarity index 92% rename from scons/scons-local-0.97/SCons/Script/__init__.py rename to scons/scons-local-0.97.0d20071212/SCons/Script/__init__.py index 6ed9a7fdd..414798caa 100644 --- a/scons/scons-local-0.97/SCons/Script/__init__.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Script/__init__.py @@ -34,7 +34,7 @@ it goes here. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Script/__init__.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Script/__init__.py 2523 2007/12/12 09:37:41 knight" import time start_time = time.time() @@ -70,7 +70,7 @@ if "--debug=memoizer" in _args: # for it to be displayed or not after warnings are configured. import Main exc_type, exc_value, tb = sys.exc_info() - Main.delayed_warnings.append(exc_type, exc_value) + Main.delayed_warnings.append((exc_type, exc_value)) del _args import SCons.Action @@ -105,23 +105,28 @@ BuildTask = Main.BuildTask CleanTask = Main.CleanTask QuestionTask = Main.QuestionTask #PrintHelp = Main.PrintHelp -OptParser = Main.OptParser -SConscriptSettableOptions = Main.SConscriptSettableOptions +#SConscriptSettableOptions = Main.SConscriptSettableOptions -keep_going_on_error = Main.keep_going_on_error +AddOption = Main.AddOption +GetOption = Main.GetOption +SetOption = Main.SetOption +Progress = Main.Progress +GetBuildFailures = Main.GetBuildFailures + +#keep_going_on_error = Main.keep_going_on_error #print_dtree = Main.print_dtree -print_explanations = Main.print_explanations -print_includes = Main.print_includes -print_objects = Main.print_objects -print_time = Main.print_time +#print_explanations = Main.print_explanations +#print_includes = Main.print_includes +#print_objects = Main.print_objects +#print_time = Main.print_time #print_tree = Main.print_tree -memory_stats = Main.memory_stats -ignore_errors = Main.ignore_errors +#memory_stats = Main.memory_stats +#ignore_errors = Main.ignore_errors #sconscript_time = Main.sconscript_time #command_time = Main.command_time #exit_status = Main.exit_status #profiling = Main.profiling -repositories = Main.repositories +#repositories = Main.repositories # import SConscript @@ -131,12 +136,14 @@ call_stack = _SConscript.call_stack # Action = SCons.Action.Action +AddMethod = SCons.Util.AddMethod AllowSubstExceptions = SCons.Subst.SetAllowableExceptions BoolOption = SCons.Options.BoolOption Builder = SCons.Builder.Builder Configure = _SConscript.Configure EnumOption = SCons.Options.EnumOption Environment = SCons.Environment.Environment +#OptParser = SCons.SConsOptions.OptParser FindPathDirs = SCons.Scanner.FindPathDirs ListOption = SCons.Options.ListOption PackageOption = SCons.Options.PackageOption @@ -255,7 +262,7 @@ def HelpFunction(text): sconscript_reading = 0 # -def Options(files=None, args=ARGUMENTS): +def Options(files=[], args=ARGUMENTS): return SCons.Options.Options(files, args) # The list of global functions to add to the SConscript name space @@ -269,12 +276,10 @@ GlobalDefaultEnvironmentFunctions = [ 'Exit', 'Export', 'GetLaunchDir', - 'GetOption', 'Help', 'Import', #'SConscript', is handled separately, below. 'SConscriptChdir', - 'SetOption', # Methods from the Environment.Base class. 'AddPostAction', @@ -285,6 +290,7 @@ GlobalDefaultEnvironmentFunctions = [ 'CacheDir', 'Clean', #The Command() method is handled separately, below. + 'Decider', 'Depends', 'Dir', 'NoClean', @@ -293,8 +299,11 @@ GlobalDefaultEnvironmentFunctions = [ 'Execute', 'File', 'FindFile', + 'FindInstalledFiles', + 'FindSourceFiles', 'Flatten', 'GetBuildPath', + 'Glob', 'Ignore', 'Install', 'InstallAs', @@ -303,11 +312,13 @@ GlobalDefaultEnvironmentFunctions = [ 'ParseDepends', 'Precious', 'Repository', + 'Requires', 'SConsignFile', 'SideEffect', 'SourceCode', 'SourceSignatures', 'Split', + 'Tag', 'TargetSignatures', 'Value', ] @@ -337,6 +348,7 @@ GlobalDefaultBuilders = [ 'Tar', 'TypeLibrary', 'Zip', + 'Package', ] for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders: diff --git a/scons/scons-local-0.97.0d20071212/SCons/Sig.py b/scons/scons-local-0.97.0d20071212/SCons/Sig.py new file mode 100644 index 000000000..454f16460 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Sig.py @@ -0,0 +1,57 @@ +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Sig.py 2523 2007/12/12 09:37:41 knight" + +__doc__ = """Place-holder for the old SCons.Sig module hierarchy + +This is no longer used, but code out there (such as the NSIS module on +the SCons wiki) may try to import SCons.Sig. If so, we generate a warning +that points them to the line that caused the import, and don't die. + +If someone actually tried to use the sub-modules or functions within +the package (for example, SCons.Sig.MD5.signature()), then they'll still +get an AttributeError, but at least they'll know where to start looking. +""" + +import SCons.Util +import SCons.Warnings + +msg = 'The SCons.Sig module no longer exists.\n' \ + ' Remove the following "import SCons.Sig" line to eliminate this warning:' + +SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, msg) + +default_calc = None +default_module = None + +class MD5Null(SCons.Util.Null): + def __repr__(self): + return "MD5Null()" + +class TimeStampNull(SCons.Util.Null): + def __repr__(self): + return "TimeStampNull()" + +MD5 = MD5Null() +TimeStamp = TimeStampNull() diff --git a/scons/scons-local-0.97/SCons/Subst.py b/scons/scons-local-0.97.0d20071212/SCons/Subst.py similarity index 99% rename from scons/scons-local-0.97/SCons/Subst.py rename to scons/scons-local-0.97.0d20071212/SCons/Subst.py index a8b872984..bff27ae25 100644 --- a/scons/scons-local-0.97/SCons/Subst.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Subst.py @@ -27,7 +27,7 @@ SCons string substitution. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Subst.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Subst.py 2523 2007/12/12 09:37:41 knight" import SCons.compat diff --git a/scons/scons-local-0.97/SCons/Taskmaster.py b/scons/scons-local-0.97.0d20071212/SCons/Taskmaster.py similarity index 84% rename from scons/scons-local-0.97/SCons/Taskmaster.py rename to scons/scons-local-0.97.0d20071212/SCons/Taskmaster.py index f22d754f4..2fc4b08aa 100644 --- a/scons/scons-local-0.97/SCons/Taskmaster.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Taskmaster.py @@ -48,7 +48,7 @@ interface and the SCons build engine. There are two key classes here: target(s) that it decides need to be evaluated and/or built. """ -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Taskmaster.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Taskmaster.py 2523 2007/12/12 09:37:41 knight" import SCons.compat @@ -205,20 +205,40 @@ class Task: raise SCons.Errors.TaskmasterException(self.targets[0], sys.exc_info()) - def executed(self): + def executed_without_callbacks(self): """ - Called when the task has been successfully executed. - - This may have been a do-nothing operation (to preserve build - order), so we have to check the node's state before deciding - whether it was "built" or just "visited." + Called when the task has been successfully executed + and the Taskmaster instance doesn't want to call + the Node's callback methods. """ for t in self.targets: if t.get_state() == SCons.Node.executing: + for side_effect in t.side_effects: + side_effect.set_state(SCons.Node.no_state) + t.set_state(SCons.Node.executed) + + def executed_with_callbacks(self): + """ + Called when the task has been successfully executed and + the Taskmaster instance wants to call the Node's callback + methods. + + This may have been a do-nothing operation (to preserve build + order), so we must check the node's state before deciding whether + it was "built", in which case we call the appropriate Node method. + In any event, we always call "visited()", which will handle any + post-visit actions that must take place regardless of whether + or not the target was an actual built target or a source Node. + """ + for t in self.targets: + if t.get_state() == SCons.Node.executing: + for side_effect in t.side_effects: + side_effect.set_state(SCons.Node.no_state) t.set_state(SCons.Node.executed) t.built() - else: - t.visited() + t.visited() + + executed = executed_with_callbacks def failed(self): """ @@ -276,7 +296,9 @@ class Task: self.out_of_date = [] for t in self.targets: try: - is_up_to_date = t.disambiguate().current() + t.disambiguate().make_ready() + is_up_to_date = not t.has_builder() or \ + (not t.always_build and t.is_up_to_date()) except EnvironmentError, e: raise SCons.Errors.BuildError(node=t, errstr=e.strerror, filename=e.filename) if is_up_to_date: @@ -307,12 +329,14 @@ class Task: # back on the candidates list if the Node is also a waiting # parent. + targets = set(self.targets) + parents = {} - for t in self.targets: + for t in targets: for p in t.waiting_parents.keys(): parents[p] = parents.get(p, 0) + 1 - for t in self.targets: + for t in targets: for s in t.side_effects: if s.get_state() == SCons.Node.executing: s.set_state(SCons.Node.no_state) @@ -328,7 +352,7 @@ class Task: if p.ref_count == 0: self.tm.candidates.append(p) - for t in self.targets: + for t in targets: t.postprocess() # Exception handling subsystem. @@ -402,8 +426,9 @@ class Taskmaster: """ def __init__(self, targets=[], tasker=Task, order=None, trace=None): - self.top_targets = targets[:] - self.top_targets.reverse() + self.original_top = targets + self.top_targets_left = targets[:] + self.top_targets_left.reverse() self.candidates = [] self.tasker = tasker if not order: @@ -437,7 +462,7 @@ class Taskmaster: except IndexError: pass try: - node = self.top_targets.pop() + node = self.top_targets_left.pop() except IndexError: return None self.current_top = node @@ -510,7 +535,7 @@ class Taskmaster: node.set_state(SCons.Node.pending) try: - children = node.children() + children = node.children() + node.prerequisites except SystemExit: exc_value = sys.exc_info()[1] e = SCons.Errors.ExplicitExit(node, exc_value.code) @@ -535,16 +560,14 @@ class Taskmaster: c.sort() T.write(' children:\n %s\n ' % c) - childinfo = map(lambda N: (N.get_state(), - N.is_derived() or N.is_pseudo_derived(), - N), children) + childstate = map(lambda N: (N, N.get_state()), children) # Skip this node if any of its children have failed. This # catches the case where we're descending a top-level target # and one of our children failed while trying to be built # by a *previous* descent of an earlier top-level target. - failed_children = filter(lambda I: I[0] == SCons.Node.failed, - childinfo) + failed_children = filter(lambda I: I[1] == SCons.Node.failed, + childstate) if failed_children: node.set_state(SCons.Node.failed) if S: S.child_failed = S.child_failed + 1 @@ -555,76 +578,48 @@ class Taskmaster: continue # Detect dependency cycles: - pending_nodes = filter(lambda I: I[0] == SCons.Node.pending, childinfo) + pending_nodes = filter(lambda I: I[1] == SCons.Node.pending, childstate) if pending_nodes: for p in pending_nodes: - cycle = find_cycle([p[2], node]) + cycle = find_cycle([p[0], node]) if cycle: desc = "Dependency cycle: " + string.join(map(str, cycle), " -> ") if T: T.write(' dependency cycle\n') raise SCons.Errors.UserError, desc - # Select all of the dependencies that are derived targets - # (that is, children who have builders or are side effects). - derived_children = filter(lambda I: I[1], childinfo) - - not_started = filter(lambda I: not I[0], derived_children) - if not_started: - not_started = map(lambda I: I[2], not_started) - - # We're waiting on one more derived targets that have - # not yet started building. Add this node to the - # waiting_parents lists of those derived files so that - # when they've finished building, our implicit dependency - # list will get cleared and we'll re-scan the newly-built - # file(s) for updated implicit dependencies. - added = map(lambda n, P=node: n.add_to_waiting_parents(P), not_started) - node.ref_count = node.ref_count + reduce(operator.add, added, 0) - - # Now we add these derived targets to the candidates - # list so they can be examined and built. We have to - # add ourselves back to the list first, though, so we get - # a chance to re-scan and build after the dependencies. - # - # We reverse the order in which the children are added - # to the candidates stack so the order in which they're - # popped matches the order in which they show up in our - # children's list. This is more logical / efficient for - # builders with multiple targets, since the "primary" - # target will be examined first. - self.candidates.append(node) - not_started.reverse() - self.candidates.extend(self.order(not_started)) - - if S: S.not_started = S.not_started + 1 - if T: - c = map(str, not_started) - c.sort() - T.write(' waiting on unstarted children:\n %s\n' % c) - continue - - not_built = filter(lambda I: I[0] <= SCons.Node.executing, derived_children) + not_built = filter(lambda I: I[1] <= SCons.Node.executing, childstate) if not_built: - not_built = map(lambda I: I[2], not_built) - # We're waiting on one or more derived targets that have - # started building but not yet finished. Add this node - # to the waiting parents lists of those derived files - # so that when they've finished building, our implicit - # dependency list will get cleared and we'll re-scan the - # newly-built file(s) for updated implicit dependencies. - added = map(lambda n, P=node: n.add_to_waiting_parents(P), not_built) - node.ref_count = node.ref_count + reduce(operator.add, added, 0) + # not yet finished building. + + not_visited = filter(lambda I: not I[1], not_built) + if not_visited: + # Some of them haven't even been visited yet. + # Add them to the list so that on some next pass + # we can take a stab at evaluating them (or + # their children). + not_visited = map(lambda I: I[0], not_visited) + not_visited.reverse() + self.candidates.extend(self.order(not_visited)) + + n_b_nodes = map(lambda I: I[0], not_built) + + # Add this node to the waiting parents lists of anything + # we're waiting on, with a reference count so we can be + # put back on the list for re-evaluation when they've + # all finished. + map(lambda n, P=node: n.add_to_waiting_parents(P), n_b_nodes) + node.ref_count = len(set(n_b_nodes)) if S: S.not_built = S.not_built + 1 if T: - c = map(str, not_built) + c = map(str, n_b_nodes) c.sort() T.write(' waiting on unfinished children:\n %s\n' % c) continue - # Skip this node if it has side-effects that are currently being - # built themselves or waiting for something else being built. + # Skip this node if it has side-effects that are + # currently being built: side_effects = filter(lambda N: N.get_state() == SCons.Node.executing, node.side_effects) @@ -659,7 +654,7 @@ class Taskmaster: tlist = node.get_executor().targets - task = self.tasker(self, tlist, node is self.current_top, node) + task = self.tasker(self, tlist, node in self.original_top, node) try: task.make_ready() except KeyboardInterrupt: diff --git a/scons/scons-local-0.97/SCons/Tool/386asm.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/386asm.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/386asm.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/386asm.py index 2d3e04302..6a0bd4da3 100644 --- a/scons/scons-local-0.97/SCons/Tool/386asm.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/386asm.py @@ -32,7 +32,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/386asm.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/386asm.py 2523 2007/12/12 09:37:41 knight" from SCons.Tool.PharLapCommon import addPharLapPaths import SCons.Util diff --git a/scons/scons-local-0.97/SCons/Tool/BitKeeper.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/BitKeeper.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/BitKeeper.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/BitKeeper.py index 1dff9bab4..46dcc0051 100644 --- a/scons/scons-local-0.97/SCons/Tool/BitKeeper.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/BitKeeper.py @@ -32,7 +32,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/BitKeeper.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/BitKeeper.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Builder diff --git a/scons/scons-local-0.97/SCons/Tool/CVS.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/CVS.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/CVS.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/CVS.py index 5bd1a2919..519a6f590 100644 --- a/scons/scons-local-0.97/SCons/Tool/CVS.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/CVS.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/CVS.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/CVS.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Builder diff --git a/scons/scons-local-0.97/SCons/Tool/JavaCommon.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/JavaCommon.py similarity index 73% rename from scons/scons-local-0.97/SCons/Tool/JavaCommon.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/JavaCommon.py index 0faf52588..2aedd8559 100644 --- a/scons/scons-local-0.97/SCons/Tool/JavaCommon.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/JavaCommon.py @@ -27,7 +27,7 @@ Stuff for processing Java. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/JavaCommon.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/JavaCommon.py 2523 2007/12/12 09:37:41 knight" import os import os.path @@ -36,6 +36,8 @@ import string java_parsing = 1 +default_java_version = '1.4' + if java_parsing: # Parse Java files for class names. # @@ -53,18 +55,26 @@ if java_parsing: # array declarations "[]"; # semi-colons; # periods. - _reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.]|' + - r'[A-Za-z_][\w\.]*|/\*|\*/|\[\])') + _reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.\(\)]|' + + r'[A-Za-z_][\w\$\.]*|/\*|\*/|\[\])') class OuterState: """The initial state for parsing a Java file for classes, interfaces, and anonymous inner classes.""" - def __init__(self): + def __init__(self, version=default_java_version): + + if not version in ('1.1', '1.2', '1.3','1.4', '1.5', '1.6'): + msg = "Java version %s not supported" % version + raise NotImplementedError, msg + + self.version = version self.listClasses = [] self.listOutputs = [] self.stackBrackets = [] self.brackets = 0 self.nextAnon = 1 + self.stackAnonClassBrackets = [] + self.anonStacksStack = [[0]] self.package = None def trace(self): @@ -90,6 +100,7 @@ if java_parsing: try: return self.anonState except AttributeError: + self.outer_state = self ret = SkipState(1, AnonClassState(self)) self.anonState = ret return ret @@ -101,6 +112,9 @@ if java_parsing: ret = SkipState(1, self) self.skipState = ret return ret + + def __getAnonStack(self): + return self.anonStacksStack[-1] def openBracket(self): self.brackets = self.brackets + 1 @@ -111,7 +125,12 @@ if java_parsing: self.brackets == self.stackBrackets[-1]: self.listOutputs.append(string.join(self.listClasses, '$')) self.listClasses.pop() + self.anonStacksStack.pop() self.stackBrackets.pop() + if len(self.stackAnonClassBrackets) and \ + self.brackets == self.stackAnonClassBrackets[-1]: + self.__getAnonStack().pop() + self.stackAnonClassBrackets.pop() def parseToken(self, token): if token[:2] == '//': @@ -145,32 +164,56 @@ if java_parsing: def addAnonClass(self): """Add an anonymous inner class""" - clazz = self.listClasses[0] - self.listOutputs.append('%s$%d' % (clazz, self.nextAnon)) + if self.version in ('1.1', '1.2', '1.3', '1.4'): + clazz = self.listClasses[0] + self.listOutputs.append('%s$%d' % (clazz, self.nextAnon)) + elif self.version in ('1.5', '1.6'): + self.stackAnonClassBrackets.append(self.brackets) + className = [] + className.extend(self.listClasses) + self.__getAnonStack()[-1] = self.__getAnonStack()[-1] + 1 + for anon in self.__getAnonStack(): + className.append(str(anon)) + self.listOutputs.append(string.join(className, '$')) + self.nextAnon = self.nextAnon + 1 + self.__getAnonStack().append(0) def setPackage(self, package): self.package = package class AnonClassState: """A state that looks for anonymous inner classes.""" - def __init__(self, outer_state): + def __init__(self, old_state): # outer_state is always an instance of OuterState - self.outer_state = outer_state - self.tokens_to_find = 2 + self.outer_state = old_state.outer_state + self.old_state = old_state + self.brace_level = 0 def parseToken(self, token): - # This is an anonymous class if and only if the next - # non-whitespace token is a bracket - if token == '\n': + # This is an anonymous class if and only if the next + # non-whitespace token is a bracket. Everything between + # braces should be parsed as normal java code. + if token[:2] == '//': + return IgnoreState('\n', self) + elif token == '/*': + return IgnoreState('*/', self) + elif token == '\n': + return self + elif token == '(': + self.brace_level = self.brace_level + 1 + return self + if self.brace_level > 0: + if token == 'new': + # look further for anonymous inner class + return SkipState(1, AnonClassState(self)) + elif token in [ '"', "'" ]: + return IgnoreState(token, self) + elif token == ')': + self.brace_level = self.brace_level - 1 return self if token == '{': - self.outer_state.openBracket() self.outer_state.addAnonClass() - elif token == '}': - self.outer_state.closeBracket() - elif token in ['"', "'"]: - return IgnoreState(token, self) - return self.outer_state + return self.old_state.parseToken(token) class SkipState: """A state that will skip a specified number of tokens before @@ -194,6 +237,7 @@ if java_parsing: if token == '\n': return self self.outer_state.listClasses.append(token) + self.outer_state.anonStacksStack.append([0]) return self.outer_state class IgnoreState: @@ -217,15 +261,15 @@ if java_parsing: self.outer_state.setPackage(token) return self.outer_state - def parse_java_file(fn): - return parse_java(open(fn, 'r').read()) + def parse_java_file(fn, version=default_java_version): + return parse_java(open(fn, 'r').read(), version) - def parse_java(contents, trace=None): + def parse_java(contents, version=default_java_version, trace=None): """Parse a .java file and return a double of package directory, plus a list of .class files that compiling that .java file will produce""" package = None - initial = OuterState() + initial = OuterState(version) currstate = initial for token in _reToken.findall(contents): # The regex produces a bunch of groups, but only one will diff --git a/scons/scons-local-0.97/SCons/Tool/Perforce.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/Perforce.py similarity index 96% rename from scons/scons-local-0.97/SCons/Tool/Perforce.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/Perforce.py index 44fbe98a3..6a06f752e 100644 --- a/scons/scons-local-0.97/SCons/Tool/Perforce.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/Perforce.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/Perforce.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/Perforce.py 2523 2007/12/12 09:37:41 knight" import os diff --git a/scons/scons-local-0.97/SCons/Tool/PharLapCommon.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/PharLapCommon.py similarity index 97% rename from scons/scons-local-0.97/SCons/Tool/PharLapCommon.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/PharLapCommon.py index 2d095c1ab..d50446c69 100644 --- a/scons/scons-local-0.97/SCons/Tool/PharLapCommon.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/PharLapCommon.py @@ -29,7 +29,7 @@ Phar Lap ETS tool chain. Right now, this is linkloc and # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/PharLapCommon.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/PharLapCommon.py 2523 2007/12/12 09:37:41 knight" import os import os.path diff --git a/scons/scons-local-0.97/SCons/Tool/RCS.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/RCS.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/RCS.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/RCS.py index fb99eafac..73b8346c1 100644 --- a/scons/scons-local-0.97/SCons/Tool/RCS.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/RCS.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/RCS.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/RCS.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Builder diff --git a/scons/scons-local-0.97/SCons/Tool/SCCS.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/SCCS.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/SCCS.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/SCCS.py index 9600914cc..16564e98f 100644 --- a/scons/scons-local-0.97/SCons/Tool/SCCS.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/SCCS.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/SCCS.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/SCCS.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Builder diff --git a/scons/scons-local-0.97/SCons/Tool/Subversion.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/Subversion.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/Subversion.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/Subversion.py index f8050cb82..c8e8cf530 100644 --- a/scons/scons-local-0.97/SCons/Tool/Subversion.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/Subversion.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/Subversion.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/Subversion.py 2523 2007/12/12 09:37:41 knight" import os.path diff --git a/scons/scons-local-0.97/SCons/Tool/__init__.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/__init__.py similarity index 72% rename from scons/scons-local-0.97/SCons/Tool/__init__.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/__init__.py index aee8c93b3..17b7fd2d9 100644 --- a/scons/scons-local-0.97/SCons/Tool/__init__.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/__init__.py @@ -15,7 +15,7 @@ tool definition. # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation -# +# # 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 @@ -36,13 +36,14 @@ tool definition. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/__init__.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/__init__.py 2523 2007/12/12 09:37:41 knight" import imp import sys import SCons.Builder import SCons.Errors +import SCons.Node.FS import SCons.Scanner import SCons.Scanner.C import SCons.Scanner.D @@ -88,8 +89,11 @@ class Tool: module = self._tool_module() self.generate = module.generate self.exists = module.exists + if hasattr(module, 'options'): + self.options = module.options def _tool_module(self): + # TODO: Interchange zipimport with normal initilization for better error reporting oldpythonpath = sys.path sys.path = self.toolpath + sys.path @@ -102,6 +106,8 @@ class Tool: if file: file.close() except ImportError, e: + if str(e)!="No module named %s"%self.name: + raise SCons.Errors.EnvironmentError, e try: import zipimport except ImportError: @@ -130,6 +136,8 @@ class Tool: file.close() return module except ImportError, e: + if e!="No module named %s"%self.name: + raise SCons.Errors.EnvironmentError, e try: import zipimport importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] ) @@ -138,10 +146,10 @@ class Tool: return module except ImportError, e: m = "No tool named '%s': %s" % (self.name, e) - raise SCons.Errors.UserError, m + raise SCons.Errors.EnvironmentError, m except ImportError, e: m = "No tool named '%s': %s" % (self.name, e) - raise SCons.Errors.UserError, m + raise SCons.Errors.EnvironmentError, m def __call__(self, env, *args, **kw): if self.init_kw is not None: @@ -154,11 +162,24 @@ class Tool: else: kw = self.init_kw env.Append(TOOLS = [ self.name ]) + if hasattr(self, 'options'): + from SCons.Options import Options + if not env.has_key('options'): + from SCons.Script import ARGUMENTS + env['options']=Options(args=ARGUMENTS) + opts=env['options'] + + self.options(opts) + opts.Update(env) + apply(self.generate, ( env, ) + args, kw) def __str__(self): return self.name +########################################################################## +# Create common executable program / library / object builders + def createProgBuilder(env): """This is a utility function that creates the Program Builder in an Environment if it is not there already. @@ -316,7 +337,8 @@ def createCFileBuilders(env): emitter = {}, suffix = {None:'$CFILESUFFIX'}) env['BUILDERS']['CFile'] = c_file - env['CFILESUFFIX'] = '.c' + + env.SetDefault(CFILESUFFIX = '.c') try: cxx_file = env['BUILDERS']['CXXFile'] @@ -325,10 +347,130 @@ def createCFileBuilders(env): emitter = {}, suffix = {None:'$CXXFILESUFFIX'}) env['BUILDERS']['CXXFile'] = cxx_file - env['CXXFILESUFFIX'] = '.cc' + env.SetDefault(CXXFILESUFFIX = '.cc') return (c_file, cxx_file) +########################################################################## +# Create common Java builders + +def CreateJarBuilder(env): + try: + java_jar = env['BUILDERS']['Jar'] + except KeyError: + fs = SCons.Node.FS.get_default_fs() + jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR') + java_jar = SCons.Builder.Builder(action = jar_com, + suffix = '$JARSUFFIX', + src_suffix = '$JAVACLASSSUFIX', + src_builder = 'JavaClassFile', + source_factory = fs.Entry) + env['BUILDERS']['Jar'] = java_jar + return java_jar + +def CreateJavaHBuilder(env): + try: + java_javah = env['BUILDERS']['JavaH'] + except KeyError: + fs = SCons.Node.FS.get_default_fs() + java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR') + java_javah = SCons.Builder.Builder(action = java_javah_com, + src_suffix = '$JAVACLASSSUFFIX', + target_factory = fs.Entry, + source_factory = fs.File, + src_builder = 'JavaClassFile') + env['BUILDERS']['JavaH'] = java_javah + return java_javah + +def CreateJavaClassFileBuilder(env): + try: + java_class_file = env['BUILDERS']['JavaClassFile'] + except KeyError: + fs = SCons.Node.FS.get_default_fs() + javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') + java_class_file = SCons.Builder.Builder(action = javac_com, + emitter = {}, + #suffix = '$JAVACLASSSUFFIX', + src_suffix = '$JAVASUFFIX', + src_builder = ['JavaFile'], + target_factory = fs.Entry, + source_factory = fs.File) + env['BUILDERS']['JavaClassFile'] = java_class_file + return java_class_file + +def CreateJavaClassDirBuilder(env): + try: + java_class_dir = env['BUILDERS']['JavaClassDir'] + except KeyError: + fs = SCons.Node.FS.get_default_fs() + javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') + java_class_dir = SCons.Builder.Builder(action = javac_com, + emitter = {}, + target_factory = fs.Dir, + source_factory = fs.Dir) + env['BUILDERS']['JavaClassDir'] = java_class_dir + return java_class_dir + +def CreateJavaFileBuilder(env): + try: + java_file = env['BUILDERS']['JavaFile'] + except KeyError: + java_file = SCons.Builder.Builder(action = {}, + emitter = {}, + suffix = {None:'$JAVASUFFIX'}) + env['BUILDERS']['JavaFile'] = java_file + env['JAVASUFFIX'] = '.java' + return java_file + +class ToolInitializer: + """ + A class for delayed initialization of Tools modules. + + This is intended to be added to a construction environment in + place of the method(s) normally called for a Builder (env.Object, + env.StaticObject, etc.). When called, it searches the specified + list of tools, applies the first one that exists to the construction + environment, and calls whatever builder was (presumably) added the + construction environment in our place. + """ + def __init__(self, name, tools): + """ + Note: we store the tool name as __name__ so it can be used by + the class that attaches this to a construction environment. + """ + self.__name__ = name + if not SCons.Util.is_List(tools): + tools = [tools] + self.tools = tools + def __call__(self, env, *args, **kw): + for t in self.tools: + tool = SCons.Tool.Tool(t) + if tool.exists(env): + env.Tool(tool) + break + + builder = getattr(env, self.__name__) + if builder is self: + # There was no Builder added, which means no valid Tool + # for this name was found (or possibly there's a mismatch + # between the name we were called by and the Builder name + # added by the Tool module). + # + # (Eventually this is where we'll put a more informative + # error message about the inability to find that tool + # as cut over more Builders+Tools to using this. + return [], [] + + # Let the construction environment remove the added method + # so we no longer copy and re-bind this method when the + # construction environment gets cloned. + env.RemoveMethod(self) + return apply(builder, args, kw) + +def Initializers(env): + env.AddMethod(ToolInitializer('Install', 'install')) + env.AddMethod(ToolInitializer('InstallAs', 'install')) + def FindTool(tools, env): for tool in tools: t = Tool(tool) @@ -340,7 +482,7 @@ def FindAllTools(tools, env): def ToolExists(tool, env=env): return Tool(tool).exists(env) return filter (ToolExists, tools) - + def tool_list(platform, env): # XXX this logic about what tool to prefer on which platform @@ -414,11 +556,11 @@ def tool_list(platform, env): ars = ['ar', 'mslib'] c_compiler = FindTool(c_compilers, env) or c_compilers[0] - + # XXX this logic about what tool provides what should somehow be # moved into the tool files themselves. if c_compiler and c_compiler == 'mingw': - # MinGW contains a linker, C compiler, C++ compiler, + # MinGW contains a linker, C compiler, C++ compiler, # Fortran compiler, archiver and assembler: cxx_compiler = None linker = None @@ -438,6 +580,7 @@ def tool_list(platform, env): other_tools = FindAllTools(['BitKeeper', 'CVS', 'dmd', + 'filesystem', 'dvipdf', 'dvips', 'gs', 'jar', 'javac', 'javah', 'latex', 'lex', @@ -448,11 +591,11 @@ def tool_list(platform, env): # 'Subversion', 'swig', 'tar', 'tex', - 'yacc', 'zip'], + 'yacc', 'zip', 'rpm', 'wix'], env) tools = ([linker, c_compiler, cxx_compiler, fortran_compiler, assembler, ar] + other_tools) - + return filter(lambda x: x, tools) diff --git a/scons/scons-local-0.97/SCons/Tool/aixc++.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/aixc++.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/aixc++.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/aixc++.py index b79f2282a..380a9b951 100644 --- a/scons/scons-local-0.97/SCons/Tool/aixc++.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/aixc++.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixc++.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/aixc++.py 2523 2007/12/12 09:37:41 knight" import os.path diff --git a/scons/scons-local-0.97/SCons/Tool/aixcc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/aixcc.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/aixcc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/aixcc.py index 5fc8cf244..2e43faf17 100644 --- a/scons/scons-local-0.97/SCons/Tool/aixcc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/aixcc.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixcc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/aixcc.py 2523 2007/12/12 09:37:41 knight" import os.path diff --git a/scons/scons-local-0.97/SCons/Tool/aixf77.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/aixf77.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/aixf77.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/aixf77.py index f264c07be..4b3567725 100644 --- a/scons/scons-local-0.97/SCons/Tool/aixf77.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/aixf77.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixf77.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/aixf77.py 2523 2007/12/12 09:37:41 knight" import os.path diff --git a/scons/scons-local-0.97/SCons/Tool/aixlink.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/aixlink.py similarity index 93% rename from scons/scons-local-0.97/SCons/Tool/aixlink.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/aixlink.py index eba698992..858121cf7 100644 --- a/scons/scons-local-0.97/SCons/Tool/aixlink.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/aixlink.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/aixlink.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/aixlink.py 2523 2007/12/12 09:37:41 knight" import os import os.path @@ -44,7 +44,7 @@ cplusplus = __import__('c++', globals(), locals(), []) def smart_linkflags(source, target, env, for_signature): if cplusplus.iscplusplus(source): - build_dir = env.subst('$BUILDDIR') + build_dir = env.subst('$BUILDDIR', target=target, source=source) if build_dir: return '-qtempinc=' + os.path.join(build_dir, 'tempinc') return '' diff --git a/scons/scons-local-0.97/SCons/Tool/applelink.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/applelink.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/applelink.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/applelink.py index b664e19ab..a63fcdf3f 100644 --- a/scons/scons-local-0.97/SCons/Tool/applelink.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/applelink.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/applelink.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/applelink.py 2523 2007/12/12 09:37:41 knight" import SCons.Util diff --git a/scons/scons-local-0.97/SCons/Tool/ar.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/ar.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/ar.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/ar.py index 5c42471e2..65bec7fa7 100644 --- a/scons/scons-local-0.97/SCons/Tool/ar.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/ar.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/ar.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/ar.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Tool diff --git a/scons/scons-local-0.97/SCons/Tool/as.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/as.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/as.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/as.py index 15aaa232a..25fd5dbf1 100644 --- a/scons/scons-local-0.97/SCons/Tool/as.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/as.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/as.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/as.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Tool diff --git a/scons/scons-local-0.97/SCons/Tool/bcc32.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/bcc32.py similarity index 88% rename from scons/scons-local-0.97/SCons/Tool/bcc32.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/bcc32.py index 030381b62..5a40c09a6 100644 --- a/scons/scons-local-0.97/SCons/Tool/bcc32.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/bcc32.py @@ -27,7 +27,7 @@ XXX # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/bcc32.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/bcc32.py 2523 2007/12/12 09:37:41 knight" import os import os.path @@ -42,12 +42,7 @@ def findIt(program, env): borwin = env.WhereIs(program) or SCons.Util.WhereIs(program) if borwin: dir = os.path.dirname(borwin) - path = env['ENV'].get('PATH', []) - if not path: - path = [] - if SCons.Util.is_String(path): - path = string.split(path, os.pathsep) - env['ENV']['PATH'] = string.join([dir]+path, os.pathsep) + env.PrependENVPath('PATH', dir) return borwin def generate(env): diff --git a/scons/scons-local-0.97/SCons/Tool/c++.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/c++.py similarity index 96% rename from scons/scons-local-0.97/SCons/Tool/c++.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/c++.py index f1e4e1d25..6b9f0a92b 100644 --- a/scons/scons-local-0.97/SCons/Tool/c++.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/c++.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/c++.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/c++.py 2523 2007/12/12 09:37:41 knight" import os.path diff --git a/scons/scons-local-0.97/SCons/Tool/cc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/cc.py similarity index 85% rename from scons/scons-local-0.97/SCons/Tool/cc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/cc.py index cc7aa7bef..e4e87c7e5 100644 --- a/scons/scons-local-0.97/SCons/Tool/cc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/cc.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/cc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/cc.py 2523 2007/12/12 09:37:41 knight" import SCons.Tool import SCons.Defaults @@ -73,6 +73,18 @@ def generate(env): shared_obj.add_action(suffix, SCons.Defaults.ShCAction) static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) +#<<<<<<< .working +# +# env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS' +# # It's a hack to test for darwin here, but the alternative of creating +# # an applecc.py to contain this seems overkill. Maybe someday the Apple +# # platform will require more setup and this logic will be moved. +# env['FRAMEWORKS'] = SCons.Util.CLVar('') +# env['FRAMEWORKPATH'] = SCons.Util.CLVar('') +# if env['PLATFORM'] == 'darwin': +# env['_CCCOMCOM'] = env['_CCCOMCOM'] + ' $_FRAMEWORKPATH' +#======= +#>>>>>>> .merge-right.r1907 add_common_cc_variables(env) diff --git a/scons/scons-local-0.97/SCons/Tool/cvf.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/cvf.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/cvf.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/cvf.py index edb2a72c1..689038ea1 100644 --- a/scons/scons-local-0.97/SCons/Tool/cvf.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/cvf.py @@ -27,7 +27,7 @@ Tool-specific initialization for the Compaq Visual Fortran compiler. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/cvf.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/cvf.py 2523 2007/12/12 09:37:41 knight" import fortran diff --git a/scons/scons-local-0.97/SCons/Tool/default.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/default.py similarity index 92% rename from scons/scons-local-0.97/SCons/Tool/default.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/default.py index 0869dd999..182aa947d 100644 --- a/scons/scons-local-0.97/SCons/Tool/default.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/default.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/default.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/default.py 2523 2007/12/12 09:37:41 knight" import SCons.Tool diff --git a/scons/scons-local-0.97/SCons/Tool/dmd.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/dmd.py similarity index 98% rename from scons/scons-local-0.97/SCons/Tool/dmd.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/dmd.py index 27c6769e6..8ef365189 100644 --- a/scons/scons-local-0.97/SCons/Tool/dmd.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/dmd.py @@ -53,7 +53,7 @@ Lib tool variables: # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/dmd.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/dmd.py 2523 2007/12/12 09:37:41 knight" import os import string diff --git a/scons/scons-local-0.97/SCons/Tool/dvi.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/dvi.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/dvi.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/dvi.py index 420a31dc0..a4eff52c0 100644 --- a/scons/scons-local-0.97/SCons/Tool/dvi.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/dvi.py @@ -27,7 +27,7 @@ Common DVI Builder definition for various other Tool modules that use it. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/dvi.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/dvi.py 2523 2007/12/12 09:37:41 knight" import SCons.Builder import SCons.Tool diff --git a/scons/scons-local-0.97/SCons/Tool/dvipdf.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/dvipdf.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/dvipdf.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/dvipdf.py index a4b850c83..eae34b0c7 100644 --- a/scons/scons-local-0.97/SCons/Tool/dvipdf.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/dvipdf.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/dvipdf.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/dvipdf.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Defaults diff --git a/scons/scons-local-0.97/SCons/Tool/dvips.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/dvips.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/dvips.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/dvips.py index ebd786caf..3d30f0cb7 100644 --- a/scons/scons-local-0.97/SCons/Tool/dvips.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/dvips.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/dvips.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/dvips.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Builder diff --git a/scons/scons-local-0.97/SCons/Tool/f77.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/f77.py similarity index 97% rename from scons/scons-local-0.97/SCons/Tool/f77.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/f77.py index c79245289..aff2681ff 100644 --- a/scons/scons-local-0.97/SCons/Tool/f77.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/f77.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/f77.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/f77.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Scanner.Fortran diff --git a/scons/scons-local-0.97/SCons/Tool/f90.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/f90.py similarity index 97% rename from scons/scons-local-0.97/SCons/Tool/f90.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/f90.py index 8fea76094..d4a154c3d 100644 --- a/scons/scons-local-0.97/SCons/Tool/f90.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/f90.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/f90.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/f90.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Scanner.Fortran diff --git a/scons/scons-local-0.97/SCons/Tool/f95.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/f95.py similarity index 97% rename from scons/scons-local-0.97/SCons/Tool/f95.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/f95.py index 4a598fc29..3a3e3e472 100644 --- a/scons/scons-local-0.97/SCons/Tool/f95.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/f95.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/f95.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/f95.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Tool diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/filesystem.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/filesystem.py new file mode 100644 index 000000000..ced41f86e --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/filesystem.py @@ -0,0 +1,92 @@ +"""SCons.Tool.filesystem + +Tool-specific initialization for the filesystem tools. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/filesystem.py 2523 2007/12/12 09:37:41 knight" + +import SCons +from SCons.Tool.install import copyFunc + +copyToBuilder, copyAsBuilder = None, None + +def copyto_emitter(target, source, env): + """ changes the path of the source to be under the target (which + are assumed to be directories. + """ + n_target = [] + + for t in target: + n_target = n_target + map( lambda s, t=t: t.File( str( s ) ), source ) + + return (n_target, source) + +def copy_action_func(target, source, env): + assert( len(target) == len(source) ), "\ntarget: %s\nsource: %s" %(map(str, target),map(str, source)) + + for t, s in zip(target, source): + if copyFunc(t.get_path(), s.get_path(), env): + return 1 + + return 0 + +def copy_action_str(target, source, env): + return env.subst_target_source(env['COPYSTR'], 0, target, source) + +copy_action = SCons.Action.Action( copy_action_func, copy_action_str ) + +def generate(env): + try: + env['BUILDERS']['CopyTo'] + env['BUILDERS']['CopyAs'] + except KeyError, e: + global copyToBuilder + if copyToBuilder is None: + copyToBuilder = SCons.Builder.Builder( + action = copy_action, + target_factory = env.fs.Dir, + source_factory = env.fs.Entry, + multi = 1, + emitter = [ copyto_emitter, ] ) + + global copyAsBuilder + if copyAsBuilder is None: + copyAsBuilder = SCons.Builder.Builder( + action = copy_action, + target_factory = env.fs.Entry, + source_factory = env.fs.Entry ) + + env['BUILDERS']['CopyTo'] = copyToBuilder + env['BUILDERS']['CopyAs'] = copyAsBuilder + + env['COPYSTR'] = 'Copy file(s): "$SOURCES" to "$TARGETS"' + +def exists(env): + return 1 diff --git a/scons/scons-local-0.97/SCons/Tool/fortran.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/fortran.py similarity index 97% rename from scons/scons-local-0.97/SCons/Tool/fortran.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/fortran.py index 0e557e329..33c135df2 100644 --- a/scons/scons-local-0.97/SCons/Tool/fortran.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/fortran.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/fortran.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/fortran.py 2523 2007/12/12 09:37:41 knight" import re import string @@ -78,8 +78,8 @@ def _fortranEmitter(target, source, env): # Remove unique items from the list modules = SCons.Util.unique(modules) # Convert module name to a .mod filename - suffix = env.subst('$FORTRANMODSUFFIX') - moddir = env.subst('$FORTRANMODDIR') + suffix = env.subst('$FORTRANMODSUFFIX', target=target, source=source) + moddir = env.subst('$FORTRANMODDIR', target=target, source=source) modules = map(lambda x, s=suffix: string.lower(x) + s, modules) for m in modules: target.append(env.fs.File(m, moddir)) diff --git a/scons/scons-local-0.97/SCons/Tool/g++.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/g++.py similarity index 96% rename from scons/scons-local-0.97/SCons/Tool/g++.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/g++.py index d4459756a..e3519a142 100644 --- a/scons/scons-local-0.97/SCons/Tool/g++.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/g++.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/g++.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/g++.py 2523 2007/12/12 09:37:41 knight" import os.path import re diff --git a/scons/scons-local-0.97/SCons/Tool/g77.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/g77.py similarity index 93% rename from scons/scons-local-0.97/SCons/Tool/g77.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/g77.py index 66f780e84..5afcc5fe4 100644 --- a/scons/scons-local-0.97/SCons/Tool/g77.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/g77.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/g77.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/g77.py 2523 2007/12/12 09:37:41 knight" import f77 diff --git a/scons/scons-local-0.97/SCons/Tool/gas.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/gas.py similarity index 93% rename from scons/scons-local-0.97/SCons/Tool/gas.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/gas.py index d16a249a8..e080c5e33 100644 --- a/scons/scons-local-0.97/SCons/Tool/gas.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/gas.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/gas.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/gas.py 2523 2007/12/12 09:37:41 knight" as_module = __import__('as', globals(), locals(), []) diff --git a/scons/scons-local-0.97/SCons/Tool/gcc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/gcc.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/gcc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/gcc.py index e14840617..81c137411 100644 --- a/scons/scons-local-0.97/SCons/Tool/gcc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/gcc.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/gcc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/gcc.py 2523 2007/12/12 09:37:41 knight" import SCons.Util diff --git a/scons/scons-local-0.97/SCons/Tool/gnulink.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/gnulink.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/gnulink.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/gnulink.py index 26c30ba37..12d1a1728 100644 --- a/scons/scons-local-0.97/SCons/Tool/gnulink.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/gnulink.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/gnulink.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/gnulink.py 2523 2007/12/12 09:37:41 knight" import SCons.Util diff --git a/scons/scons-local-0.97/SCons/Tool/gs.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/gs.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/gs.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/gs.py index 0d83eab90..7e7325c32 100644 --- a/scons/scons-local-0.97/SCons/Tool/gs.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/gs.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/gs.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/gs.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Platform diff --git a/scons/scons-local-0.97/SCons/Tool/hpc++.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/hpc++.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/hpc++.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/hpc++.py index 2e2374806..15eee3b3d 100644 --- a/scons/scons-local-0.97/SCons/Tool/hpc++.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/hpc++.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/hpc++.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/hpc++.py 2523 2007/12/12 09:37:41 knight" import os.path import string diff --git a/scons/scons-local-0.97/SCons/Tool/hpcc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/hpcc.py similarity index 93% rename from scons/scons-local-0.97/SCons/Tool/hpcc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/hpcc.py index 1970e483f..4b493e487 100644 --- a/scons/scons-local-0.97/SCons/Tool/hpcc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/hpcc.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/hpcc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/hpcc.py 2523 2007/12/12 09:37:41 knight" import SCons.Util diff --git a/scons/scons-local-0.97/SCons/Tool/hplink.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/hplink.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/hplink.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/hplink.py index f36bc156e..5a4815549 100644 --- a/scons/scons-local-0.97/SCons/Tool/hplink.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/hplink.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/hplink.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/hplink.py 2523 2007/12/12 09:37:41 knight" import os import os.path diff --git a/scons/scons-local-0.97/SCons/Tool/icc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/icc.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/icc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/icc.py index 2a9813153..5b1e1fd40 100644 --- a/scons/scons-local-0.97/SCons/Tool/icc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/icc.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/icc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/icc.py 2523 2007/12/12 09:37:41 knight" import cc diff --git a/scons/scons-local-0.97/SCons/Tool/icl.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/icl.py similarity index 93% rename from scons/scons-local-0.97/SCons/Tool/icl.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/icl.py index 77a47607c..9ef0b120f 100644 --- a/scons/scons-local-0.97/SCons/Tool/icl.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/icl.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/icl.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/icl.py 2523 2007/12/12 09:37:41 knight" import SCons.Tool.intelc diff --git a/scons/scons-local-0.97/SCons/Tool/ifl.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/ifl.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/ifl.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/ifl.py index a1dfe0710..d180d7fa5 100644 --- a/scons/scons-local-0.97/SCons/Tool/ifl.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/ifl.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/ifl.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/ifl.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults diff --git a/scons/scons-local-0.97/SCons/Tool/ifort.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/ifort.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/ifort.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/ifort.py index 099e4e5f2..d89855bb2 100644 --- a/scons/scons-local-0.97/SCons/Tool/ifort.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/ifort.py @@ -32,7 +32,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/ifort.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/ifort.py 2523 2007/12/12 09:37:41 knight" import string diff --git a/scons/scons-local-0.97/SCons/Tool/ilink.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/ilink.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/ilink.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/ilink.py index a9279c475..faf3ece79 100644 --- a/scons/scons-local-0.97/SCons/Tool/ilink.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/ilink.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/ilink.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/ilink.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Tool diff --git a/scons/scons-local-0.97/SCons/Tool/ilink32.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/ilink32.py similarity index 93% rename from scons/scons-local-0.97/SCons/Tool/ilink32.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/ilink32.py index 2247bccd3..b2cfe4de8 100644 --- a/scons/scons-local-0.97/SCons/Tool/ilink32.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/ilink32.py @@ -27,7 +27,7 @@ XXX # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/ilink32.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/ilink32.py 2523 2007/12/12 09:37:41 knight" import SCons.Tool import SCons.Tool.bcc32 diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/install.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/install.py new file mode 100644 index 000000000..1c7ff2e66 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/install.py @@ -0,0 +1,226 @@ +"""SCons.Tool.install + +Tool-specific initialization for the install tool. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/install.py 2523 2007/12/12 09:37:41 knight" + +import os +import shutil +import stat + +import SCons.Action +from SCons.Util import make_path_relative + +# +# We keep track of *all* installed files. +_INSTALLED_FILES = [] +_UNIQUE_INSTALLED_FILES = None + +# +# Functions doing the actual work of the Install Builder. +# +def copyFunc(dest, source, env): + """Install a source file or directory into a destination by copying, + (including copying permission/mode bits).""" + + if os.path.isdir(source): + if os.path.exists(dest): + if not os.path.isdir(dest): + raise SCons.Errors.UserError, "cannot overwrite non-directory `%s' with a directory `%s'" % (str(dest), str(source)) + else: + parent = os.path.split(dest)[0] + if not os.path.exists(parent): + os.makedirs(parent) + shutil.copytree(source, dest) + else: + shutil.copy2(source, dest) + st = os.stat(source) + os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) + + return 0 + +def installFunc(target, source, env): + """Install a source file into a target using the function specified + as the INSTALL construction variable.""" + try: + install = env['INSTALL'] + except KeyError: + raise SCons.Errors.UserError('Missing INSTALL construction variable.') + + assert( len(target)==len(source) ) + for t,s in zip(target,source): + if install(t.get_path(),s.get_path(),env): + return 1 + + return 0 + +def stringFunc(target, source, env): + installstr = env.get('INSTALLSTR') + if installstr: + return env.subst_target_source(installstr, 0, target, source) + target = str(target[0]) + source = str(source[0]) + if os.path.isdir(source): + type = 'directory' + else: + type = 'file' + return 'Install %s: "%s" as "%s"' % (type, source, target) + +# +# Emitter functions +# +def add_targets_to_INSTALLED_FILES(target, source, env): + """ an emitter that adds all target files to the list stored in the + _INSTALLED_FILES global variable. This way all installed files of one + scons call will be collected. + """ + global _INSTALLED_FILES, _UNIQUE_INSTALLED_FILES + _INSTALLED_FILES.extend(target) + _UNIQUE_INSTALLED_FILES = None + return (target, source) + +class DESTDIR_factory: + """ a node factory, where all files will be relative to the dir supplied + in the constructor. + """ + def __init__(self, env, dir): + self.env = env + self.dir = env.arg2nodes( dir, env.fs.Dir )[0] + + def Entry(self, name): + name = make_path_relative(name) + return self.dir.Entry(name) + + def Dir(self, name): + name = make_path_relative(name) + return self.dir.Dir(name) + +# +# The Builder Definition +# +install_action = SCons.Action.Action(installFunc, stringFunc) +installas_action = SCons.Action.Action(installFunc, stringFunc) + +BaseInstallBuilder = None + +def InstallBuilderWrapper(env, target, source, dir=None): + if target and dir: + raise SCons.Errors.UserError, "Both target and dir defined for Install(), only one may be defined." + if not dir: + dir=target + + import SCons.Script + install_sandbox = SCons.Script.GetOption('install_sandbox') + if install_sandbox: + target_factory = DESTDIR_factory(env, install_sandbox) + else: + target_factory = env.fs + + try: + dnodes = env.arg2nodes(dir, target_factory.Dir) + except TypeError: + raise SCons.Errors.UserError, "Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" % str(dir) + sources = env.arg2nodes(source, env.fs.Entry) + tgt = [] + for dnode in dnodes: + for src in sources: + # Prepend './' so the lookup doesn't interpret an initial + # '#' on the file name portion as meaning the Node should + # be relative to the top-level SConstruct directory. + target = env.fs.Entry('.'+os.sep+src.name, dnode) + tgt.extend(BaseInstallBuilder(env, target, src)) + return tgt + +def InstallAsBuilderWrapper(env, target, source): + result = [] + for src, tgt in map(lambda x, y: (x, y), source, target): + result.extend(BaseInstallBuilder(env, tgt, src)) + return result + +added = None + +def generate(env): + + from SCons.Script import AddOption, GetOption + global added + if not added: + added = 1 + AddOption('--install-sandbox', + dest='install_sandbox', + type="string", + action="store", + help='A directory under which all installed files will be placed.') + + global BaseInstallBuilder + if BaseInstallBuilder is None: + install_sandbox = GetOption('install_sandbox') + if install_sandbox: + target_factory = DESTDIR_factory(env, install_sandbox) + else: + target_factory = env.fs + + BaseInstallBuilder = SCons.Builder.Builder( + action = install_action, + target_factory = target_factory.Entry, + source_factory = env.fs.Entry, + multi = 1, + emitter = [ add_targets_to_INSTALLED_FILES, ], + name = 'InstallBuilder') + + try: + env['BUILDERS']['Install'] + except KeyError, e: + env['BUILDERS']['Install'] = InstallBuilderWrapper + + try: + env['BUILDERS']['InstallAs'] + except KeyError, e: + env['BUILDERS']['InstallAs'] = InstallAsBuilderWrapper + + # We'd like to initialize this doing something like the following, + # but there isn't yet support for a ${SOURCE.type} expansion that + # will print "file" or "directory" depending on what's being + # installed. For now we punt by not initializing it, and letting + # the stringFunc() that we put in the action fall back to the + # hand-crafted default string if it's not set. + # + #try: + # env['INSTALLSTR'] + #except KeyError: + # env['INSTALLSTR'] = 'Install ${SOURCE.type}: "$SOURCES" as "$TARGETS"' + + try: + env['INSTALL'] + except KeyError: + env['INSTALL'] = copyFunc + +def exists(env): + return 1 diff --git a/scons/scons-local-0.97/SCons/Tool/intelc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/intelc.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/intelc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/intelc.py index 4b243b8bd..7ecd70b55 100644 --- a/scons/scons-local-0.97/SCons/Tool/intelc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/intelc.py @@ -32,11 +32,14 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/intelc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/intelc.py 2523 2007/12/12 09:37:41 knight" import math, sys, os.path, glob, string, re is_windows = sys.platform == 'win32' +is_win64 = is_windows and (os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' or + (os.environ.has_key('PROCESSOR_ARCHITEW6432') and + os.environ['PROCESSOR_ARCHITEW6432'] == 'AMD64')) is_linux = sys.platform == 'linux2' if is_windows: @@ -138,7 +141,10 @@ def get_intel_registry_value(valuename, version=None, abi=None): Return a value from the Intel compiler registry tree. (Windows only) """ # Open the key: - K = 'Software\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper() + if is_win64: + K = 'Software\\Wow6432Node\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper() + else: + K = 'Software\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper() try: k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K) except SCons.Util.RegError: @@ -160,7 +166,10 @@ def get_all_compiler_versions(): """ versions=[] if is_windows: - keyname = 'Software\\Intel\\Compilers\\C++' + if is_win64: + keyname = 'Software\\WoW6432Node\\Intel\\Compilers\\C++' + else: + keyname = 'Software\\Intel\\Compilers\\C++' try: k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, keyname) @@ -178,7 +187,7 @@ def get_all_compiler_versions(): # than uninstalling properly), so the registry values # are still there. ok = False - for try_abi in ('IA32', 'IA32e', 'IA64'): + for try_abi in ('IA32', 'IA32e', 'IA64', 'EM64T'): try: d = get_intel_registry_value('ProductDir', subkey, try_abi) except MissingRegistryError: @@ -212,6 +221,7 @@ def get_intel_compiler_top(version, abi): The compiler will be in /bin/icl.exe (icc on linux), the include dir is /include, etc. """ + if is_windows: if not SCons.Util.can_read_reg: raise NoRegistryModuleError, "No Windows registry module was found" @@ -282,8 +292,10 @@ def generate(env, version=None, abi=None, topdir=None, verbose=0): else: abi = 'ia32' else: - # XXX: how would we do the same test on Windows? - abi = "ia32" + if is_win64: + abi = 'em64t' + else: + abi = 'ia32' if version and not topdir: try: diff --git a/scons/scons-local-0.97/SCons/Tool/jar.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/jar.py similarity index 82% rename from scons/scons-local-0.97/SCons/Tool/jar.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/jar.py index 61077dcc9..dd2d6f125 100644 --- a/scons/scons-local-0.97/SCons/Tool/jar.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/jar.py @@ -31,16 +31,14 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/jar.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/jar.py 2523 2007/12/12 09:37:41 knight" -import SCons.Action -import SCons.Builder import SCons.Subst import SCons.Util def jarSources(target, source, env, for_signature): """Only include sources that are not a manifest file.""" - jarchdir = env.subst('$JARCHDIR') + jarchdir = env.subst('$JARCHDIR', target=target, source=source) if jarchdir: jarchdir = env.fs.Dir(jarchdir) result = [] @@ -67,7 +65,7 @@ def jarManifest(target, source, env, for_signature): def jarFlags(target, source, env, for_signature): """If we have a manifest, make sure that the 'm' flag is specified.""" - jarflags = env.subst('$JARFLAGS') + jarflags = env.subst('$JARFLAGS', target=target, source=source) for src in source: contents = src.get_contents() if contents[:16] == "Manifest-Version": @@ -76,25 +74,17 @@ def jarFlags(target, source, env, for_signature): break return jarflags -JarAction = SCons.Action.Action('$JARCOM', '$JARCOMSTR') - -JarBuilder = SCons.Builder.Builder(action = JarAction, - source_factory = SCons.Node.FS.Entry, - suffix = '$JARSUFFIX') - def generate(env): """Add Builders and construction variables for jar to an Environment.""" - try: - env['BUILDERS']['Jar'] - except KeyError: - env['BUILDERS']['Jar'] = JarBuilder + SCons.Tool.CreateJarBuilder(env) env['JAR'] = 'jar' env['JARFLAGS'] = SCons.Util.CLVar('cf') env['_JARFLAGS'] = jarFlags env['_JARMANIFEST'] = jarManifest env['_JARSOURCES'] = jarSources - env['JARCOM'] = '$JAR $_JARFLAGS $TARGET $_JARMANIFEST $_JARSOURCES' + env['_JARCOM'] = '$JAR $_JARFLAGS $TARGET $_JARMANIFEST $_JARSOURCES' + env['JARCOM'] = "${TEMPFILE('$_JARCOM')}" env['JARSUFFIX'] = '.jar' def exists(env): diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/javac.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/javac.py new file mode 100644 index 000000000..54bc94e85 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/javac.py @@ -0,0 +1,222 @@ +"""SCons.Tool.javac + +Tool-specific initialization for javac. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/javac.py 2523 2007/12/12 09:37:41 knight" + +import os +import os.path +import string + +import SCons.Action +import SCons.Builder +from SCons.Node.FS import _my_normcase +from SCons.Tool.JavaCommon import parse_java_file +import SCons.Util + +def classname(path): + """Turn a string (path name) into a Java class name.""" + return string.replace(os.path.normpath(path), os.sep, '.') + +def emit_java_classes(target, source, env): + """Create and return lists of source java files + and their corresponding target class files. + """ + java_suffix = env.get('JAVASUFFIX', '.java') + class_suffix = env.get('JAVACLASSSUFFIX', '.class') + + target[0].must_be_same(SCons.Node.FS.Dir) + classdir = target[0] + + s = source[0].rentry().disambiguate() + if isinstance(s, SCons.Node.FS.File): + sourcedir = s.dir.rdir() + elif isinstance(s, SCons.Node.FS.Dir): + sourcedir = s.rdir() + else: + raise SCons.Errors.UserError("Java source must be File or Dir, not '%s'" % s.__class__) + + slist = [] + js = _my_normcase(java_suffix) + find_java = lambda n, js=js, ljs=len(js): _my_normcase(n[-ljs:]) == js + for entry in source: + entry = entry.rentry().disambiguate() + if isinstance(entry, SCons.Node.FS.File): + slist.append(entry) + elif isinstance(entry, SCons.Node.FS.Dir): + result = SCons.Util.OrderedDict() + def visit(arg, dirname, names, fj=find_java, dirnode=entry.rdir()): + java_files = filter(fj, names) + # The on-disk entries come back in arbitrary order. Sort + # them so our target and source lists are determinate. + java_files.sort() + mydir = dirnode.Dir(dirname) + java_paths = map(lambda f, d=mydir: d.File(f), java_files) + for jp in java_paths: + arg[jp] = True + + os.path.walk(entry.rdir().get_abspath(), visit, result) + entry.walk(visit, result) + + slist.extend(result.keys()) + else: + raise SCons.Errors.UserError("Java source must be File or Dir, not '%s'" % entry.__class__) + + version = env.get('JAVAVERSION', '1.4') + tlist = [] + for f in slist: + source_file_based = True + pkg_dir = None + if not f.is_derived(): + pkg_dir, classes = parse_java_file(f.rfile().get_abspath(), version) + if classes: + source_file_based = False + if pkg_dir: + d = target[0].Dir(pkg_dir) + p = pkg_dir + os.sep + else: + d = target[0] + p = '' + for c in classes: + t = d.File(c + class_suffix) + t.attributes.java_classdir = classdir + t.attributes.java_sourcedir = sourcedir + t.attributes.java_classname = classname(p + c) + tlist.append(t) + + if source_file_based: + base = f.name[:-len(java_suffix)] + if pkg_dir: + t = target[0].Dir(pkg_dir).File(base + class_suffix) + else: + t = target[0].File(base + class_suffix) + t.attributes.java_classdir = classdir + t.attributes.java_sourcedir = f.dir + t.attributes.java_classname = classname(base) + tlist.append(t) + + return tlist, slist + +JavaAction = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') + +JavaBuilder = SCons.Builder.Builder(action = JavaAction, + emitter = emit_java_classes, + target_factory = SCons.Node.FS.Entry, + source_factory = SCons.Node.FS.Entry) + +class pathopt: + """ + Callable object for generating javac-style path options from + a construction variable (e.g. -classpath, -sourcepath). + """ + def __init__(self, opt, var, default=None): + self.opt = opt + self.var = var + self.default = default + + def __call__(self, target, source, env, for_signature): + path = env[self.var] + if path and not SCons.Util.is_List(path): + path = [path] + if self.default: + path = path + [ env[self.default] ] + if path: + return [self.opt, string.join(path, os.pathsep)] + #return self.opt + " " + string.join(path, os.pathsep) + else: + return [] + #return "" + +def Java(env, target, source, *args, **kw): + """ + A pseudo-Builder wrapper around the separate JavaClass{File,Dir} + Builders. + """ + if not SCons.Util.is_List(target): + target = [target] + if not SCons.Util.is_List(source): + source = [source] + + # Pad the target list with repetitions of the last element in the + # list so we have a target for every source element. + target = target + ([target[-1]] * (len(source) - len(target))) + + java_suffix = env.subst('$JAVASUFFIX') + result = [] + + for t, s in zip(target, source): + if isinstance(s, SCons.Node.FS.Base): + if isinstance(s, SCons.Node.FS.File): + b = env.JavaClassFile + else: + b = env.JavaClassDir + else: + if os.path.isfile(s): + b = env.JavaClassFile + elif os.path.isdir(s): + b = env.JavaClassDir + elif s[-len(java_suffix):] == java_suffix: + b = env.JavaClassFile + else: + b = env.JavaClassDir + result.extend(apply(b, (t, s) + args, kw)) + + return result + +def generate(env): + """Add Builders and construction variables for javac to an Environment.""" + java_file = SCons.Tool.CreateJavaFileBuilder(env) + java_class = SCons.Tool.CreateJavaClassFileBuilder(env) + java_class_dir = SCons.Tool.CreateJavaClassDirBuilder(env) + java_class.add_emitter(None, emit_java_classes) + java_class.add_emitter(env.subst('$JAVASUFFIX'), emit_java_classes) + java_class_dir.emitter = emit_java_classes + + env.AddMethod(Java) + + env['JAVAC'] = 'javac' + env['JAVACFLAGS'] = SCons.Util.CLVar('') + env['JAVABOOTCLASSPATH'] = [] + env['JAVACLASSPATH'] = [] + env['JAVASOURCEPATH'] = [] + env['_javapathopt'] = pathopt + env['_JAVABOOTCLASSPATH'] = '${_javapathopt("-bootclasspath", "JAVABOOTCLASSPATH")} ' + env['_JAVACLASSPATH'] = '${_javapathopt("-classpath", "JAVACLASSPATH")} ' + env['_JAVASOURCEPATH'] = '${_javapathopt("-sourcepath", "JAVASOURCEPATH", "_JAVASOURCEPATHDEFAULT")} ' + env['_JAVASOURCEPATHDEFAULT'] = '${TARGET.attributes.java_sourcedir}' + env['_JAVACCOM'] = '$JAVAC $JAVACFLAGS $_JAVABOOTCLASSPATH $_JAVACLASSPATH -d ${TARGET.attributes.java_classdir} $_JAVASOURCEPATH $SOURCES' + env['JAVACCOM'] = "${TEMPFILE('$_JAVACCOM')}" + env['JAVACLASSSUFFIX'] = '.class' + env['JAVASUFFIX'] = '.java' + +def exists(env): + return 1 diff --git a/scons/scons-local-0.97/SCons/Tool/javah.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/javah.py similarity index 86% rename from scons/scons-local-0.97/SCons/Tool/javah.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/javah.py index 4e770e06a..195bfe068 100644 --- a/scons/scons-local-0.97/SCons/Tool/javah.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/javah.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/javah.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/javah.py 2523 2007/12/12 09:37:41 knight" import os.path import string @@ -60,6 +60,7 @@ def emit_java_headers(target, source, env): except AttributeError: classdir = '.' classdir = env.Dir(classdir).rdir() + if str(classdir) == '.': c_ = None else: @@ -77,10 +78,13 @@ def emit_java_headers(target, source, env): classname = classname[:-len(class_suffix)] classname = SCons.Tool.javac.classname(classname) s = src.rfile() - s.attributes.java_classdir = classdir s.attributes.java_classname = classname slist.append(s) + s = source[0].rfile() + if not hasattr(s.attributes, 'java_classdir'): + s.attributes.java_classdir = classdir + if target[0].__class__ is SCons.Node.FS.File: tlist = target else: @@ -106,22 +110,22 @@ def JavaHOutFlagGenerator(target, source, env, for_signature): except AttributeError: return '-o ' + str(t) -JavaHAction = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR') - -JavaHBuilder = SCons.Builder.Builder(action = JavaHAction, - emitter = emit_java_headers, - src_suffix = '$JAVACLASSSUFFIX', - target_factory = SCons.Node.FS.Entry, - source_factory = SCons.Node.FS.File) +def getJavaHClassPath(env,target, source, for_signature): + path = "${SOURCE.attributes.java_classdir}" + if env.has_key('JAVACLASSPATH') and env['JAVACLASSPATH']: + path = SCons.Util.AppendPath(path, env['JAVACLASSPATH']) + return "-classpath %s" % (path) def generate(env): """Add Builders and construction variables for javah to an Environment.""" - env['BUILDERS']['JavaH'] = JavaHBuilder + java_javah = SCons.Tool.CreateJavaHBuilder(env) + java_javah.emitter = emit_java_headers env['_JAVAHOUTFLAG'] = JavaHOutFlagGenerator env['JAVAH'] = 'javah' env['JAVAHFLAGS'] = SCons.Util.CLVar('') - env['JAVAHCOM'] = '$JAVAH $JAVAHFLAGS $_JAVAHOUTFLAG -classpath ${SOURCE.attributes.java_classdir} ${SOURCES.attributes.java_classname}' + env['_JAVAHCLASSPATH'] = getJavaHClassPath + env['JAVAHCOM'] = '$JAVAH $JAVAHFLAGS $_JAVAHOUTFLAG $_JAVAHCLASSPATH ${SOURCES.attributes.java_classname}' env['JAVACLASSSUFFIX'] = '.class' def exists(env): diff --git a/scons/scons-local-0.97/SCons/Tool/latex.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/latex.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/latex.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/latex.py index f07fae0bf..6dab15e11 100644 --- a/scons/scons-local-0.97/SCons/Tool/latex.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/latex.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/latex.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/latex.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Defaults diff --git a/scons/scons-local-0.97/SCons/Tool/lex.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/lex.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/lex.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/lex.py index c40f24d7c..a710b6462 100644 --- a/scons/scons-local-0.97/SCons/Tool/lex.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/lex.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/lex.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/lex.py 2523 2007/12/12 09:37:41 knight" import os.path @@ -55,7 +55,8 @@ def lexEmitter(target, source, env): # Different options that are used to trigger the creation of extra files. fileGenOptions = ["--header-file=", "--tables-file="] - for option in SCons.Util.CLVar(env.subst("$LEXFLAGS")): + lexflags = env.subst("$LEXFLAGS", target=target, source=source) + for option in SCons.Util.CLVar(lexflags): for fileGenOption in fileGenOptions: l = len(fileGenOption) if option[:l] == fileGenOption: diff --git a/scons/scons-local-0.97/SCons/Tool/link.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/link.py similarity index 96% rename from scons/scons-local-0.97/SCons/Tool/link.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/link.py index 458dd70d5..97c6713da 100644 --- a/scons/scons-local-0.97/SCons/Tool/link.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/link.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/link.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/link.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Tool @@ -48,7 +48,7 @@ def generate(env): """Add Builders and construction variables for gnulink to an Environment.""" SCons.Tool.createSharedLibBuilder(env) SCons.Tool.createProgBuilder(env) - + env['SHLINK'] = '$LINK' env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' diff --git a/scons/scons-local-0.97/SCons/Tool/linkloc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/linkloc.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/linkloc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/linkloc.py index 902fcb7fe..33e9c5c6e 100644 --- a/scons/scons-local-0.97/SCons/Tool/linkloc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/linkloc.py @@ -32,7 +32,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/linkloc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/linkloc.py 2523 2007/12/12 09:37:41 knight" import os.path import re @@ -96,8 +96,8 @@ def generate(env): msvs_version = env.get('MSVS_VERSION') include_path, lib_path, exe_path = get_msvc_paths(env, version = msvs_version) - env['ENV']['LIB'] = lib_path - env['ENV']['PATH'] = exe_path + env['ENV']['LIB'] = lib_path + env.PrependENVPath('PATH', exe_path) addPharLapPaths(env) diff --git a/scons/scons-local-0.97/SCons/Tool/m4.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/m4.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/m4.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/m4.py index a1aefed10..fa9d50c5a 100644 --- a/scons/scons-local-0.97/SCons/Tool/m4.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/m4.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/m4.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/m4.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Builder diff --git a/scons/scons-local-0.97/SCons/Tool/masm.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/masm.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/masm.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/masm.py index 5f6ae2f7e..86f262c1a 100644 --- a/scons/scons-local-0.97/SCons/Tool/masm.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/masm.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/masm.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/masm.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Tool diff --git a/scons/scons-local-0.97/SCons/Tool/midl.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/midl.py similarity index 85% rename from scons/scons-local-0.97/SCons/Tool/midl.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/midl.py index 57e42f373..4ca6c1a66 100644 --- a/scons/scons-local-0.97/SCons/Tool/midl.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/midl.py @@ -31,14 +31,15 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/midl.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/midl.py 2523 2007/12/12 09:37:41 knight" + +import string import SCons.Action import SCons.Builder import SCons.Defaults import SCons.Scanner.IDL import SCons.Util -import SCons.Tool.msvs def midl_emitter(target, source, env): """Produces a list of outputs from the MIDL compiler""" @@ -46,11 +47,17 @@ def midl_emitter(target, source, env): tlb = target[0] incl = base + '.h' interface = base + '_i.c' - proxy = base + '_p.c' - dlldata = base + '_data.c' + t = [tlb, incl, interface] - t = [tlb, incl, interface, proxy, dlldata] + midlcom = env['MIDLCOM'] + if string.find(midlcom, '/proxy') != -1: + proxy = base + '_p.c' + t.append(proxy) + if string.find(midlcom, '/dlldata') != -1: + dlldata = base + '_data.c' + t.append(dlldata) + return (t,source) idl_scanner = SCons.Scanner.IDL.IDLScan() @@ -72,6 +79,10 @@ def generate(env): env['BUILDERS']['TypeLibrary'] = midl_builder def exists(env): + if not env['PLATFORM'] in ('win32', 'cygwin'): + return 0 + + import SCons.Tool.msvs if SCons.Tool.msvs.is_msvs_installed(): # there's at least one version of MSVS installed, which comes with midl: return 1 diff --git a/scons/scons-local-0.97/SCons/Tool/mingw.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/mingw.py similarity index 92% rename from scons/scons-local-0.97/SCons/Tool/mingw.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/mingw.py index d639f3358..6dbf2ae92 100644 --- a/scons/scons-local-0.97/SCons/Tool/mingw.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/mingw.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/mingw.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/mingw.py 2523 2007/12/12 09:37:41 knight" import os import os.path @@ -107,15 +107,7 @@ def generate(env): mingw = find(env) if mingw: dir = os.path.dirname(mingw) - - # The mingw bin directory must be added to the path: - path = env['ENV'].get('PATH', []) - if not path: - path = [] - if SCons.Util.is_String(path): - path = string.split(path, os.pathsep) - - env['ENV']['PATH'] = string.join([dir] + path, os.pathsep) + env.PrependENVPath('PATH', dir ) # Most of mingw is the same as gcc and friends... diff --git a/scons/scons-local-0.97/SCons/Tool/mslib.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/mslib.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/mslib.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/mslib.py index cb764fbf5..038130f4f 100644 --- a/scons/scons-local-0.97/SCons/Tool/mslib.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/mslib.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/mslib.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/mslib.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Tool diff --git a/scons/scons-local-0.97/SCons/Tool/mslink.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/mslink.py similarity index 93% rename from scons/scons-local-0.97/SCons/Tool/mslink.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/mslink.py index 759e50859..487dad98c 100644 --- a/scons/scons-local-0.97/SCons/Tool/mslink.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/mslink.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/mslink.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/mslink.py 2523 2007/12/12 09:37:41 knight" import os.path @@ -45,10 +45,10 @@ import SCons.Tool.msvs import SCons.Util def pdbGenerator(env, target, source, for_signature): - if target and env.has_key('PDB') and env['PDB']: - return ['/PDB:%s'%target[0].File(env['PDB']).get_string(for_signature), - '/DEBUG'] - return None + try: + return ['/PDB:%s' % target[0].attributes.pdb, '/DEBUG'] + except (AttributeError, IndexError): + return None def windowsShlinkTargets(target, source, env, for_signature): listCmd = [] @@ -99,7 +99,9 @@ def windowsLibEmitter(target, source, env): "WINDOWSSHLIBMANIFESTPREFIX", "WINDOWSSHLIBMANIFESTSUFFIX")) if env.has_key('PDB') and env['PDB']: - target.append(env['PDB']) + pdb = env.arg2nodes('$PDB', target=target, source=source)[0] + target.append(pdb) + target[0].attributes.pdb = pdb if not no_import_lib and \ not env.FindIxes(target, "LIBPREFIX", "LIBSUFFIX"): @@ -129,7 +131,9 @@ def prog_emitter(target, source, env): "WINDOWSPROGMANIFESTPREFIX", "WINDOWSPROGMANIFESTSUFFIX")) if env.has_key('PDB') and env['PDB']: - target.append(env['PDB']) + pdb = env.arg2nodes('$PDB', target=target, source=source)[0] + target.append(pdb) + target[0].attributes.pdb = pdb return (target,source) @@ -182,9 +186,9 @@ def generate(env): env['WINDOWSEXPSUFFIX'] = '${WIN32EXPSUFFIX}' env['WINDOWSSHLIBMANIFESTPREFIX'] = '' - env['WINDOWSSHLIBMANIFESTSUFFIX'] = env['SHLIBSUFFIX'] + '.manifest' + env['WINDOWSSHLIBMANIFESTSUFFIX'] = '${SHLIBSUFFIX}.manifest' env['WINDOWSPROGMANIFESTPREFIX'] = '' - env['WINDOWSPROGMANIFESTSUFFIX'] = env['PROGSUFFIX'] + '.manifest' + env['WINDOWSPROGMANIFESTSUFFIX'] = '${PROGSUFFIX}.manifest' env['REGSVRACTION'] = regServerCheck env['REGSVR'] = os.path.join(SCons.Platform.win32.get_system_root(),'System32','regsvr32') diff --git a/scons/scons-local-0.97/SCons/Tool/msvc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/msvc.py similarity index 99% rename from scons/scons-local-0.97/SCons/Tool/msvc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/msvc.py index f43654dd5..4f4875077 100644 --- a/scons/scons-local-0.97/SCons/Tool/msvc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/msvc.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/msvc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/msvc.py 2523 2007/12/12 09:37:41 knight" import os.path import re diff --git a/scons/scons-local-0.97/SCons/Tool/msvs.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/msvs.py similarity index 99% rename from scons/scons-local-0.97/SCons/Tool/msvs.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/msvs.py index 3b5b91660..5e029321a 100644 --- a/scons/scons-local-0.97/SCons/Tool/msvs.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/msvs.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/msvs.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/msvs.py 2523 2007/12/12 09:37:41 knight" import base64 import md5 @@ -1018,8 +1018,10 @@ class _GenerateV7DSW(_DSWGenerator): self.file.write('\t\t%s.%s|%s.ActiveCfg = %s|%s\n' '\t\t%s.%s|%s.Build.0 = %s|%s\n' % (guid,variant,platform,variant,platform,guid,variant,platform,variant,platform)) else: - self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n' - '\t\t%s.%s.Build.0 = %s|%s\n' %(self.slnguid,variant,variant,platform,self.slnguid,variant,variant,platform)) + for p in self.dspfiles: + guid = _generateGUID(p, '') + self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n' + '\t\t%s.%s.Build.0 = %s|%s\n' %(guid,variant,variant,platform,guid,variant,variant,platform)) self.file.write('\tEndGlobalSection\n') @@ -1761,6 +1763,9 @@ def generate(env): env['SCONS_HOME'] = os.environ.get('SCONS_HOME') def exists(env): + if not env['PLATFORM'] in ('win32', 'cygwin'): + return 0 + try: v = SCons.Tool.msvs.get_visualstudio_versions() except (SCons.Util.RegError, SCons.Errors.InternalError): diff --git a/scons/scons-local-0.97/SCons/Tool/mwcc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/mwcc.py similarity index 98% rename from scons/scons-local-0.97/SCons/Tool/mwcc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/mwcc.py index cb01b49f1..30a7a9759 100644 --- a/scons/scons-local-0.97/SCons/Tool/mwcc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/mwcc.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/mwcc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/mwcc.py 2523 2007/12/12 09:37:41 knight" import os import os.path diff --git a/scons/scons-local-0.97/SCons/Tool/mwld.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/mwld.py similarity index 96% rename from scons/scons-local-0.97/SCons/Tool/mwld.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/mwld.py index 7e13ad0f9..597b51585 100644 --- a/scons/scons-local-0.97/SCons/Tool/mwld.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/mwld.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/mwld.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/mwld.py 2523 2007/12/12 09:37:41 knight" import SCons.Tool diff --git a/scons/scons-local-0.97/SCons/Tool/nasm.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/nasm.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/nasm.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/nasm.py index 927c6e8a6..6f80da6ac 100644 --- a/scons/scons-local-0.97/SCons/Tool/nasm.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/nasm.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/nasm.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/nasm.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Tool diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/__init__.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/__init__.py new file mode 100644 index 000000000..b5312baeb --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/__init__.py @@ -0,0 +1,306 @@ +"""SCons.Tool.Packaging + +SCons Packaging Tool. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/packaging/__init__.py 2523 2007/12/12 09:37:41 knight" + +import SCons.Environment +from SCons.Options import * +from SCons.Errors import * +from SCons.Util import is_List, make_path_relative +from SCons.Warnings import warn, Warning + +import os, imp +import SCons.Defaults + +__all__ = [ 'src_targz', 'src_tarbz2', 'src_zip', 'tarbz2', 'targz', 'zip', 'rpm', 'msi', 'ipk' ] + +# +# Utility and Builder function +# +def Tag(env, target, source, *more_tags, **kw_tags): + """ Tag a file with the given arguments, just sets the accordingly named + attribute on the file object. + + TODO: FIXME + """ + if not target: + target=source + first_tag=None + else: + first_tag=source + + if first_tag: + kw_tags[first_tag[0]] = '' + + if len(kw_tags) == 0 and len(more_tags) == 0: + raise UserError, "No tags given." + + # XXX: sanity checks + for x in more_tags: + kw_tags[x] = '' + + if not SCons.Util.is_List(target): + target=[target] + else: + # hmm, sometimes the target list, is a list of a list + # make sure it is flattened prior to processing. + # TODO: perhaps some bug ?!? + target=env.Flatten(target) + + for t in target: + for (k,v) in kw_tags.items(): + # all file tags have to start with PACKAGING_, so we can later + # differentiate between "normal" object attributes and the + # packaging attributes. As the user should not be bothered with + # that, the prefix will be added here if missing. + #if not k.startswith('PACKAGING_'): + if k[:10] != 'PACKAGING_': + k='PACKAGING_'+k + setattr(t, k, v) + +def Package(env, target=None, source=None, **kw): + """ Entry point for the package tool. + """ + # check if we need to find the source files ourself + if not source: + source = env.FindInstalledFiles() + + if len(source)==0: + raise UserError, "No source for Package() given" + + # decide which types of packages shall be built. Can be defined through + # four mechanisms: command line argument, keyword argument, + # environment argument and default selection( zip or tar.gz ) in that + # order. + try: kw['PACKAGETYPE']=env['PACKAGETYPE'] + except KeyError: pass + + if not kw.get('PACKAGETYPE'): + from SCons.Script import GetOption + kw['PACKAGETYPE'] = GetOption('package_type') + + if kw['PACKAGETYPE'] == None: + if env['BUILDERS'].has_key('Tar'): + kw['PACKAGETYPE']='targz' + elif env['BUILDERS'].has_key('Zip'): + kw['PACKAGETYPE']='zip' + else: + raise UserError, "No type for Package() given" + + PACKAGETYPE=kw['PACKAGETYPE'] + if not is_List(PACKAGETYPE): + PACKAGETYPE=string.split(PACKAGETYPE, ',') + + # load the needed packagers. + def load_packager(type): + try: + file,path,desc=imp.find_module(type, __path__) + return imp.load_module(type, file, path, desc) + except ImportError, e: + raise EnvironmentError("packager %s not available: %s"%(type,str(e))) + + packagers=map(load_packager, PACKAGETYPE) + + # set up targets and the PACKAGEROOT + try: + # fill up the target list with a default target name until the PACKAGETYPE + # list is of the same size as the target list. + if not target: target = [] + + size_diff = len(PACKAGETYPE)-len(target) + default_name = "%(NAME)s-%(VERSION)s" + + if size_diff>0: + default_target = default_name%kw + target.extend( [default_target]*size_diff ) + + if not kw.has_key('PACKAGEROOT'): + kw['PACKAGEROOT'] = default_name%kw + + except KeyError, e: + raise SCons.Errors.UserError( "Missing Packagetag '%s'"%e.args[0] ) + + # setup the source files + source=env.arg2nodes(source, env.fs.Entry) + + # call the packager to setup the dependencies. + targets=[] + try: + for packager in packagers: + t=[target.pop(0)] + t=apply(packager.package, [env,t,source], kw) + targets.extend(t) + + assert( len(target) == 0 ) + + except KeyError, e: + raise SCons.Errors.UserError( "Missing Packagetag '%s' for %s packager"\ + % (e.args[0],packager.__name__) ) + except TypeError, e: + # this exception means that a needed argument for the packager is + # missing. As our packagers get their "tags" as named function + # arguments we need to find out which one is missing. + from inspect import getargspec + args,varargs,varkw,defaults=getargspec(packager.package) + if defaults!=None: + args=args[:-len(defaults)] # throw away arguments with default values + map(args.remove, 'env target source'.split()) + # now remove any args for which we have a value in kw. + #args=[x for x in args if not kw.has_key(x)] + args=filter(lambda x, kw=kw: not kw.has_key(x), args) + + if len(args)==0: + raise # must be a different error, so reraise + elif len(args)==1: + raise SCons.Errors.UserError( "Missing Packagetag '%s' for %s packager"\ + % (args[0],packager.__name__) ) + else: + raise SCons.Errors.UserError( "Missing Packagetags '%s' for %s packager"\ + % (", ".join(args),packager.__name__) ) + + target=env.arg2nodes(target, env.fs.Entry) + targets.extend(env.Alias( 'package', targets )) + return targets + +# +# SCons tool initialization functions +# + +added = None + +def generate(env): + from SCons.Script import AddOption + global added + if not added: + added = 1 + AddOption('--package-type', + dest='package_type', + default=None, + type="string", + action="store", + help='The type of package to create.') + + try: + env['BUILDERS']['Package'] + env['BUILDERS']['Tag'] + except KeyError: + env['BUILDERS']['Package'] = Package + env['BUILDERS']['Tag'] = Tag + +def exists(env): + return 1 + +# XXX +def options(opts): + opts.AddOptions( + EnumOption( 'PACKAGETYPE', + 'the type of package to create.', + None, allowed_values=map( str, __all__ ), + ignorecase=2 + ) + ) + +# +# Internal utility functions +# + +def copy_attr(f1, f2): + """ copies the special packaging file attributes from f1 to f2. + """ + #pattrs = [x for x in dir(f1) if not hasattr(f2, x) and\ + # x.startswith('PACKAGING_')] + copyit = lambda x, f2=f2: not hasattr(f2, x) and x[:10] == 'PACKAGING_' + pattrs = filter(copyit, dir(f1)) + for attr in pattrs: + setattr(f2, attr, getattr(f1, attr)) +def putintopackageroot(target, source, env, pkgroot, honor_install_location=1): + """ Uses the CopyAs builder to copy all source files to the directory given + in pkgroot. + + If honor_install_location is set and the copied source file has an + PACKAGING_INSTALL_LOCATION attribute, the PACKAGING_INSTALL_LOCATION is + used as the new name of the source file under pkgroot. + + The source file will not be copied if it is already under the the pkgroot + directory. + + All attributes of the source file will be copied to the new file. + """ + # make sure the packageroot is a Dir object. + if SCons.Util.is_String(pkgroot): pkgroot=env.Dir(pkgroot) + if not SCons.Util.is_List(source): source=[source] + + new_source = [] + for file in source: + if SCons.Util.is_String(file): file = env.File(file) + + if file.is_under(pkgroot): + new_source.append(file) + else: + if hasattr(file, 'PACKAGING_INSTALL_LOCATION') and\ + honor_install_location: + new_name=make_path_relative(file.PACKAGING_INSTALL_LOCATION) + else: + new_name=make_path_relative(file.get_path()) + + new_file=pkgroot.File(new_name) + new_file=env.CopyAs(new_file, file)[0] + copy_attr(file, new_file) + new_source.append(new_file) + + return (target, new_source) + +def stripinstallbuilder(target, source, env): + """ strips the install builder action from the source list and stores + the final installation location as the "PACKAGING_INSTALL_LOCATION" of + the source of the source file. This effectively removes the final installed + files from the source list while remembering the installation location. + + It also warns about files which have no install builder attached. + """ + def has_no_install_location(file): + return not (file.has_builder() and\ + hasattr(file.builder, 'name') and\ + (file.builder.name=="InstallBuilder" or\ + file.builder.name=="InstallAsBuilder")) + + if len(filter(has_no_install_location, source)): + warn(Warning, "there are files to package which have no\ + InstallBuilder attached, this might lead to irreproducible packages") + + n_source=[] + for s in source: + if has_no_install_location(s): + n_source.append(s) + else: + for ss in s.sources: + n_source.append(ss) + copy_attr(s, ss) + setattr(ss, 'PACKAGING_INSTALL_LOCATION', s.get_path()) + + return (target, n_source) diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/ipk.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/ipk.py new file mode 100644 index 000000000..aeeb1f403 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/ipk.py @@ -0,0 +1,179 @@ +"""SCons.Tool.Packaging.ipk +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/packaging/ipk.py 2523 2007/12/12 09:37:41 knight" + +import SCons.Builder +import SCons.Node.FS +import os + +from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot + +def package(env, target, source, PACKAGEROOT, NAME, VERSION, DESCRIPTION, + SUMMARY, X_IPK_PRIORITY, X_IPK_SECTION, SOURCE_URL, + X_IPK_MAINTAINER, X_IPK_DEPENDS, **kw): + """ this function prepares the packageroot directory for packaging with the + ipkg builder. + """ + SCons.Tool.Tool('ipkg').generate(env) + + # setup the Ipkg builder + bld = env['BUILDERS']['Ipkg'] + target, source = stripinstallbuilder(target, source, env) + target, source = putintopackageroot(target, source, env, PACKAGEROOT) + + # This should be overridable from the construction environment, + # which it is by using ARCHITECTURE=. + # Guessing based on what os.uname() returns at least allows it + # to work for both i386 and x86_64 Linux systems. + archmap = { + 'i686' : 'i386', + 'i586' : 'i386', + 'i486' : 'i386', + } + + buildarchitecture = os.uname()[4] + buildarchitecture = archmap.get(buildarchitecture, buildarchitecture) + + if kw.has_key('ARCHITECTURE'): + buildarchitecture = kw['ARCHITECTURE'] + + # setup the kw to contain the mandatory arguments to this fucntion. + # do this before calling any builder or setup function + loc=locals() + del loc['kw'] + kw.update(loc) + del kw['source'], kw['target'], kw['env'] + + # generate the specfile + specfile = gen_ipk_dir(PACKAGEROOT, source, env, kw) + + # override the default target. + if str(target[0])=="%s-%s"%(NAME, VERSION): + target=[ "%s_%s_%s.ipk"%(NAME, VERSION, buildarchitecture) ] + + # now apply the Ipkg builder + return apply(bld, [env, target, specfile], kw) + +def gen_ipk_dir(proot, source, env, kw): + # make sure the packageroot is a Dir object. + if SCons.Util.is_String(proot): proot=env.Dir(proot) + + # create the specfile builder + s_bld=SCons.Builder.Builder( + action = build_specfiles, + ) + + # create the specfile targets + spec_target=[] + control=proot.Dir('CONTROL') + spec_target.append(control.File('control')) + spec_target.append(control.File('conffiles')) + spec_target.append(control.File('postrm')) + spec_target.append(control.File('prerm')) + spec_target.append(control.File('postinst')) + spec_target.append(control.File('preinst')) + + # apply the builder to the specfile targets + apply(s_bld, [env, spec_target, source], kw) + + # the packageroot directory does now contain the specfiles. + return proot + +def build_specfiles(source, target, env): + """ filter the targets for the needed files and use the variables in env + to create the specfile. + """ + # + # At first we care for the CONTROL/control file, which is the main file for ipk. + # + # For this we need to open multiple files in random order, so we store into + # a dict so they can be easily accessed. + # + # + opened_files={} + def open_file(needle, haystack): + try: + return opened_files[needle] + except KeyError: + file=filter(lambda x: x.get_path().rfind(needle)!=-1, haystack)[0] + opened_files[needle]=open(file.abspath, 'w') + return opened_files[needle] + + control_file=open_file('control', target) + + if not env.has_key('X_IPK_DESCRIPTION'): + env['X_IPK_DESCRIPTION']="%s\n %s"%(env['SUMMARY'], + env['DESCRIPTION'].replace('\n', '\n ')) + + + content = """ +Package: $NAME +Version: $VERSION +Priority: $X_IPK_PRIORITY +Section: $X_IPK_SECTION +Source: $SOURCE_URL +Architecture: $ARCHITECTURE +Maintainer: $X_IPK_MAINTAINER +Depends: $X_IPK_DEPENDS +Description: $X_IPK_DESCRIPTION +""" + + control_file.write(env.subst(content)) + + # + # now handle the various other files, which purpose it is to set post-, + # pre-scripts and mark files as config files. + # + # We do so by filtering the source files for files which are marked with + # the "config" tag and afterwards we do the same for x_ipk_postrm, + # x_ipk_prerm, x_ipk_postinst and x_ipk_preinst tags. + # + # The first one will write the name of the file into the file + # CONTROL/configfiles, the latter add the content of the x_ipk_* variable + # into the same named file. + # + for f in [x for x in source if 'PACKAGING_CONFIG' in dir(x)]: + config=open_file('conffiles') + config.write(f.PACKAGING_INSTALL_LOCATION) + config.write('\n') + + for str in 'POSTRM PRERM POSTINST PREINST'.split(): + name="PACKAGING_X_IPK_%s"%str + for f in [x for x in source if name in dir(x)]: + file=open_file(name) + file.write(env[str]) + + # + # close all opened files + for f in opened_files.values(): + f.close() + + # call a user specified function + if env.has_key('CHANGE_SPECFILE'): + content += env['CHANGE_SPECFILE'](target) + + return 0 diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/msi.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/msi.py new file mode 100644 index 000000000..8d4df0b25 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/msi.py @@ -0,0 +1,521 @@ +"""SCons.Tool.packaging.msi + +The msi packager. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/packaging/msi.py 2523 2007/12/12 09:37:41 knight" + +import os +import SCons +from SCons.Action import Action +from SCons.Builder import Builder + +from xml.dom.minidom import * +from xml.sax.saxutils import escape + +from SCons.Tool.packaging import stripinstallbuilder + +# +# Utility functions +# +def convert_to_id(s, id_set): + """ Some parts of .wxs need an Id attribute (for example: The File and + Directory directives. The charset is limited to A-Z, a-z, digits, + underscores, periods. Each Id must begin with a letter or with a + underscore. Google for "CNDL0015" for information about this. + + Requirements: + * the string created must only contain chars from the target charset. + * the string created must have a minimal editing distance from the + original string. + * the string created must be unique for the whole .wxs file. + + Observation: + * There are 62 chars in the charset. + + Idea: + * filter out forbidden characters. Check for a collision with the help + of the id_set. Add the number of the number of the collision at the + end of the created string. Furthermore care for a correct start of + the string. + """ + charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz0123456789_.' + if s[0] in '0123456789.': + s += '_'+s + id = filter( lambda c : c in charset, s ) + + # did we already generate an id for this file? + try: + return id_set[id][s] + except KeyError: + # no we did not so initialize with the id + if not id_set.has_key(id): id_set[id] = { s : id } + # there is a collision, generate an id which is unique by appending + # the collision number + else: id_set[id][s] = id + str(len(id_set[id])) + + return id_set[id][s] + +def is_dos_short_file_name(file): + """ examine if the given file is in the 8.3 form. + """ + fname, ext = os.path.splitext(file) + proper_ext = len(ext) == 0 or (2 <= len(ext) <= 4) # the ext contains the dot + proper_fname = file.isupper() and len(fname) <= 8 + + return proper_ext and proper_fname + +def gen_dos_short_file_name(file, filename_set): + """ see http://support.microsoft.com/default.aspx?scid=kb;en-us;Q142982 + + These are no complete 8.3 dos short names. The ~ char is missing and + replaced with one character from the filename. WiX warns about such + filenames, since a collision might occur. Google for "CNDL1014" for + more information. + """ + # guard this to not confuse the generation + if is_dos_short_file_name(file): + return file + + fname, ext = os.path.splitext(file) # ext contains the dot + + # first try if it suffices to convert to upper + file = file.upper() + if is_dos_short_file_name(file): + return file + + # strip forbidden characters. + forbidden = '."/[]:;=, ' + fname = filter( lambda c : c not in forbidden, fname ) + + # check if we already generated a filename with the same number: + # thisis1.txt, thisis2.txt etc. + duplicate, num = not None, 1 + while duplicate: + shortname = "%s%s" % (fname[:8-len(str(num))].upper(),\ + str(num)) + if len(ext) >= 2: + shortname = "%s%s" % (shortname, ext[:4].upper()) + + duplicate, num = shortname in filename_set, num+1 + + assert( is_dos_short_file_name(shortname) ), 'shortname is %s, longname is %s' % (shortname, file) + filename_set.append(shortname) + return shortname + +def create_feature_dict(files): + """ X_MSI_FEATURE and doc FileTag's can be used to collect files in a + hierarchy. This function collects the files into this hierarchy. + """ + dict = {} + + def add_to_dict( feature, file ): + if not SCons.Util.is_List( feature ): + feature = [ feature ] + + for f in feature: + if not dict.has_key( f ): + dict[ f ] = [ file ] + else: + dict[ f ].append( file ) + + for file in files: + if hasattr( file, 'PACKAGING_X_MSI_FEATURE' ): + add_to_dict(file.PACKAGING_X_MSI_FEATURE, file) + elif hasattr( file, 'PACKAGING_DOC' ): + add_to_dict( 'PACKAGING_DOC', file ) + else: + add_to_dict( 'default', file ) + + return dict + +def generate_guids(root): + """ generates globally unique identifiers for parts of the xml which need + them. + + Component tags have a special requirement. Their UUID is only allowed to + change if the list of their contained resources has changed. This allows + for clean removal and proper updates. + + To handle this requirement, the uuid is generated with an md5 hashing the + whole subtree of a xml node. + """ + from md5 import md5 + + # specify which tags need a guid and in which attribute this should be stored. + needs_id = { 'Product' : 'Id', + 'Package' : 'Id', + 'Component' : 'Guid', + } + + # find all XMl nodes matching the key, retrieve their attribute, hash their + # subtree, convert hash to string and add as a attribute to the xml node. + for (key,value) in needs_id.items(): + node_list = root.getElementsByTagName(key) + attribute = value + for node in node_list: + hash = md5(node.toxml()).hexdigest() + hash_str = '%s-%s-%s-%s-%s' % ( hash[:8], hash[8:12], hash[12:16], hash[16:20], hash[20:] ) + node.attributes[attribute] = hash_str + + + +def string_wxsfile(target, source, env): + return "building WiX file %s"%( target[0].path ) + +def build_wxsfile(target, source, env): + """ compiles a .wxs file from the keywords given in env['msi_spec'] and + by analyzing the tree of source nodes and their tags. + """ + file = open(target[0].abspath, 'w') + + try: + # Create a document with the Wix root tag + doc = Document() + root = doc.createElement( 'Wix' ) + root.attributes['xmlns']='http://schemas.microsoft.com/wix/2003/01/wi' + doc.appendChild( root ) + + filename_set = [] # this is to circumvent duplicates in the shortnames + id_set = {} # this is to circumvent duplicates in the ids + + # Create the content + build_wxsfile_header_section(root, env) + build_wxsfile_file_section(root, source, env['NAME'], env['VERSION'], env['VENDOR'], filename_set, id_set) + generate_guids(root) + build_wxsfile_features_section(root, source, env['NAME'], env['VERSION'], env['SUMMARY'], id_set) + build_wxsfile_default_gui(root) + build_license_file(target[0].get_dir(), env) + + # write the xml to a file + file.write( doc.toprettyxml() ) + + # call a user specified function + if env.has_key('CHANGE_SPECFILE'): + env['CHANGE_SPECFILE'](target, source) + + except KeyError, e: + raise SCons.Errors.UserError( '"%s" package field for MSI is missing.' % e.args[0] ) + +# +# setup function +# +def create_default_directory_layout(root, NAME, VERSION, VENDOR, filename_set): + """ Create the wix default target directory layout and return the innermost + directory. + + We assume that the XML tree delivered in the root argument already contains + the Product tag. + + Everything is put under the PFiles directory property defined by WiX. + After that a directory with the 'VENDOR' tag is placed and then a + directory with the name of the project and its VERSION. This leads to the + following TARGET Directory Layout: + C:\\\\ + Example: C:\Programme\Company\Product-1.2\ + """ + doc = Document() + d1 = doc.createElement( 'Directory' ) + d1.attributes['Id'] = 'TARGETDIR' + d1.attributes['Name'] = 'SourceDir' + + d2 = doc.createElement( 'Directory' ) + d2.attributes['Id'] = 'ProgramFilesFolder' + d2.attributes['Name'] = 'PFiles' + + d3 = doc.createElement( 'Directory' ) + d3.attributes['Id'] = 'VENDOR_folder' + d3.attributes['Name'] = escape( gen_dos_short_file_name( VENDOR, filename_set ) ) + d3.attributes['LongName'] = escape( VENDOR ) + + d4 = doc.createElement( 'Directory' ) + project_folder = "%s-%s" % ( NAME, VERSION ) + d4.attributes['Id'] = 'MY_DEFAULT_FOLDER' + d4.attributes['Name'] = escape( gen_dos_short_file_name( project_folder, filename_set ) ) + d4.attributes['LongName'] = escape( project_folder ) + + d1.childNodes.append( d2 ) + d2.childNodes.append( d3 ) + d3.childNodes.append( d4 ) + + root.getElementsByTagName('Product')[0].childNodes.append( d1 ) + + return d4 + +# +# mandatory and optional file tags +# +def build_wxsfile_file_section(root, files, NAME, VERSION, VENDOR, filename_set, id_set): + """ builds the Component sections of the wxs file with their included files. + + Files need to be specified in 8.3 format and in the long name format, long + filenames will be converted automatically. + + Features are specficied with the 'X_MSI_FEATURE' or 'DOC' FileTag. + """ + root = create_default_directory_layout( root, NAME, VERSION, VENDOR, filename_set ) + components = create_feature_dict( files ) + factory = Document() + + def get_directory( node, dir ): + """ returns the node under the given node representing the directory. + + Returns the component node if dir is None or empty. + """ + if dir == '' or not dir: + return node + + Directory = node + dir_parts = dir.split(os.path.sep) + + # to make sure that our directory ids are unique, the parent folders are + # consecutively added to upper_dir + upper_dir = '' + + # walk down the xml tree finding parts of the directory + dir_parts = filter( lambda d: d != '', dir_parts ) + for d in dir_parts[:]: + already_created = filter( lambda c: c.nodeName == 'Directory' and c.attributes['LongName'].value == escape(d), Directory.childNodes ) + + if already_created != []: + Directory = already_created[0] + dir_parts.remove(d) + upper_dir += d + else: + break + + for d in dir_parts: + nDirectory = factory.createElement( 'Directory' ) + nDirectory.attributes['LongName'] = escape( d ) + nDirectory.attributes['Name'] = escape( gen_dos_short_file_name( d, filename_set ) ) + upper_dir += d + nDirectory.attributes['Id'] = convert_to_id( upper_dir, id_set ) + + Directory.childNodes.append( nDirectory ) + Directory = nDirectory + + return Directory + + for file in files: + drive, path = os.path.splitdrive( file.PACKAGING_INSTALL_LOCATION ) + filename = os.path.basename( path ) + dirname = os.path.dirname( path ) + + h = { + # tagname : default value + 'PACKAGING_X_MSI_VITAL' : 'yes', + 'PACKAGING_X_MSI_FILEID' : convert_to_id(filename, id_set), + 'PACKAGING_X_MSI_LONGNAME' : filename, + 'PACKAGING_X_MSI_SHORTNAME' : gen_dos_short_file_name(filename, filename_set), + 'PACKAGING_X_MSI_SOURCE' : file.get_path(), + } + + # fill in the default tags given above. + for k,v in [ (k, v) for (k,v) in h.items() if not hasattr(file, k) ]: + setattr( file, k, v ) + + File = factory.createElement( 'File' ) + File.attributes['LongName'] = escape( file.PACKAGING_X_MSI_LONGNAME ) + File.attributes['Name'] = escape( file.PACKAGING_X_MSI_SHORTNAME ) + File.attributes['Source'] = escape( file.PACKAGING_X_MSI_SOURCE ) + File.attributes['Id'] = escape( file.PACKAGING_X_MSI_FILEID ) + File.attributes['Vital'] = escape( file.PACKAGING_X_MSI_VITAL ) + + # create the Tag under which this file should appear + Component = factory.createElement('Component') + Component.attributes['DiskId'] = '1' + Component.attributes['Id'] = convert_to_id( filename, id_set ) + + # hang the component node under the root node and the file node + # under the component node. + Directory = get_directory( root, dirname ) + Directory.childNodes.append( Component ) + Component.childNodes.append( File ) + +# +# additional functions +# +def build_wxsfile_features_section(root, files, NAME, VERSION, SUMMARY, id_set): + """ This function creates the tag based on the supplied xml tree. + + This is achieved by finding all s and adding them to a default target. + + It should be called after the tree has been built completly. We assume + that a MY_DEFAULT_FOLDER Property is defined in the wxs file tree. + + Furthermore a top-level with the name and VERSION of the software will be created. + + An PACKAGING_X_MSI_FEATURE can either be a string, where the feature + DESCRIPTION will be the same as its title or a Tuple, where the first + part will be its title and the second its DESCRIPTION. + """ + factory = Document() + Feature = factory.createElement('Feature') + Feature.attributes['Id'] = 'complete' + Feature.attributes['ConfigurableDirectory'] = 'MY_DEFAULT_FOLDER' + Feature.attributes['Level'] = '1' + Feature.attributes['Title'] = escape( '%s %s' % (NAME, VERSION) ) + Feature.attributes['Description'] = escape( SUMMARY ) + Feature.attributes['Display'] = 'expand' + + for (feature, files) in create_feature_dict(files).items(): + SubFeature = factory.createElement('Feature') + SubFeature.attributes['Level'] = '1' + + if SCons.Util.is_Tuple(feature): + SubFeature.attributes['Id'] = convert_to_id( feature[0], id_set ) + SubFeature.attributes['Title'] = escape(feature[0]) + SubFeature.attributes['Description'] = escape(feature[1]) + else: + SubFeature.attributes['Id'] = convert_to_id( feature, id_set ) + if feature=='default': + SubFeature.attributes['Description'] = 'Main Part' + SubFeature.attributes['Title'] = 'Main Part' + elif feature=='PACKAGING_DOC': + SubFeature.attributes['Description'] = 'Documentation' + SubFeature.attributes['Title'] = 'Documentation' + else: + SubFeature.attributes['Description'] = escape(feature) + SubFeature.attributes['Title'] = escape(feature) + + # build the componentrefs. As one of the design decision is that every + # file is also a component we walk the list of files and create a + # reference. + for f in files: + ComponentRef = factory.createElement('ComponentRef') + ComponentRef.attributes['Id'] = convert_to_id( os.path.basename(f.get_path()), id_set ) + SubFeature.childNodes.append(ComponentRef) + + Feature.childNodes.append(SubFeature) + + root.getElementsByTagName('Product')[0].childNodes.append(Feature) + +def build_wxsfile_default_gui(root): + """ this function adds a default GUI to the wxs file + """ + factory = Document() + Product = root.getElementsByTagName('Product')[0] + + UIRef = factory.createElement('UIRef') + UIRef.attributes['Id'] = 'WixUI_Mondo' + Product.childNodes.append(UIRef) + + UIRef = factory.createElement('UIRef') + UIRef.attributes['Id'] = 'WixUI_ErrorProgressText' + Product.childNodes.append(UIRef) + +def build_license_file(directory, spec): + """ creates a License.rtf file with the content of "X_MSI_LICENSE_TEXT" + in the given directory + """ + name, text = '', '' + + try: + name = spec['LICENSE'] + text = spec['X_MSI_LICENSE_TEXT'] + except KeyError: + pass # ignore this as X_MSI_LICENSE_TEXT is optional + + if name!='' or text!='': + file = open( os.path.join(directory.get_path(), 'License.rtf'), 'w' ) + file.write('{\\rtf') + if text!='': + file.write(text.replace('\n', '\\par ')) + else: + file.write(name+'\\par\\par') + file.write('}') + file.close() + +# +# mandatory and optional package tags +# +def build_wxsfile_header_section(root, spec): + """ Adds the xml file node which define the package meta-data. + """ + # Create the needed DOM nodes and add them at the correct position in the tree. + factory = Document() + Product = factory.createElement( 'Product' ) + Package = factory.createElement( 'Package' ) + + root.childNodes.append( Product ) + Product.childNodes.append( Package ) + + # set "mandatory" default values + if not spec.has_key('X_MSI_LANGUAGE'): + spec['X_MSI_LANGUAGE'] = '1033' # select english + + # mandatory sections, will throw a KeyError if the tag is not available + Product.attributes['Name'] = escape( spec['NAME'] ) + Product.attributes['Version'] = escape( spec['VERSION'] ) + Product.attributes['Manufacturer'] = escape( spec['VENDOR'] ) + Product.attributes['Language'] = escape( spec['X_MSI_LANGUAGE'] ) + Package.attributes['Description'] = escape( spec['SUMMARY'] ) + + # now the optional tags, for which we avoid the KeyErrror exception + if spec.has_key( 'DESCRIPTION' ): + Package.attributes['Comments'] = escape( spec['DESCRIPTION'] ) + + if spec.has_key( 'X_MSI_UPGRADE_CODE' ): + Package.attributes['X_MSI_UPGRADE_CODE'] = escape( spec['X_MSI_UPGRADE_CODE'] ) + + # We hardcode the media tag as our current model cannot handle it. + Media = factory.createElement('Media') + Media.attributes['Id'] = '1' + Media.attributes['Cabinet'] = 'default.cab' + Media.attributes['EmbedCab'] = 'yes' + root.getElementsByTagName('Product')[0].childNodes.append(Media) + +# this builder is the entry-point for .wxs file compiler. +wxs_builder = Builder( + action = Action( build_wxsfile, string_wxsfile ), + ensure_suffix = '.wxs' ) + +def package(env, target, source, PACKAGEROOT, NAME, VERSION, + DESCRIPTION, SUMMARY, VENDOR, X_MSI_LANGUAGE, **kw): + # make sure that the Wix Builder is in the environment + SCons.Tool.Tool('wix').generate(env) + + # get put the keywords for the specfile compiler. These are the arguments + # given to the package function and all optional ones stored in kw, minus + # the the source, target and env one. + loc = locals() + del loc['kw'] + kw.update(loc) + del kw['source'], kw['target'], kw['env'] + + # strip the install builder from the source files + target, source = stripinstallbuilder(target, source, env) + + # put the arguments into the env and call the specfile builder. + env['msi_spec'] = kw + specfile = apply( wxs_builder, [env, target, source], kw ) + + # now call the WiX Tool with the built specfile added as a source. + msifile = env.WiX(target, specfile) + + # return the target and source tuple. + return (msifile, source+[specfile]) + diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/rpm.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/rpm.py new file mode 100644 index 000000000..cc3cc60f5 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/rpm.py @@ -0,0 +1,362 @@ +"""SCons.Tool.Packaging.rpm + +The rpm packager. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/packaging/rpm.py 2523 2007/12/12 09:37:41 knight" + +import os +import string + +import SCons.Builder + +from SCons.Environment import OverrideEnvironment +from SCons.Tool.packaging import stripinstallbuilder, src_targz +from SCons.Errors import UserError + +def package(env, target, source, PACKAGEROOT, NAME, VERSION, + PACKAGEVERSION, DESCRIPTION, SUMMARY, X_RPM_GROUP, LICENSE, + **kw): + # initialize the rpm tool + SCons.Tool.Tool('rpm').generate(env) + + bld = env['BUILDERS']['Rpm'] + + # Generate a UserError whenever the target name has been set explicitly, + # since rpm does not allow for controlling it. This is detected by + # checking if the target has been set to the default by the Package() + # Environment function. + if str(target[0])!="%s-%s"%(NAME, VERSION): + raise UserError( "Setting target is not supported for rpm." ) + else: + # This should be overridable from the construction environment, + # which it is by using ARCHITECTURE=. + # Guessing based on what os.uname() returns at least allows it + # to work for both i386 and x86_64 Linux systems. + archmap = { + 'i686' : 'i386', + 'i586' : 'i386', + 'i486' : 'i386', + } + + buildarchitecture = os.uname()[4] + buildarchitecture = archmap.get(buildarchitecture, buildarchitecture) + + if kw.has_key('ARCHITECTURE'): + buildarchitecture = kw['ARCHITECTURE'] + + fmt = '%s-%s-%s.%s.rpm' + srcrpm = fmt % (NAME, VERSION, PACKAGEVERSION, 'src') + binrpm = fmt % (NAME, VERSION, PACKAGEVERSION, buildarchitecture) + + target = [ srcrpm, binrpm ] + + # get the correct arguments into the kw hash + loc=locals() + del loc['kw'] + kw.update(loc) + del kw['source'], kw['target'], kw['env'] + + # if no "SOURCE_URL" tag is given add a default one. + if not kw.has_key('SOURCE_URL'): + #kw['SOURCE_URL']=(str(target[0])+".tar.gz").replace('.rpm', '') + kw['SOURCE_URL']=string.replace(str(target[0])+".tar.gz", '.rpm', '') + + # mangle the source and target list for the rpmbuild + env = OverrideEnvironment(env, kw) + target, source = stripinstallbuilder(target, source, env) + target, source = addspecfile(target, source, env) + target, source = collectintargz(target, source, env) + + # now call the rpm builder to actually build the packet. + return apply(bld, [env, target, source], kw) + +def collectintargz(target, source, env): + """ Puts all source files into a tar.gz file. """ + # the rpm tool depends on a source package, until this is chagned + # this hack needs to be here that tries to pack all sources in. + sources = env.FindSourceFiles() + + # filter out the target we are building the source list for. + #sources = [s for s in sources if not (s in target)] + sources = filter(lambda s, t=target: not (s in t), sources) + + # find the .spec file for rpm and add it since it is not necessarily found + # by the FindSourceFiles function. + #sources.extend( [s for s in source if str(s).rfind('.spec')!=-1] ) + spec_file = lambda s: string.rfind(str(s), '.spec') != -1 + sources.extend( filter(spec_file, source) ) + + # as the source contains the url of the source package this rpm package + # is built from, we extract the target name + #tarball = (str(target[0])+".tar.gz").replace('.rpm', '') + tarball = string.replace(str(target[0])+".tar.gz", '.rpm', '') + try: + #tarball = env['SOURCE_URL'].split('/')[-1] + tarball = string.split(env['SOURCE_URL'], '/')[-1] + except KeyError, e: + raise SCons.Errors.UserError( "Missing PackageTag '%s' for RPM packager" % e.args[0] ) + + tarball = src_targz.package(env, source=sources, target=tarball, + PACKAGEROOT=env['PACKAGEROOT'], ) + + return (target, tarball) + +def addspecfile(target, source, env): + specfile = "%s-%s" % (env['NAME'], env['VERSION']) + + bld = SCons.Builder.Builder(action = build_specfile, + suffix = '.spec', + target_factory = SCons.Node.FS.File) + + source.extend(bld(env, specfile, source)) + + return (target,source) + +def build_specfile(target, source, env): + """ Builds a RPM specfile from a dictionary with string metadata and + by analyzing a tree of nodes. + """ + file = open(target[0].abspath, 'w') + str = "" + + try: + file.write( build_specfile_header(env) ) + file.write( build_specfile_sections(env) ) + file.write( build_specfile_filesection(env, source) ) + file.close() + + # call a user specified function + if env.has_key('CHANGE_SPECFILE'): + env['CHANGE_SPECFILE'](target, source) + + except KeyError, e: + raise SCons.Errors.UserError( '"%s" package field for RPM is missing.' % e.args[0] ) + + +# +# mandatory and optional package tag section +# +def build_specfile_sections(spec): + """ Builds the sections of a rpm specfile. + """ + str = "" + + mandatory_sections = { + 'DESCRIPTION' : '\n%%description\n%s\n\n', } + + str = str + SimpleTagCompiler(mandatory_sections).compile( spec ) + + optional_sections = { + 'DESCRIPTION_' : '%%description -l %s\n%s\n\n', + 'CHANGELOG' : '%%changelog\n%s\n\n', + 'X_RPM_PREINSTALL' : '%%pre\n%s\n\n', + 'X_RPM_POSTINSTALL' : '%%post\n%s\n\n', + 'X_RPM_PREUNINSTALL' : '%%preun\n%s\n\n', + 'X_RPM_POSTUNINSTALL' : '%%postun\n%s\n\n', + 'X_RPM_VERIFY' : '%%verify\n%s\n\n', + + # These are for internal use but could possibly be overriden + 'X_RPM_PREP' : '%%prep\n%s\n\n', + 'X_RPM_BUILD' : '%%build\n%s\n\n', + 'X_RPM_INSTALL' : '%%install\n%s\n\n', + 'X_RPM_CLEAN' : '%%clean\n%s\n\n', + } + + # Default prep, build, install and clean rules + # TODO: optimize those build steps, to not compile the project a second time + if not spec.has_key('X_RPM_PREP'): + spec['X_RPM_PREP'] = '[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"' + '\n%setup -q' + + if not spec.has_key('X_RPM_BUILD'): + spec['X_RPM_BUILD'] = 'mkdir "$RPM_BUILD_ROOT"' + + if not spec.has_key('X_RPM_INSTALL'): + spec['X_RPM_INSTALL'] = 'scons --install-sandbox="$RPM_BUILD_ROOT" "$RPM_BUILD_ROOT"' + + if not spec.has_key('X_RPM_CLEAN'): + spec['X_RPM_CLEAN'] = '[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"' + + str = str + SimpleTagCompiler(optional_sections, mandatory=0).compile( spec ) + + return str + +def build_specfile_header(spec): + """ Builds all section but the %file of a rpm specfile + """ + str = "" + + # first the mandatory sections + mandatory_header_fields = { + 'NAME' : '%%define name %s\nName: %%{name}\n', + 'VERSION' : '%%define version %s\nVersion: %%{version}\n', + 'PACKAGEVERSION' : '%%define release %s\nRelease: %%{release}\n', + 'X_RPM_GROUP' : 'Group: %s\n', + 'SUMMARY' : 'Summary: %s\n', + 'LICENSE' : 'License: %s\n', } + + str = str + SimpleTagCompiler(mandatory_header_fields).compile( spec ) + + # now the optional tags + optional_header_fields = { + 'VENDOR' : 'Vendor: %s\n', + 'X_RPM_URL' : 'Url: %s\n', + 'SOURCE_URL' : 'Source: %s\n', + 'SUMMARY_' : 'Summary(%s): %s\n', + 'X_RPM_DISTRIBUTION' : 'Distribution: %s\n', + 'X_RPM_ICON' : 'Icon: %s\n', + 'X_RPM_PACKAGER' : 'Packager: %s\n', + 'X_RPM_GROUP_' : 'Group(%s): %s\n', + + 'X_RPM_REQUIRES' : 'Requires: %s\n', + 'X_RPM_PROVIDES' : 'Provides: %s\n', + 'X_RPM_CONFLICTS' : 'Conflicts: %s\n', + 'X_RPM_BUILDREQUIRES' : 'BuildRequires: %s\n', + + 'X_RPM_SERIAL' : 'Serial: %s\n', + 'X_RPM_EPOCH' : 'Epoch: %s\n', + 'X_RPM_AUTOREQPROV' : 'AutoReqProv: %s\n', + 'X_RPM_EXCLUDEARCH' : 'ExcludeArch: %s\n', + 'X_RPM_EXCLUSIVEARCH' : 'ExclusiveArch: %s\n', + 'X_RPM_PREFIX' : 'Prefix: %s\n', + 'X_RPM_CONFLICTS' : 'Conflicts: %s\n', + + # internal use + 'X_RPM_BUILDROOT' : 'BuildRoot: %s\n', } + + # fill in default values: + # Adding a BuildRequires renders the .rpm unbuildable under System, which + # are not managed by rpm, since the database to resolve this dependency is + # missing (take Gentoo as an example) +# if not s.has_key('x_rpm_BuildRequires'): +# s['x_rpm_BuildRequires'] = 'scons' + + if not spec.has_key('X_RPM_BUILDROOT'): + spec['X_RPM_BUILDROOT'] = '%{_tmppath}/%{name}-%{version}-%{release}' + + str = str + SimpleTagCompiler(optional_header_fields, mandatory=0).compile( spec ) + return str + +# +# mandatory and optional file tags +# +def build_specfile_filesection(spec, files): + """ builds the %file section of the specfile + """ + str = '%files\n' + + if not spec.has_key('X_RPM_DEFATTR'): + spec['X_RPM_DEFATTR'] = '(-,root,root)' + + str = str + '%%defattr %s\n' % spec['X_RPM_DEFATTR'] + + supported_tags = { + 'PACKAGING_CONFIG' : '%%config %s', + 'PACKAGING_CONFIG_NOREPLACE' : '%%config(noreplace) %s', + 'PACKAGING_DOC' : '%%doc %s', + 'PACKAGING_UNIX_ATTR' : '%%attr %s', + 'PACKAGING_LANG_' : '%%lang(%s) %s', + 'PACKAGING_X_RPM_VERIFY' : '%%verify %s', + 'PACKAGING_X_RPM_DIR' : '%%dir %s', + 'PACKAGING_X_RPM_DOCDIR' : '%%docdir %s', + 'PACKAGING_X_RPM_GHOST' : '%%ghost %s', } + + for file in files: + # build the tagset + tags = {} + for k in supported_tags.keys(): + try: + tags[k]=getattr(file, k) + except AttributeError: + pass + + # compile the tagset + str = str + SimpleTagCompiler(supported_tags, mandatory=0).compile( tags ) + + str = str + ' ' + str = str + file.PACKAGING_INSTALL_LOCATION + str = str + '\n\n' + + return str + +class SimpleTagCompiler: + """ This class is a simple string substition utility: + the replacement specfication is stored in the tagset dictionary, something + like: + { "abc" : "cdef %s ", + "abc_" : "cdef %s %s" } + + the compile function gets a value dictionary, which may look like: + { "abc" : "ghij", + "abc_gh" : "ij" } + + The resulting string will be: + "cdef ghij cdef gh ij" + """ + def __init__(self, tagset, mandatory=1): + self.tagset = tagset + self.mandatory = mandatory + + def compile(self, values): + """ compiles the tagset and returns a str containing the result + """ + def is_international(tag): + #return tag.endswith('_') + return tag[-1:] == '_' + + def get_country_code(tag): + return tag[-2:] + + def strip_country_code(tag): + return tag[:-2] + + replacements = self.tagset.items() + + str = "" + #domestic = [ (k,v) for k,v in replacements if not is_international(k) ] + domestic = filter(lambda t, i=is_international: not i(t[0]), replacements) + for key, replacement in domestic: + try: + str = str + replacement % values[key] + except KeyError, e: + if self.mandatory: + raise e + + #international = [ (k,v) for k,v in replacements if is_international(k) ] + international = filter(lambda t, i=is_international: i(t[0]), replacements) + for key, replacement in international: + try: + #int_values_for_key = [ (get_country_code(k),v) for k,v in values.items() if strip_country_code(k) == key ] + x = filter(lambda t,key=key,s=strip_country_code: s(t[0]) == key, values.items()) + int_values_for_key = map(lambda t,g=get_country_code: (g(t[0]),t[1]), x) + for v in int_values_for_key: + str = str + replacement % v + except KeyError, e: + if self.mandatory: + raise e + + return str + diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/src_tarbz2.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/src_tarbz2.py new file mode 100644 index 000000000..45f423ed6 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/src_tarbz2.py @@ -0,0 +1,37 @@ +"""SCons.Tool.Packaging.tarbz2 + +The tarbz2 SRC packager. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/packaging/src_tarbz2.py 2523 2007/12/12 09:37:41 knight" + +from SCons.Tool.packaging import putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Tar'] + bld.set_suffix('.tar.bz2') + target, source = putintopackageroot(target, source, env, PACKAGEROOT, honor_install_location=0) + return bld(env, target, source, TARFLAGS='-jc') diff --git a/scons/scons-local-0.97/SCons/Sig/__init__.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/src_targz.py similarity index 62% rename from scons/scons-local-0.97/SCons/Sig/__init__.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/src_targz.py index c93e8e10d..dd618617a 100644 --- a/scons/scons-local-0.97/SCons/Sig/__init__.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/src_targz.py @@ -1,7 +1,6 @@ -"""SCons.Sig - -The Signature package for the scons software construction utility. +"""SCons.Tool.Packaging.targz +The targz SRC packager. """ # @@ -27,27 +26,12 @@ The Signature package for the scons software construction utility. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Sig/__init__.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/packaging/src_targz.py 2523 2007/12/12 09:37:41 knight" -try: - import MD5 - default_module = MD5 -except ImportError: - import TimeStamp - default_module = TimeStamp +from SCons.Tool.packaging import putintopackageroot -class Calculator: - """ - Encapsulates signature calculations and .sconsign file generating - for the build engine. - """ - - def __init__(self, module=default_module): - """ - Initialize the calculator. - - module - the signature module to use for signature calculations - """ - self.module = module - -default_calc = Calculator() +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Tar'] + bld.set_suffix('.tar.gz') + target, source = putintopackageroot(target, source, env, PACKAGEROOT, honor_install_location=0) + return bld(env, target, source, TARFLAGS='-zc') diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/src_zip.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/src_zip.py new file mode 100644 index 000000000..1480c77c0 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/src_zip.py @@ -0,0 +1,37 @@ +"""SCons.Tool.Packaging.zip + +The zip SRC packager. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/packaging/src_zip.py 2523 2007/12/12 09:37:41 knight" + +from SCons.Tool.packaging import putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Zip'] + bld.set_suffix('.zip') + target, source = putintopackageroot(target, source, env, PACKAGEROOT, honor_install_location=0) + return bld(env, target, source) diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/tarbz2.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/tarbz2.py new file mode 100644 index 000000000..a50b2489a --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/tarbz2.py @@ -0,0 +1,38 @@ +"""SCons.Tool.Packaging.tarbz2 + +The tarbz2 SRC packager. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/packaging/tarbz2.py 2523 2007/12/12 09:37:41 knight" + +from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Tar'] + bld.set_suffix('.tar.gz') + target, source = putintopackageroot(target, source, env, PACKAGEROOT) + target, source = stripinstallbuilder(target, source, env) + return bld(env, target, source, TARFLAGS='-jc') diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/targz.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/targz.py new file mode 100644 index 000000000..200b3f7b6 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/targz.py @@ -0,0 +1,38 @@ +"""SCons.Tool.Packaging.targz + +The targz SRC packager. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/packaging/targz.py 2523 2007/12/12 09:37:41 knight" + +from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Tar'] + bld.set_suffix('.tar.gz') + target, source = stripinstallbuilder(target, source, env) + target, source = putintopackageroot(target, source, env, PACKAGEROOT) + return bld(env, target, source, TARFLAGS='-zc') diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/zip.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/zip.py new file mode 100644 index 000000000..a32d652b4 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/packaging/zip.py @@ -0,0 +1,38 @@ +"""SCons.Tool.Packaging.zip + +The zip SRC packager. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/packaging/zip.py 2523 2007/12/12 09:37:41 knight" + +from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Zip'] + bld.set_suffix('.zip') + target, source = stripinstallbuilder(target, source, env) + target, source = putintopackageroot(target, source, env, PACKAGEROOT) + return bld(env, target, source) diff --git a/scons/scons-local-0.97/SCons/Tool/pdf.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/pdf.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/pdf.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/pdf.py index ec6366a5c..5f684872e 100644 --- a/scons/scons-local-0.97/SCons/Tool/pdf.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/pdf.py @@ -27,7 +27,7 @@ Common PDF Builder definition for various other Tool modules that use it. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/pdf.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/pdf.py 2523 2007/12/12 09:37:41 knight" import SCons.Builder import SCons.Tool diff --git a/scons/scons-local-0.97/SCons/Tool/pdflatex.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/pdflatex.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/pdflatex.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/pdflatex.py index 76d4d5f87..74da467d2 100644 --- a/scons/scons-local-0.97/SCons/Tool/pdflatex.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/pdflatex.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/pdflatex.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/pdflatex.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Util diff --git a/scons/scons-local-0.97/SCons/Tool/pdftex.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/pdftex.py similarity index 96% rename from scons/scons-local-0.97/SCons/Tool/pdftex.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/pdftex.py index 9dee2653b..bb515b736 100644 --- a/scons/scons-local-0.97/SCons/Tool/pdftex.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/pdftex.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/pdftex.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/pdftex.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Util diff --git a/scons/scons-local-0.97/SCons/Tool/qt.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/qt.py similarity index 99% rename from scons/scons-local-0.97/SCons/Tool/qt.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/qt.py index 7d911419e..5e7664e7f 100644 --- a/scons/scons-local-0.97/SCons/Tool/qt.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/qt.py @@ -32,7 +32,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/qt.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/qt.py 2523 2007/12/12 09:37:41 knight" import os.path import re diff --git a/scons/scons-local-0.97/SCons/Tool/rmic.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/rmic.py similarity index 96% rename from scons/scons-local-0.97/SCons/Tool/rmic.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/rmic.py index f70cef44c..fbd274ca1 100644 --- a/scons/scons-local-0.97/SCons/Tool/rmic.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/rmic.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/rmic.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/rmic.py 2523 2007/12/12 09:37:41 knight" import os.path import string diff --git a/scons/scons-local-0.97/SCons/Tool/rpcgen.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/rpcgen.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/rpcgen.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/rpcgen.py index a5b5b222f..4e7900f59 100644 --- a/scons/scons-local-0.97/SCons/Tool/rpcgen.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/rpcgen.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/rpcgen.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/rpcgen.py 2523 2007/12/12 09:37:41 knight" from SCons.Builder import Builder import SCons.Util diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/rpm.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/rpm.py new file mode 100644 index 000000000..5cefc17b6 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/rpm.py @@ -0,0 +1,125 @@ +"""SCons.Tool.rpm + +Tool-specific initialization for rpm. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +The rpm tool calls the rpmbuild command. The first and only argument should a +tar.gz consisting of the source file and a specfile. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/rpm.py 2523 2007/12/12 09:37:41 knight" + +import os +import re +import shutil +import popen2 + +import SCons.Builder +import SCons.Node.FS +import SCons.Util +import SCons.Action +import SCons.Defaults + +def get_cmd(source, env): + tar_file_with_included_specfile = source + if SCons.Util.is_List(source): + tar_file_with_included_specfile = source[0] + return "%s %s %s"%(env['RPM'], env['RPMFLAGS'], + tar_file_with_included_specfile.abspath ) + +def build_rpm(target, source, env): + # create a temporary rpm build root. + tmpdir = os.path.join( os.path.dirname( target[0].abspath ), 'rpmtemp' ) + if os.path.exists(tmpdir): + shutil.rmtree(tmpdir) + + # now create the mandatory rpm directory structure. + for d in ['RPMS', 'SRPMS', 'SPECS', 'BUILD']: + os.makedirs( os.path.join( tmpdir, d ) ) + + # set the topdir as an rpmflag. + env.Prepend( RPMFLAGS = '--define \'_topdir %s\'' % tmpdir ) + + # now call rpmbuild to create the rpm package. + handle = popen2.Popen3( get_cmd(source, env), capturestderr=1 ) + output = handle.fromchild.read() + #output += handle.childerr.read() + output = output + handle.childerr.read() + status = handle.wait() + + if status: + raise SCons.Errors.BuildError( node=target[0], + errstr=output, + filename=str(target[0]) ) + else: + # XXX: assume that LC_ALL=c is set while running rpmbuild + output_files = re.compile( 'Wrote: (.*)' ).findall( output ) + + for output, input in zip( output_files, target ): + rpm_output = os.path.basename(output) + expected = os.path.basename(input.get_path()) + + assert expected == rpm_output, "got %s but expected %s" % (rpm_output, expected) + shutil.copy( output, input.abspath ) + + + # cleanup before leaving. + shutil.rmtree(tmpdir) + + return status + +def string_rpm(target, source, env): + try: + return env['RPMCOMSTR'] + except KeyError: + return get_cmd(source, env) + +rpmAction = SCons.Action.Action(build_rpm, string_rpm) + +RpmBuilder = SCons.Builder.Builder(action = SCons.Action.Action('$RPMCOM', '$RPMCOMSTR'), + source_scanner = SCons.Defaults.DirScanner, + suffix = '$RPMSUFFIX') + + + +def generate(env): + """Add Builders and construction variables for rpm to an Environment.""" + try: + bld = env['BUILDERS']['Rpm'] + except KeyError: + bld = RpmBuilder + env['BUILDERS']['Rpm'] = bld + + env.SetDefault(RPM = 'LC_ALL=c rpmbuild') + env.SetDefault(RPMFLAGS = SCons.Util.CLVar('-ta')) + env.SetDefault(RPMCOM = rpmAction) + env.SetDefault(RPMSUFFIX = '.rpm') + +def exists(env): + return env.Detect('rpmbuild') diff --git a/scons/scons-local-0.97/SCons/Tool/sgiar.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/sgiar.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/sgiar.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/sgiar.py index 46933d275..3103d6dc5 100644 --- a/scons/scons-local-0.97/SCons/Tool/sgiar.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/sgiar.py @@ -33,7 +33,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/sgiar.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/sgiar.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Tool diff --git a/scons/scons-local-0.97/SCons/Tool/sgic++.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/sgic++.py similarity index 92% rename from scons/scons-local-0.97/SCons/Tool/sgic++.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/sgic++.py index 7d1d5813a..b91614732 100644 --- a/scons/scons-local-0.97/SCons/Tool/sgic++.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/sgic++.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/sgic++.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/sgic++.py 2523 2007/12/12 09:37:41 knight" import SCons.Util @@ -44,7 +44,7 @@ def generate(env): env['CXX'] = 'CC' env['CXXFLAGS'] = SCons.Util.CLVar('$CCFLAGS -LANG:std') - env['SHCXX'] = 'CC' + env['SHCXX'] = '$CXX' env['SHOBJSUFFIX'] = '.o' env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 diff --git a/scons/scons-local-0.97/SCons/Tool/sgicc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/sgicc.py similarity index 93% rename from scons/scons-local-0.97/SCons/Tool/sgicc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/sgicc.py index 9e7c5db2e..8c4c14f91 100644 --- a/scons/scons-local-0.97/SCons/Tool/sgicc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/sgicc.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/sgicc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/sgicc.py 2523 2007/12/12 09:37:41 knight" import cc diff --git a/scons/scons-local-0.97/SCons/Tool/sgilink.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/sgilink.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/sgilink.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/sgilink.py index f4c6b2e55..428d0b962 100644 --- a/scons/scons-local-0.97/SCons/Tool/sgilink.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/sgilink.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/sgilink.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/sgilink.py 2523 2007/12/12 09:37:41 knight" import SCons.Util diff --git a/scons/scons-local-0.97/SCons/Tool/sunar.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/sunar.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/sunar.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/sunar.py index e3c16fa87..c873e1c38 100644 --- a/scons/scons-local-0.97/SCons/Tool/sunar.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/sunar.py @@ -32,7 +32,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/sunar.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/sunar.py 2523 2007/12/12 09:37:41 knight" import SCons.Defaults import SCons.Tool diff --git a/scons/scons-local-0.97/SCons/Tool/sunc++.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/sunc++.py similarity index 90% rename from scons/scons-local-0.97/SCons/Tool/sunc++.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/sunc++.py index 36ac37d3b..8f0af572a 100644 --- a/scons/scons-local-0.97/SCons/Tool/sunc++.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/sunc++.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/sunc++.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/sunc++.py 2523 2007/12/12 09:37:41 knight" import SCons.Util @@ -39,8 +39,6 @@ import os.path cplusplus = __import__('c++', globals(), locals(), []) -compilers = ['CC', 'sunCC'] - # use the package installer tool lslpp to figure out where cppc and what # version of it is installed def get_cppc(env): @@ -71,11 +69,16 @@ def generate(env): cplusplus.generate(env) env['CXX'] = cxx - #env['SHCXX'] = shcxx + env['SHCXX'] = shcxx env['CXXVERSION'] = version env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -KPIC') env['SHOBJPREFIX'] = 'so_' env['SHOBJSUFFIX'] = '.o' def exists(env): - return env.Detect(compilers) + path, cxx, shcxx, version = get_cppc(env) + if path and cxx: + cppc = os.path.join(path, cxx) + if os.path.exists(cppc): + return cppc + return None diff --git a/scons/scons-local-0.97/SCons/Tool/suncc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/suncc.py similarity index 93% rename from scons/scons-local-0.97/SCons/Tool/suncc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/suncc.py index 1724839d9..bbfe4e4bb 100644 --- a/scons/scons-local-0.97/SCons/Tool/suncc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/suncc.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/suncc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/suncc.py 2523 2007/12/12 09:37:41 knight" import SCons.Util diff --git a/scons/scons-local-0.97/SCons/Tool/sunlink.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/sunlink.py similarity index 94% rename from scons/scons-local-0.97/SCons/Tool/sunlink.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/sunlink.py index 12e387257..1934206dd 100644 --- a/scons/scons-local-0.97/SCons/Tool/sunlink.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/sunlink.py @@ -30,7 +30,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/sunlink.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/sunlink.py 2523 2007/12/12 09:37:41 knight" import os import os.path diff --git a/scons/scons-local-0.97/SCons/Tool/swig.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/swig.py similarity index 55% rename from scons/scons-local-0.97/SCons/Tool/swig.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/swig.py index 07eb650d7..b03c25d1f 100644 --- a/scons/scons-local-0.97/SCons/Tool/swig.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/swig.py @@ -31,71 +31,50 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/swig.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/swig.py 2523 2007/12/12 09:37:41 knight" + +import os.path +import re import SCons.Action import SCons.Defaults +import SCons.Scanner import SCons.Tool import SCons.Util -from SCons.Scanner import Scanner -import os -import re SwigAction = SCons.Action.Action('$SWIGCOM', '$SWIGCOMSTR') def swigSuffixEmitter(env, source): - if '-c++' in SCons.Util.CLVar(env.subst("$SWIGFLAGS")): + if '-c++' in SCons.Util.CLVar(env.subst("$SWIGFLAGS", source=source)): return '$SWIGCXXFILESUFFIX' else: return '$SWIGCFILESUFFIX' -_reInclude = re.compile(r'%include\s+(\S+)') _reModule = re.compile(r'%module\s+(.+)') -def recurse(path, searchPath): - global _reInclude - f = open(path) - try: contents = f.read() - finally: f.close() - - found = [] - # Better code for when we drop Python 1.5.2. - #for m in _reInclude.finditer(contents): - # fname = m.group(1) - for fname in _reInclude.findall(contents): - for dpath in searchPath: - absPath = os.path.join(dpath, fname) - if os.path.isfile(absPath): - found.append(absPath) - break - - # Equivalent code for when we drop Python 1.5.2. - #for f in [f for f in found if os.path.splitext(f)[1] == ".i"]: - # found += recurse(f, searchPath) - for f in filter(lambda f: os.path.splitext(f)[1] == ".i", found): - found = found + recurse(f, searchPath) - return found - -def _scanSwig(node, env, path): - r = recurse(str(node), [os.path.abspath(os.path.dirname(str(node))), os.path.abspath(os.path.join("include", "swig"))]) - return r - def _swigEmitter(target, source, env): + swigflags = env.subst("$SWIGFLAGS", target=target, source=source) + flags = SCons.Util.CLVar(swigflags) for src in source: - src = str(src) - mname = None - flags = SCons.Util.CLVar(env.subst("$SWIGFLAGS")) + src = str(src.rfile()) + mnames = None if "-python" in flags and "-noproxy" not in flags: - f = open(src) - try: - for l in f.readlines(): - m = _reModule.match(l) - if m: - mname = m.group(1) - finally: - f.close() - if mname is not None: - target.append(mname + ".py") + if mnames is None: + mnames = _reModule.findall(open(src).read()) + target.extend(map(lambda m: m + ".py", mnames)) + if "-java" in flags: + if mnames is None: + mnames = _reModule.findall(open(src).read()) + java_files = map(lambda m: [m + ".java", m + "JNI.java"], mnames) + java_files = SCons.Util.flatten(java_files) + outdir = env.subst('$SWIGOUTDIR', target=target, source=source) + if outdir: + java_files = map(lambda j, o=outdir: os.path.join(o, j), java_files) + java_files = map(env.fs.File, java_files) + for jf in java_files: + t_from_s = lambda t, p, s, x: t.dir + SCons.Util.AddMethod(jf, t_from_s, 'target_from_source') + target.extend(java_files) return (target, source) def generate(env): @@ -110,12 +89,28 @@ def generate(env): cxx_file.add_action('.i', SwigAction) cxx_file.add_emitter('.i', _swigEmitter) + java_file = SCons.Tool.CreateJavaFileBuilder(env) + + java_file.suffix['.i'] = swigSuffixEmitter + + java_file.add_action('.i', SwigAction) + java_file.add_emitter('.i', _swigEmitter) + env['SWIG'] = 'swig' env['SWIGFLAGS'] = SCons.Util.CLVar('') env['SWIGCFILESUFFIX'] = '_wrap$CFILESUFFIX' env['SWIGCXXFILESUFFIX'] = '_wrap$CXXFILESUFFIX' - env['SWIGCOM'] = '$SWIG $SWIGFLAGS -o $TARGET $SOURCES' - env.Append(SCANNERS=Scanner(function=_scanSwig, skeys=[".i"])) + env['_SWIGOUTDIR'] = '${"-outdir " + str(SWIGOUTDIR)}' + env['SWIGPATH'] = [] + env['SWIGINCPREFIX'] = '-I' + env['SWIGINCSUFFIX'] = '' + env['_SWIGINCFLAGS'] = '$( ${_concat(SWIGINCPREFIX, SWIGPATH, SWIGINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' + env['SWIGCOM'] = '$SWIG -o $TARGET ${_SWIGOUTDIR} ${_SWIGINCFLAGS} $SWIGFLAGS $SOURCES' + + expr = '^[ \t]*%[ \t]*(?:include|import|extern)[ \t]*(<|"?)([^>\s"]+)(?:>|"?)' + scanner = SCons.Scanner.ClassicCPP("SWIGScan", ".i", "SWIGPATH", expr) + + env.Append(SCANNERS = scanner) def exists(env): return env.Detect(['swig']) diff --git a/scons/scons-local-0.97/SCons/Tool/tar.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/tar.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/tar.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/tar.py index d5cd9fab9..af860b9f1 100644 --- a/scons/scons-local-0.97/SCons/Tool/tar.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/tar.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/tar.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/tar.py 2523 2007/12/12 09:37:41 knight" import SCons.Action import SCons.Builder diff --git a/scons/scons-local-0.97/SCons/Tool/tex.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/tex.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/tex.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/tex.py index 9dc4aafbc..79e9750a6 100644 --- a/scons/scons-local-0.97/SCons/Tool/tex.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/tex.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/tex.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/tex.py 2523 2007/12/12 09:37:41 knight" import os.path import re @@ -51,6 +51,7 @@ undefined_references_str = '(^LaTeX Warning:.*undefined references)|(^Package \w undefined_references_re = re.compile(undefined_references_str, re.MULTILINE) openout_aux_re = re.compile(r"\\openout.*`(.*\.aux)'") +openout_re = re.compile(r"\\openout.*`(.*)'") makeindex_re = re.compile(r"^[^%]*\\makeindex", re.MULTILINE) tableofcontents_re = re.compile(r"^[^%]*\\tableofcontents", re.MULTILINE) @@ -193,17 +194,18 @@ def tex_emitter(target, source, env): env.Precious(base + '.bbl') target.append(base + '.blg') - # read log file to get all .aux files + # read log file to get all output file (include .aux files) logfilename = base + '.log' dir, base_nodir = os.path.split(base) if os.path.exists(logfilename): content = open(logfilename, "rb").read() - aux_files = openout_aux_re.findall(content) - aux_files = filter(lambda f, b=base_nodir+'.aux': f != b, aux_files) - aux_files = map(lambda f, d=dir: d+os.sep+f, aux_files) - target.extend(aux_files) - for a in aux_files: - env.Precious( a ) + out_files = openout_re.findall(content) + out_files = filter(lambda f, b=base_nodir+'.aux': f != b, out_files) + if dir != '': + out_files = map(lambda f, d=dir: d+os.sep+f, out_files) + target.extend(out_files) + for f in out_files: + env.Precious( f ) return (target, source) diff --git a/scons/scons-local-0.97/SCons/Tool/tlib.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/tlib.py similarity index 93% rename from scons/scons-local-0.97/SCons/Tool/tlib.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/tlib.py index 50c8c6cc0..4b045151a 100644 --- a/scons/scons-local-0.97/SCons/Tool/tlib.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/tlib.py @@ -27,7 +27,7 @@ XXX # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/tlib.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/tlib.py 2523 2007/12/12 09:37:41 knight" import SCons.Tool import SCons.Tool.bcc32 diff --git a/scons/scons-local-0.97.0d20071212/SCons/Tool/wix.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/wix.py new file mode 100644 index 000000000..bae5d05f2 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/wix.py @@ -0,0 +1,94 @@ +"""SCons.Tool.wix + +Tool-specific initialization for wix, the Windows Installer XML Tool. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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__ = "src/engine/SCons/Tool/wix.py 2523 2007/12/12 09:37:41 knight" + +import SCons.Builder +import SCons.Action +import os +import string + +def generate(env): + """Add Builders and construction variables for WiX to an Environment.""" + if not exists(env): + return + + env['WIXCANDLEFLAGS'] = ['-nologo'] + env['WIXCANDLEINCLUDE'] = [] + env['WIXCANDLECOM'] = '$WIXCANDLE $WIXCANDLEFLAGS -I $WIXCANDLEINCLUDE -o ${TARGET} ${SOURCE}' + + env['WIXLIGHTFLAGS'].append( '-nologo' ) + env['WIXLIGHTCOM'] = "$WIXLIGHT $WIXLIGHTFLAGS -out ${TARGET} ${SOURCES}" + + object_builder = SCons.Builder.Builder( + action = '$WIXCANDLECOM', + suffix = '.wxiobj', + src_suffix = '.wxs') + + linker_builder = SCons.Builder.Builder( + action = '$WIXLIGHTCOM', + src_suffix = '.wxiobj', + src_builder = object_builder) + + env['BUILDERS']['WiX'] = linker_builder + +def exists(env): + env['WIXCANDLE'] = 'candle.exe' + env['WIXLIGHT'] = 'light.exe' + + # try to find the candle.exe and light.exe tools and + # add the install directory to light libpath. + #for path in os.environ['PATH'].split(os.pathsep): + for path in string.split(os.environ['PATH'], os.pathsep): + if not path: + continue + + # workaround for some weird python win32 bug. + if path[0] == '"' and path[-1:]=='"': + path = path[1:-1] + + # normalize the path + path = os.path.normpath(path) + + # search for the tools in the PATH environment variable + try: + if env['WIXCANDLE'] in os.listdir(path) and\ + env['WIXLIGHT'] in os.listdir(path): + env.PrependENVPath('PATH', path) + env['WIXLIGHTFLAGS'] = [ os.path.join( path, 'wixui.wixlib' ), + '-loc', + os.path.join( path, 'WixUI_en-us.wxl' ) ] + return 1 + except OSError: + pass # ignore this, could be a stale PATH entry. + + return None diff --git a/scons/scons-local-0.97/SCons/Tool/yacc.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/yacc.py similarity index 95% rename from scons/scons-local-0.97/SCons/Tool/yacc.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/yacc.py index ccb0664fe..389c068ae 100644 --- a/scons/scons-local-0.97/SCons/Tool/yacc.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/yacc.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/yacc.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/yacc.py 2523 2007/12/12 09:37:41 knight" import os.path import string @@ -43,7 +43,8 @@ import SCons.Util YaccAction = SCons.Action.Action("$YACCCOM", "$YACCCOMSTR") def _yaccEmitter(target, source, env, ysuf, hsuf): - flags = SCons.Util.CLVar(env.subst("$YACCFLAGS")) + yaccflags = env.subst("$YACCFLAGS", target=target, source=source) + flags = SCons.Util.CLVar(yaccflags) targetBase, targetExt = os.path.splitext(SCons.Util.to_String(target[0])) if '.ym' in ysuf: # If using Objective-C diff --git a/scons/scons-local-0.97/SCons/Tool/zip.py b/scons/scons-local-0.97.0d20071212/SCons/Tool/zip.py similarity index 96% rename from scons/scons-local-0.97/SCons/Tool/zip.py rename to scons/scons-local-0.97.0d20071212/SCons/Tool/zip.py index 0a01a1926..f3875fc99 100644 --- a/scons/scons-local-0.97/SCons/Tool/zip.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Tool/zip.py @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/zip.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Tool/zip.py 2523 2007/12/12 09:37:41 knight" import os.path diff --git a/scons/scons-local-0.97/SCons/Util.py b/scons/scons-local-0.97.0d20071212/SCons/Util.py similarity index 73% rename from scons/scons-local-0.97/SCons/Util.py rename to scons/scons-local-0.97.0d20071212/SCons/Util.py index d0b48ada2..6f097b424 100644 --- a/scons/scons-local-0.97/SCons/Util.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Util.py @@ -27,7 +27,7 @@ Various utility functions go here. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Util.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Util.py 2523 2007/12/12 09:37:41 knight" import SCons.compat @@ -51,6 +51,11 @@ ListType = types.ListType StringType = types.StringType TupleType = types.TupleType +def dictify(keys, values, result={}): + for k, v in zip(keys, values): + result[k] = v + return result + _altsep = os.altsep if _altsep is None and sys.platform == 'win32': # My ActivePython 2.0.1 doesn't set os.altsep! What gives? @@ -300,7 +305,7 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}): tags.append(' S'[IDX(root.side_effect)]) tags.append(' P'[IDX(root.precious)]) tags.append(' A'[IDX(root.always_build)]) - tags.append(' C'[IDX(root.current())]) + tags.append(' C'[IDX(root.is_up_to_date())]) tags.append(' N'[IDX(root.noclean)]) tags.append(' H'[IDX(root.nocache)]) tags.append(']') @@ -312,16 +317,16 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}): return [" ","| "][m] margins = map(MMM, margin[:-1]) - if visited.has_key(rname): + children = child_func(root) + + if prune and visited.has_key(rname) and children: print string.join(tags + margins + ['+-[', rname, ']'], '') return print string.join(tags + margins + ['+-', rname], '') - if prune: - visited[rname] = 1 + visited[rname] = 1 - children = child_func(root) if children: margin.append(1) map(lambda C, cf=child_func, p=prune, i=IDX(showtags), m=margin, v=visited: @@ -404,6 +409,64 @@ def flatten(sequence, scalarp=is_Scalar, result=None): flatten(item, scalarp, result) return result + + +# The SCons "semi-deep" copy. +# +# This makes separate copies of lists (including UserList objects) +# dictionaries (including UserDict objects) and tuples, but just copies +# references to anything else it finds. +# +# A special case is any object that has a __semi_deepcopy__() method, +# which we invoke to create the copy, which is used by the BuilderDict +# class because of its extra initialization argument. +# +# The dispatch table approach used here is a direct rip-off from the +# normal Python copy module. + +_semi_deepcopy_dispatch = d = {} + +def _semi_deepcopy_dict(x): + copy = {} + for key, val in x.items(): + # The regular Python copy.deepcopy() also deepcopies the key, + # as follows: + # + # copy[semi_deepcopy(key)] = semi_deepcopy(val) + # + # Doesn't seem like we need to, but we'll comment it just in case. + copy[key] = semi_deepcopy(val) + return copy +d[types.DictionaryType] = _semi_deepcopy_dict + +def _semi_deepcopy_list(x): + return map(semi_deepcopy, x) +d[types.ListType] = _semi_deepcopy_list + +def _semi_deepcopy_tuple(x): + return tuple(map(semi_deepcopy, x)) +d[types.TupleType] = _semi_deepcopy_tuple + +def _semi_deepcopy_inst(x): + if hasattr(x, '__semi_deepcopy__'): + return x.__semi_deepcopy__() + elif isinstance(x, UserDict): + return x.__class__(_semi_deepcopy_dict(x)) + elif isinstance(x, UserList): + return x.__class__(_semi_deepcopy_list(x)) + else: + return x +d[types.InstanceType] = _semi_deepcopy_inst + +def semi_deepcopy(x): + copier = _semi_deepcopy_dispatch.get(type(x)) + if copier: + return copier(x) + else: + return x + + + class Proxy: """A simple generic Proxy class, forwarding all calls to subject. So, for the benefit of the python newbie, what does @@ -828,17 +891,26 @@ else: def case_sensitive_suffixes(s1, s2): return (os.path.normcase(s1) != os.path.normcase(s2)) -def adjustixes(fname, pre, suf): +def adjustixes(fname, pre, suf, ensure_suffix=False): if pre: path, fn = os.path.split(os.path.normpath(fname)) if fn[:len(pre)] != pre: fname = os.path.join(path, pre + fn) - # Only append a suffix if the file does not have one. - if suf and not splitext(fname)[1] and fname[-len(suf):] != suf: + # Only append a suffix if the suffix we're going to add isn't already + # there, and if either we've been asked to ensure the specific suffix + # is present or there's no suffix on it at all. + if suf and fname[-len(suf):] != suf and \ + (ensure_suffix or not splitext(fname)[1]): fname = fname + suf return fname + +# From Tim Peters, +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 +# ASPN: Python Cookbook: Remove duplicates from a sequence +# (Also in the printed Python Cookbook.) + def unique(s): """Return a list of the elements in s, but without duplicates. @@ -909,6 +981,45 @@ def unique(s): u.append(x) return u + + +# From Alex Martelli, +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 +# ASPN: Python Cookbook: Remove duplicates from a sequence +# First comment, dated 2001/10/13. +# (Also in the printed Python Cookbook.) + +def uniquer(seq, idfun=None): + if idfun is None: + def idfun(x): return x + seen = {} + result = [] + for item in seq: + marker = idfun(item) + # in old Python versions: + # if seen.has_key(marker) + # but in new ones: + if marker in seen: continue + seen[marker] = 1 + result.append(item) + return result + +# A more efficient implementation of Alex's uniquer(), this avoids the +# idfun() argument and function-call overhead by assuming that all +# items in the sequence are hashable. + +def uniquer_hashables(seq): + seen = {} + result = [] + for item in seq: + #if not item in seen: + if not seen.has_key(item): + seen[item] = 1 + result.append(item) + return result + + + # Much of the logic here was originally based on recipe 4.9 from the # Python CookBook, but we had to dumb it way down for Python 1.5.2. class LogicalLines: @@ -938,6 +1049,101 @@ class LogicalLines: result.append(line) return result + + +class UniqueList(UserList): + def __init__(self, seq = []): + UserList.__init__(self, seq) + self.unique = True + def __make_unique(self): + if not self.unique: + self.data = uniquer_hashables(self.data) + self.unique = True + def __lt__(self, other): + self.__make_unique() + return UserList.__lt__(self, other) + def __le__(self, other): + self.__make_unique() + return UserList.__le__(self, other) + def __eq__(self, other): + self.__make_unique() + return UserList.__eq__(self, other) + def __ne__(self, other): + self.__make_unique() + return UserList.__ne__(self, other) + def __gt__(self, other): + self.__make_unique() + return UserList.__gt__(self, other) + def __ge__(self, other): + self.__make_unique() + return UserList.__ge__(self, other) + def __cmp__(self, other): + self.__make_unique() + return UserList.__cmp__(self, other) + def __len__(self): + self.__make_unique() + return UserList.__len__(self) + def __getitem__(self, i): + self.__make_unique() + return UserList.__getitem__(self, i) + def __setitem__(self, i, item): + UserList.__setitem__(self, i, item) + self.unique = False + def __getslice__(self, i, j): + self.__make_unique() + return UserList.__getslice__(self, i, j) + def __setslice__(self, i, j, other): + UserList.__setslice__(self, i, j, other) + self.unique = False + def __add__(self, other): + result = UserList.__add__(self, other) + result.unique = False + return result + def __radd__(self, other): + result = UserList.__radd__(self, other) + result.unique = False + return result + def __iadd__(self, other): + result = UserList.__iadd__(self, other) + result.unique = False + return result + def __mul__(self, other): + result = UserList.__mul__(self, other) + result.unique = False + return result + def __rmul__(self, other): + result = UserList.__rmul__(self, other) + result.unique = False + return result + def __imul__(self, other): + result = UserList.__imul__(self, other) + result.unique = False + return result + def append(self, item): + UserList.append(self, item) + self.unique = False + def insert(self, i): + UserList.insert(self, i) + self.unique = False + def count(self, item): + self.__make_unique() + return UserList.count(self, item) + def index(self, item): + self.__make_unique() + return UserList.index(self, item) + def reverse(self): + self.__make_unique() + UserList.reverse(self) + def sort(self, *args, **kwds): + self.__make_unique() + #return UserList.sort(self, *args, **kwds) + return apply(UserList.sort, (self,)+args, kwds) + def extend(self, other): + UserList.extend(self, other) + self.unique = False + + + class Unbuffered: """ A proxy class that wraps a file object, flushing after every write, @@ -950,3 +1156,158 @@ class Unbuffered: self.file.flush() def __getattr__(self, attr): return getattr(self.file, attr) + +def make_path_relative(path): + """ makes an absolute path name to a relative pathname. + """ + if os.path.isabs(path): + drive_s,path = os.path.splitdrive(path) + + import re + if not drive_s: + path=re.compile("/*(.*)").findall(path)[0] + else: + path=path[1:] + + assert( not os.path.isabs( path ) ), path + return path + + + +# The original idea for AddMethod() and RenameFunction() come from the +# following post to the ActiveState Python Cookbook: +# +# ASPN: Python Cookbook : Install bound methods in an instance +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613 +# +# That code was a little fragile, though, so the following changes +# have been wrung on it: +# +# * Switched the installmethod() "object" and "function" arguments, +# so the order reflects that the left-hand side is the thing being +# "assigned to" and the right-hand side is the value being assigned. +# +# * Changed explicit type-checking to the "try: klass = object.__class__" +# block in installmethod() below so that it still works with the +# old-style classes that SCons uses. +# +# * Replaced the by-hand creation of methods and functions with use of +# the "new" module, as alluded to in Alex Martelli's response to the +# following Cookbook post: +# +# ASPN: Python Cookbook : Dynamically added methods to a class +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 + +def AddMethod(object, function, name = None): + """ + Adds either a bound method to an instance or an unbound method to + a class. If name is ommited the name of the specified function + is used by default. + Example: + a = A() + def f(self, x, y): + self.z = x + y + AddMethod(f, A, "add") + a.add(2, 4) + print a.z + AddMethod(lambda self, i: self.l[i], a, "listIndex") + print a.listIndex(5) + """ + import new + + if name is None: + name = function.func_name + else: + function = RenameFunction(function, name) + + try: + klass = object.__class__ + except AttributeError: + # "object" is really a class, so it gets an unbound method. + object.__dict__[name] = new.instancemethod(function, None, object) + else: + # "object" is really an instance, so it gets a bound method. + object.__dict__[name] = new.instancemethod(function, object, klass) + +def RenameFunction(function, name): + """ + Returns a function identical to the specified function, but with + the specified name. + """ + import new + + # Compatibility for Python 1.5 and 2.1. Can be removed in favor of + # passing function.func_defaults directly to new.function() once + # we base on Python 2.2 or later. + func_defaults = function.func_defaults + if func_defaults is None: + func_defaults = () + + return new.function(function.func_code, + function.func_globals, + name, + func_defaults) + + +md5 = False +def MD5signature(s): + return str(s) + +try: + import hashlib +except ImportError: + pass +else: + if hasattr(hashlib, 'md5'): + md5 = True + def MD5signature(s): + m = hashlib.md5() + m.update(str(s)) + return m.hexdigest() + +def MD5collect(signatures): + """ + Collects a list of signatures into an aggregate signature. + + signatures - a list of signatures + returns - the aggregate signature + """ + if len(signatures) == 1: + return signatures[0] + else: + return MD5signature(string.join(signatures, ', ')) + + + +# From Dinu C. Gherman, +# Python Cookbook, second edition, recipe 6.17, p. 277. +# Also: +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205 +# ASPN: Python Cookbook: Null Object Design Pattern + +class Null: + """ Null objects always and reliably "do nothging." """ + + def __new__(cls, *args, **kwargs): + if not '_inst' in vars(cls): + #cls._inst = type.__new__(cls, *args, **kwargs) + cls._inst = apply(type.__new__, (cls,) + args, kwargs) + return cls._inst + def __init__(self, *args, **kwargs): + pass + def __call__(self, *args, **kwargs): + return self + def __repr__(self): + return "Null()" + def __nonzero__(self): + return False + def __getattr__(self, mname): + return self + def __setattr__(self, name, value): + return self + def __delattr__(self, name): + return self + + + +del __revision__ diff --git a/scons/scons-local-0.97/SCons/Warnings.py b/scons/scons-local-0.97.0d20071212/SCons/Warnings.py similarity index 96% rename from scons/scons-local-0.97/SCons/Warnings.py rename to scons/scons-local-0.97.0d20071212/SCons/Warnings.py index 890c2784a..eb23b29a0 100644 --- a/scons/scons-local-0.97/SCons/Warnings.py +++ b/scons/scons-local-0.97.0d20071212/SCons/Warnings.py @@ -27,7 +27,7 @@ This file implements the warnings framework for SCons. """ -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Warnings.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/Warnings.py 2523 2007/12/12 09:37:41 knight" import SCons.Errors @@ -64,6 +64,9 @@ class NoMD5ModuleWarning(Warning): class NoMetaclassSupportWarning(Warning): pass +class NoObjectCountWarning(Warning): + pass + class NoParallelSupportWarning(Warning): pass diff --git a/scons/scons-local-0.97/SCons/__init__.py b/scons/scons-local-0.97.0d20071212/SCons/__init__.py similarity index 85% rename from scons/scons-local-0.97/SCons/__init__.py rename to scons/scons-local-0.97.0d20071212/SCons/__init__.py index 00fc647a1..217e1e72b 100644 --- a/scons/scons-local-0.97/SCons/__init__.py +++ b/scons/scons-local-0.97.0d20071212/SCons/__init__.py @@ -27,14 +27,14 @@ The main package for the SCons software construction utility. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/__init__.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/__init__.py 2523 2007/12/12 09:37:41 knight" -__version__ = "0.97" +__version__ = "0.97.0d20071212" -__build__ = "D001" +__build__ = "r2523" -__buildsys__ = "roxbury" +__buildsys__ = "bangkok" -__date__ = "2007/05/17 11:35:19" +__date__ = "2007/12/12 09:37:41" __developer__ = "knight" diff --git a/scons/scons-local-0.97/SCons/compat/__init__.py b/scons/scons-local-0.97.0d20071212/SCons/compat/__init__.py similarity index 65% rename from scons/scons-local-0.97/SCons/compat/__init__.py rename to scons/scons-local-0.97.0d20071212/SCons/compat/__init__.py index f2b8c3995..8220d3420 100644 --- a/scons/scons-local-0.97/SCons/compat/__init__.py +++ b/scons/scons-local-0.97.0d20071212/SCons/compat/__init__.py @@ -60,11 +60,11 @@ _scons_subprocess.py is our compatibility module for subprocess) so that we can still try to import the real module name and fall back to our compatibility module if we get an ImportError. The import_as() function defined below loads the module as the "real" name (without the -underscore), after which all of the "import {module}" statements in the +'_scons'), after which all of the "import {module}" statements in the rest of our code will find our pre-loaded compatibility module. """ -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/compat/__init__.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/compat/__init__.py 2523 2007/12/12 09:37:41 knight" def import_as(module, name): """ @@ -79,6 +79,19 @@ def import_as(module, name): import builtins +try: + import hashlib +except ImportError: + # Pre-2.5 Python has no hashlib module. + try: + import_as('_scons_hashlib', 'hashlib') + except ImportError: + # If we failed importing our compatibility module, it probably + # means this version of Python has no md5 module. Don't do + # anything and let the higher layer discover this fact, so it + # can fall back to using timestamp. + pass + try: set except NameError: @@ -98,6 +111,68 @@ except NameError: import sets __builtin__.set = sets.Set +import fnmatch +try: + fnmatch.filter +except AttributeError: + # Pre-2.2 Python has no fnmatch.filter() function. + def filter(names, pat): + """Return the subset of the list NAMES that match PAT""" + import os,posixpath + result=[] + pat = os.path.normcase(pat) + if not fnmatch._cache.has_key(pat): + import re + res = fnmatch.translate(pat) + fnmatch._cache[pat] = re.compile(res) + match = fnmatch._cache[pat].match + if os.path is posixpath: + # normcase on posix is NOP. Optimize it away from the loop. + for name in names: + if match(name): + result.append(name) + else: + for name in names: + if match(os.path.normcase(name)): + result.append(name) + return result + fnmatch.filter = filter + del filter + + +# If we need the compatibility version of textwrap, it must be imported +# before optparse, which uses it. +try: + import textwrap +except ImportError: + # Pre-2.3 Python has no textwrap module. + import_as('_scons_textwrap', 'textwrap') + +try: + import optparse +except ImportError: + # Pre-2.3 Python has no optparse module. + import_as('_scons_optparse', 'optparse') + +import shlex +try: + shlex.split +except AttributeError: + # Pre-2.3 Python has no shlex.split function. + def split(s, comments=False): + import StringIO + lex = shlex.shlex(StringIO.StringIO(s)) + lex.wordchars = lex.wordchars + '/\\-+,=:' + result = [] + while True: + tt = lex.get_token() + if not tt: + break + result.append(tt) + return result + shlex.split = split + del split + try: import subprocess except ImportError: diff --git a/scons/scons-local-0.97/SCons/compat/_scons_UserString.py b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_UserString.py similarity index 96% rename from scons/scons-local-0.97/SCons/compat/_scons_UserString.py rename to scons/scons-local-0.97.0d20071212/SCons/compat/_scons_UserString.py index 4bf4c8cf9..507d1a175 100644 --- a/scons/scons-local-0.97/SCons/compat/_scons_UserString.py +++ b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_UserString.py @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/compat/_scons_UserString.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/compat/_scons_UserString.py 2523 2007/12/12 09:37:41 knight" __doc__ = """ A user-defined wrapper around string objects diff --git a/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_hashlib.py b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_hashlib.py new file mode 100644 index 000000000..d972827a1 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_hashlib.py @@ -0,0 +1,85 @@ +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation +# +# 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. +# + +__doc__ = """ +hashlib backwards-compatibility module for older (pre-2.5) Python versions + +This does not not NOT (repeat, *NOT*) provide complete hashlib +functionality. It only wraps the portions of MD5 functionality used +by SCons, in an interface that looks like hashlib (or enough for our +purposes, anyway). In fact, this module will raise an ImportError if +the underlying md5 module isn't available. +""" + +__revision__ = "src/engine/SCons/compat/_scons_hashlib.py 2523 2007/12/12 09:37:41 knight" + +import md5 +import string + +class md5obj: + + md5_module = md5 + + def __init__(self, name, string=''): + if not name in ('MD5', 'md5'): + raise ValueError, "unsupported hash type" + self.name = 'md5' + self.m = self.md5_module.md5() + + def __repr__(self): + return '<%s HASH object @ %#x>' % (self.name, id(self)) + + def copy(self): + import copy + result = copy.copy(self) + result.m = self.m.copy() + return result + + def digest(self): + return self.m.digest() + + def update(self, arg): + return self.m.update(arg) + + if hasattr(md5.md5(), 'hexdigest'): + + def hexdigest(self): + return self.m.hexdigest() + + else: + + # Objects created by the underlying md5 module have no native + # hexdigest() method (*cough* 1.5.2 *cough*), so provide an + # equivalent lifted from elsewhere. + def hexdigest(self): + h = string.hexdigits + r = '' + for c in self.digest(): + i = ord(c) + r = r + h[(i >> 4) & 0xF] + h[i & 0xF] + return r + +new = md5obj + +def md5(string=''): + return md5obj('md5', string) diff --git a/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_optparse.py b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_optparse.py new file mode 100644 index 000000000..6b376875e --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_optparse.py @@ -0,0 +1,1719 @@ +"""optparse - a powerful, extensible, and easy-to-use option parser. + +By Greg Ward + +Originally distributed as Optik; see http://optik.sourceforge.net/ . + +If you have problems with this module, please do not file bugs, +patches, or feature requests with Python; instead, use Optik's +SourceForge project page: + http://sourceforge.net/projects/optik + +For support, use the optik-users@lists.sourceforge.net mailing list +(http://lists.sourceforge.net/lists/listinfo/optik-users). +""" + +# Python developers: please do not make changes to this file, since +# it is automatically generated from the Optik source code. + +__version__ = "1.5.3" + +__all__ = ['Option', + 'SUPPRESS_HELP', + 'SUPPRESS_USAGE', + 'Values', + 'OptionContainer', + 'OptionGroup', + 'OptionParser', + 'HelpFormatter', + 'IndentedHelpFormatter', + 'TitledHelpFormatter', + 'OptParseError', + 'OptionError', + 'OptionConflictError', + 'OptionValueError', + 'BadOptionError'] + +__copyright__ = """ +Copyright (c) 2001-2006 Gregory P. Ward. All rights reserved. +Copyright (c) 2002-2006 Python Software Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +import string +import sys, os +import types +import textwrap + +def _repr(self): + return "<%s at 0x%x: %s>" % (self.__class__.__name__, id(self), self) + + +try: + sys.getdefaultencoding +except AttributeError: + def fake_getdefaultencoding(): + return None + sys.getdefaultencoding = fake_getdefaultencoding + +try: + ''.encode +except AttributeError: + def encode_wrapper(s, encoding, replacement): + return s +else: + def encode_wrapper(s, encoding, replacement): + return s.encode(encoding, replacement) + + +# This file was generated from: +# Id: option_parser.py 527 2006-07-23 15:21:30Z greg +# Id: option.py 522 2006-06-11 16:22:03Z gward +# Id: help.py 527 2006-07-23 15:21:30Z greg +# Id: errors.py 509 2006-04-20 00:58:24Z gward + +try: + from gettext import gettext +except ImportError: + def gettext(message): + return message +_ = gettext + + +class OptParseError (Exception): + def __init__(self, msg): + self.msg = msg + + def __str__(self): + return self.msg + + +class OptionError (OptParseError): + """ + 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 (OptParseError): + """ + Raised if an invalid option value is encountered on the command + line. + """ + +class BadOptionError (OptParseError): + """ + Raised if an invalid option is seen on the command line. + """ + def __init__(self, opt_str): + self.opt_str = opt_str + + def __str__(self): + return _("no such option: %s") % self.opt_str + +class AmbiguousOptionError (BadOptionError): + """ + Raised if an ambiguous option is seen on the command line. + """ + def __init__(self, opt_str, possibilities): + BadOptionError.__init__(self, opt_str) + self.possibilities = possibilities + + def __str__(self): + return (_("ambiguous option: %s (%s?)") + % (self.opt_str, string.join(self.possibilities, ", "))) + + +class HelpFormatter: + + """ + Abstract base class for formatting option help. OptionParser + instances should use one of the HelpFormatter subclasses for + formatting help; by default IndentedHelpFormatter is used. + + Instance attributes: + parser : OptionParser + the controlling OptionParser instance + indent_increment : int + the number of columns to indent per nesting level + max_help_position : int + the maximum starting column for option help text + help_position : int + the calculated starting column for option help text; + initially the same as the maximum + width : int + total number of columns for output (pass None to constructor for + this value to be taken from the $COLUMNS environment variable) + level : int + current indentation level + current_indent : int + current indentation level (in columns) + help_width : int + number of columns available for option help text (calculated) + default_tag : str + text to replace with each option's default value, "%default" + by default. Set to false value to disable default value expansion. + option_strings : { Option : str } + maps Option instances to the snippet of help text explaining + the syntax of that option, e.g. "-h, --help" or + "-fFILE, --file=FILE" + _short_opt_fmt : str + format string controlling how short options with values are + printed in help text. Must be either "%s%s" ("-fFILE") or + "%s %s" ("-f FILE"), because those are the two syntaxes that + Optik supports. + _long_opt_fmt : str + similar but for long options; must be either "%s %s" ("--file FILE") + or "%s=%s" ("--file=FILE"). + """ + + NO_DEFAULT_VALUE = "none" + + def __init__(self, + indent_increment, + max_help_position, + width, + short_first): + self.parser = None + self.indent_increment = indent_increment + self.help_position = self.max_help_position = max_help_position + if width is None: + try: + width = int(os.environ['COLUMNS']) + except (KeyError, ValueError): + width = 80 + width = width - 2 + self.width = width + self.current_indent = 0 + self.level = 0 + self.help_width = None # computed later + self.short_first = short_first + self.default_tag = "%default" + self.option_strings = {} + self._short_opt_fmt = "%s %s" + self._long_opt_fmt = "%s=%s" + + def set_parser(self, parser): + self.parser = parser + + def set_short_opt_delimiter(self, delim): + if delim not in ("", " "): + raise ValueError( + "invalid metavar delimiter for short options: %r" % delim) + self._short_opt_fmt = "%s" + delim + "%s" + + def set_long_opt_delimiter(self, delim): + if delim not in ("=", " "): + raise ValueError( + "invalid metavar delimiter for long options: %r" % delim) + self._long_opt_fmt = "%s" + delim + "%s" + + def indent(self): + self.current_indent = self.current_indent + self.indent_increment + self.level = self.level + 1 + + def dedent(self): + self.current_indent = self.current_indent - self.indent_increment + assert self.current_indent >= 0, "Indent decreased below 0." + self.level = self.level - 1 + + def format_usage(self, usage): + raise NotImplementedError, "subclasses must implement" + + def format_heading(self, heading): + raise NotImplementedError, "subclasses must implement" + + def _format_text(self, text): + """ + Format a paragraph of free-form text for inclusion in the + help output at the current indentation level. + """ + text_width = self.width - self.current_indent + indent = " "*self.current_indent + return textwrap.fill(text, + text_width, + initial_indent=indent, + subsequent_indent=indent) + + def format_description(self, description): + if description: + return self._format_text(description) + "\n" + else: + return "" + + def format_epilog(self, epilog): + if epilog: + return "\n" + self._format_text(epilog) + "\n" + else: + return "" + + + def expand_default(self, option): + if self.parser is None or not self.default_tag: + return option.help + + default_value = self.parser.defaults.get(option.dest) + if default_value is NO_DEFAULT or default_value is None: + default_value = self.NO_DEFAULT_VALUE + + return string.replace(option.help, self.default_tag, str(default_value)) + + def format_option(self, option): + # 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 + result = [] + opts = self.option_strings[option] + opt_width = self.help_position - self.current_indent - 2 + if len(opts) > opt_width: + opts = "%*s%s\n" % (self.current_indent, "", opts) + indent_first = self.help_position + else: # start help on same line as opts + opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts) + indent_first = 0 + result.append(opts) + if option.help: + help_text = self.expand_default(option) + help_lines = textwrap.wrap(help_text, self.help_width) + result.append("%*s%s\n" % (indent_first, "", help_lines[0])) + for line in help_lines[1:]: + result.append("%*s%s\n" % (self.help_position, "", line)) + elif opts[-1] != "\n": + result.append("\n") + return string.join(result, "") + + def store_option_strings(self, parser): + self.indent() + max_len = 0 + for opt in parser.option_list: + strings = self.format_option_strings(opt) + self.option_strings[opt] = strings + max_len = max(max_len, len(strings) + self.current_indent) + self.indent() + for group in parser.option_groups: + for opt in group.option_list: + strings = self.format_option_strings(opt) + self.option_strings[opt] = strings + max_len = max(max_len, len(strings) + self.current_indent) + self.dedent() + self.dedent() + self.help_position = min(max_len + 2, self.max_help_position) + self.help_width = self.width - self.help_position + + def format_option_strings(self, option): + """Return a comma-separated list of option strings & metavariables.""" + if option.takes_value(): + metavar = option.metavar or string.upper(option.dest) + short_opts = [] + for sopt in option._short_opts: + short_opts.append(self._short_opt_fmt % (sopt, metavar)) + long_opts = [] + for lopt in option._long_opts: + long_opts.append(self._long_opt_fmt % (lopt, metavar)) + else: + short_opts = option._short_opts + long_opts = option._long_opts + + if self.short_first: + opts = short_opts + long_opts + else: + opts = long_opts + short_opts + + return string.join(opts, ", ") + +class IndentedHelpFormatter (HelpFormatter): + """Format help with indented section bodies. + """ + + def __init__(self, + indent_increment=2, + max_help_position=24, + width=None, + short_first=1): + HelpFormatter.__init__( + self, indent_increment, max_help_position, width, short_first) + + def format_usage(self, usage): + return _("Usage: %s\n") % usage + + def format_heading(self, heading): + return "%*s%s:\n" % (self.current_indent, "", heading) + + +class TitledHelpFormatter (HelpFormatter): + """Format help with underlined section headers. + """ + + def __init__(self, + indent_increment=0, + max_help_position=24, + width=None, + short_first=0): + HelpFormatter.__init__ ( + self, indent_increment, max_help_position, width, short_first) + + def format_usage(self, usage): + return "%s %s\n" % (self.format_heading(_("Usage")), usage) + + def format_heading(self, heading): + return "%s\n%s\n" % (heading, "=-"[self.level] * len(heading)) + + +def _parse_num(val, type): + if string.lower(val[:2]) == "0x": # hexadecimal + radix = 16 + elif string.lower(val[:2]) == "0b": # binary + radix = 2 + val = val[2:] or "0" # have to remove "0b" prefix + elif val[:1] == "0": # octal + radix = 8 + else: # decimal + radix = 10 + + return type(val, radix) + +def _parse_int(val): + return _parse_num(val, int) + +def _parse_long(val): + return _parse_num(val, long) + +try: + int('0', 10) +except TypeError: + # Python 1.5.2 doesn't allow a radix value to be passed to int(). + _parse_int = int + +try: + long('0', 10) +except TypeError: + # Python 1.5.2 doesn't allow a radix value to be passed to long(). + _parse_long = long + +_builtin_cvt = { "int" : (_parse_int, _("integer")), + "long" : (_parse_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( + _("option %s: invalid %s value: %r") % (opt, what, 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: %r (choose from %s)") + % (opt, 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", + "append_const", + "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", + "append_const", + "count") + + # The set of actions for which it makes sense to supply a value + # type, ie. which may consume an argument from the command line. + TYPED_ACTIONS = ("store", + "append", + "callback") + + # The set of actions which *require* a value type, ie. that + # always consume an argument from the command line. + ALWAYS_TYPED_ACTIONS = ("store", + "append") + + # The set of actions which take a 'const' attribute. + CONST_ACTIONS = ("store_const", + "append_const") + + # 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. + # Have to be set now, in case no option strings are supplied. + self._short_opts = [] + self._long_opts = [] + 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 TypeError("at least one option string must be supplied") + return opts + + def _set_opt_strings(self, opts): + for opt in opts: + if len(opt) < 2: + raise OptionError( + "invalid option string %r: " + "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 %r: " + "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 %r: " + "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: + attrs = attrs.keys() + attrs.sort() + raise OptionError( + "invalid keyword arguments: %s" % string.join(attrs, ", "), + 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: %r" % self.action, self) + + def _check_type(self): + if self.type is None: + if self.action in self.ALWAYS_TYPED_ACTIONS: + 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: + # Allow type objects or builtin type conversion functions + # (int, str, etc.) as an alternative to their names. (The + # complicated check of __builtin__ is only necessary for + # Python 2.1 and earlier, and is short-circuited by the + # first check on modern Pythons.) + import __builtin__ + if ( type(self.type) is types.TypeType or + (hasattr(self.type, "__name__") and + getattr(__builtin__, self.type.__name__, None) is self.type) ): + self.type = self.type.__name__ + + if self.type == "str": + self.type = "string" + + if self.type not in self.TYPES: + raise OptionError("invalid option type: %r" % self.type, self) + if self.action not in self.TYPED_ACTIONS: + raise OptionError( + "must not supply a type for action %r" % 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 (types.TupleType, types.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 %r" % self.type, self) + + def _check_dest(self): + # No destination given, and we need one for this action. The + # self.type check is for callbacks that take a value. + takes_value = (self.action in self.STORE_ACTIONS or + self.type is not None) + if self.dest is None and takes_value: + + # 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 not in self.CONST_ACTIONS and self.const is not None: + raise OptionError( + "'const' must not be supplied for action %r" % 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 %r" % self.action, + self) + + def _check_callback(self): + if self.action == "callback": + if not callable(self.callback): + raise OptionError( + "callback not callable: %r" % self.callback, self) + if (self.callback_args is not None and + type(self.callback_args) is not types.TupleType): + raise OptionError( + "callback_args, if supplied, must be a tuple: not %r" + % self.callback_args, self) + if (self.callback_kwargs is not None and + type(self.callback_kwargs) is not types.DictType): + raise OptionError( + "callback_kwargs, if supplied, must be a dict: not %r" + % self.callback_kwargs, self) + else: + if self.callback is not None: + raise OptionError( + "callback supplied (%r) for non-callback option" + % 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): + return string.join(self._short_opts + self._long_opts, "/") + + __repr__ = _repr + + def takes_value(self): + return self.type is not None + + def get_opt_string(self): + if self._long_opts: + return self._long_opts[0] + else: + return self._short_opts[0] + + + # -- 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 convert_value(self, opt, value): + if value is not None: + if self.nargs == 1: + return self.check_value(opt, value) + else: + return tuple(map(lambda v, o=opt, s=self: s.check_value(o, v), value)) + + def process(self, opt, value, values, parser): + + # First, convert the value(s) to the right type. Howl if any + # value(s) are bogus. + value = self.convert_value(opt, 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, True) + elif action == "store_false": + setattr(values, dest, False) + elif action == "append": + values.ensure_value(dest, []).append(value) + elif action == "append_const": + values.ensure_value(dest, []).append(self.const) + 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() + parser.exit() + elif action == "version": + parser.print_version() + parser.exit() + else: + raise RuntimeError, "unknown action %r" % self.action + + return 1 + +# class Option + + +SUPPRESS_HELP = "SUPPRESS"+"HELP" +SUPPRESS_USAGE = "SUPPRESS"+"USAGE" + +# For compatibility with Python 2.2 +try: + True, False +except NameError: + (True, False) = (1, 0) + +try: + types.UnicodeType +except AttributeError: + def isbasestring(x): + return isinstance(x, types.StringType) +else: + def isbasestring(x): + return isinstance(x, types.StringType) or isinstance(x, types.UnicodeType) + +class Values: + + def __init__(self, defaults=None): + if defaults: + for (attr, val) in defaults.items(): + setattr(self, attr, val) + + def __str__(self): + return str(self.__dict__) + + __repr__ = _repr + + def __cmp__(self, other): + if isinstance(other, Values): + return cmp(self.__dict__, other.__dict__) + elif isinstance(other, types.DictType): + return cmp(self.__dict__, other) + else: + return -1 + + 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: %r" % 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 OptionContainer: + + """ + Abstract base class. + + 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: + option_list : [Option] + the list of Option objects contained by this OptionContainer + _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. [1] + _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. [1] + defaults : { string : any } + dictionary mapping option destination names to default + values for each destination [1] + + [1] These mappings are common to (shared by) all components of the + controlling OptionParser, where they are initially created. + + """ + + def __init__(self, option_class, conflict_handler, description): + # Initialize the option list and related data structures. + # This method must be provided by subclasses, and it must + # initialize at least the following instance attributes: + # option_list, _short_opt, _long_opt, defaults. + self._create_option_list() + + self.option_class = option_class + self.set_conflict_handler(conflict_handler) + self.set_description(description) + + def _create_option_mappings(self): + # For use by OptionParser constructor -- create the master + # option mappings used by this OptionParser and all + # OptionGroups that it owns. + self._short_opt = {} # single letter -> Option instance + self._long_opt = {} # long option -> Option instance + self.defaults = {} # maps option dest -> default value + + + def _share_option_mappings(self, parser): + # For use by OptionGroup constructor -- use shared option + # mappings from the OptionParser that owns this OptionGroup. + self._short_opt = parser._short_opt + self._long_opt = parser._long_opt + self.defaults = parser.defaults + + def set_conflict_handler(self, handler): + if handler not in ("error", "resolve"): + raise ValueError, "invalid conflict_resolution value %r" % handler + self.conflict_handler = handler + + def set_description(self, description): + self.description = description + + def get_description(self): + return self.description + + + def destroy(self): + """see OptionParser.destroy().""" + del self._short_opt + del self._long_opt + del 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 == "error": + raise OptionConflictError( + "conflicting option string(s): %s" + % string.join(map(lambda co: co[0], conflict_opts), ", "), + option) + elif handler == "resolve": + for (opt, c_option) in conflict_opts: + if 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): + c_option.container.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: %r" % option + else: + raise TypeError, "invalid arguments" + + self._check_conflict(option) + + self.option_list.append(option) + option.container = self + 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 + + return option + + 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 %r" % opt_str) + + for opt in option._short_opts: + del self._short_opt[opt] + for opt in option._long_opts: + del self._long_opt[opt] + option.container.option_list.remove(option) + + + # -- Help-formatting methods --------------------------------------- + + def format_option_help(self, formatter): + if not self.option_list: + return "" + result = [] + for option in self.option_list: + if not option.help is SUPPRESS_HELP: + result.append(formatter.format_option(option)) + return string.join(result, "") + + def format_description(self, formatter): + return formatter.format_description(self.get_description()) + + def format_help(self, formatter): + result = [] + if self.description: + result.append(self.format_description(formatter)) + if self.option_list: + result.append(self.format_option_help(formatter)) + return string.join(result, "\n") + + +class OptionGroup (OptionContainer): + + def __init__(self, parser, title, description=None): + self.parser = parser + OptionContainer.__init__( + self, parser.option_class, parser.conflict_handler, description) + self.title = title + + def _create_option_list(self): + self.option_list = [] + self._share_option_mappings(self.parser) + + def set_title(self, title): + self.title = title + + def destroy(self): + """see OptionParser.destroy().""" + OptionContainer.destroy(self) + del self.option_list + + # -- Help-formatting methods --------------------------------------- + + def format_help(self, formatter): + result = formatter.format_heading(self.title) + formatter.indent() + result = result + OptionContainer.format_help(self, formatter) + formatter.dedent() + return result + + +class OptionParser (OptionContainer): + + """ + 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 (self.prog or os.path.basename(sys.argv[0])). + prog : string + the name of the current program (to override + os.path.basename(sys.argv[0])). + epilog : string + paragraph of help text to print after option help + + option_groups : [OptionGroup] + list of option groups in this parser (option groups are + irrelevant for parsing the command-line, but very useful + for generating help) + + allow_interspersed_args : bool = 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.) + + process_default_values : bool = true + if true, option default values are processed similarly to option + values from the command line: that is, they are passed to the + type-checking function for the option's type (as long as the + default value is a string). (This really only matters if you + have defined custom types; see SF bug #955889.) Set it to false + to restore the behaviour of Optik 1.4.1 and earlier. + + 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", + description=None, + formatter=None, + add_help_option=True, + prog=None, + epilog=None): + OptionContainer.__init__( + self, option_class, conflict_handler, description) + self.set_usage(usage) + self.prog = prog + self.version = version + self.allow_interspersed_args = True + self.process_default_values = True + if formatter is None: + formatter = IndentedHelpFormatter() + self.formatter = formatter + self.formatter.set_parser(self) + self.epilog = epilog + + # Populate the option list; initial sources are the + # standard_option_list class attribute, the 'option_list' + # argument, and (if applicable) the _add_version_option() and + # _add_help_option() methods. + self._populate_option_list(option_list, + add_help=add_help_option) + + self._init_parsing_state() + + + def destroy(self): + """ + Declare that you are done with this OptionParser. This cleans up + reference cycles so the OptionParser (and all objects referenced by + it) can be garbage-collected promptly. After calling destroy(), the + OptionParser is unusable. + """ + OptionContainer.destroy(self) + for group in self.option_groups: + group.destroy() + del self.option_list + del self.option_groups + del self.formatter + + + # -- Private methods ----------------------------------------------- + # (used by our or OptionContainer's constructor) + + def _create_option_list(self): + self.option_list = [] + self.option_groups = [] + self._create_option_mappings() + + def _add_help_option(self): + self.add_option("-h", "--help", + action="help", + help=_("show this help message and exit")) + + def _add_version_option(self): + self.add_option("--version", + action="version", + help=_("show program's version number and exit")) + + def _populate_option_list(self, option_list, add_help=True): + if self.standard_option_list: + self.add_options(self.standard_option_list) + if option_list: + self.add_options(option_list) + if self.version: + self._add_version_option() + if add_help: + self._add_help_option() + + 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 = _("%prog [options]") + elif usage is SUPPRESS_USAGE: + self.usage = None + # For backwards compatibility with Optik 1.3 and earlier. + elif string.lower(usage)[:7] == "usage: ": + self.usage = usage[7:] + else: + self.usage = usage + + def enable_interspersed_args(self): + self.allow_interspersed_args = True + + def disable_interspersed_args(self): + self.allow_interspersed_args = False + + def set_process_default_values(self, process): + self.process_default_values = process + + def set_default(self, dest, value): + self.defaults[dest] = value + + def set_defaults(self, **kwargs): + self.defaults.update(kwargs) + + def _get_all_options(self): + options = self.option_list[:] + for group in self.option_groups: + options.extend(group.option_list) + return options + + def get_default_values(self): + if not self.process_default_values: + # Old, pre-Optik 1.5 behaviour. + return Values(self.defaults) + + defaults = self.defaults.copy() + for option in self._get_all_options(): + default = defaults.get(option.dest) + if isbasestring(default): + opt_str = option.get_opt_string() + defaults[option.dest] = option.check_value(opt_str, default) + + return Values(defaults) + + + # -- OptionGroup methods ------------------------------------------- + + def add_option_group(self, *args, **kwargs): + # XXX lots of overlap with OptionContainer.add_option() + if type(args[0]) is types.StringType: + group = apply(OptionGroup, (self,) + args, kwargs) + elif len(args) == 1 and not kwargs: + group = args[0] + if not isinstance(group, OptionGroup): + raise TypeError, "not an OptionGroup instance: %r" % group + if group.parser is not self: + raise ValueError, "invalid OptionGroup (wrong parser)" + else: + raise TypeError, "invalid arguments" + + self.option_groups.append(group) + return group + + def get_option_group(self, opt_str): + option = (self._short_opt.get(opt_str) or + self._long_opt.get(opt_str)) + if option and option.container is not self: + return option.container + return None + + + # -- 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(str(err)) + + 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 = True + else: + opt = arg + had_explicit_value = False + + 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 an argument") % opt) + else: + self.error(_("%s option requires %d arguments") + % (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 = False + 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: + raise BadOptionError(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 = True + + nargs = option.nargs + if len(rargs) < nargs: + if nargs == 1: + self.error(_("%s option requires an argument") % opt) + else: + self.error(_("%s option requires %d arguments") + % (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 + + + # -- Feedback methods ---------------------------------------------- + + def get_prog_name(self): + if self.prog is None: + return os.path.basename(sys.argv[0]) + else: + return self.prog + + def expand_prog_name(self, s): + return string.replace(s, "%prog", self.get_prog_name()) + + def get_description(self): + return self.expand_prog_name(self.description) + + def exit(self, status=0, msg=None): + if msg: + sys.stderr.write(msg) + sys.exit(status) + + 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) + self.exit(2, "%s: error: %s\n" % (self.get_prog_name(), msg)) + + def get_usage(self): + if self.usage: + return self.formatter.format_usage( + self.expand_prog_name(self.usage)) + else: + return "" + + 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 self.usage: + file.write(self.get_usage() + '\n') + + def get_version(self): + if self.version: + return self.expand_prog_name(self.version) + else: + return "" + + 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 self.version: + file.write(self.get_version() + '\n') + + def format_option_help(self, formatter=None): + if formatter is None: + formatter = self.formatter + formatter.store_option_strings(self) + result = [] + result.append(formatter.format_heading(_("Options"))) + formatter.indent() + if self.option_list: + result.append(OptionContainer.format_option_help(self, formatter)) + result.append("\n") + for group in self.option_groups: + result.append(group.format_help(formatter)) + result.append("\n") + formatter.dedent() + # Drop the last "\n", or the header if no options or option groups: + return string.join(result[:-1], "") + + def format_epilog(self, formatter): + return formatter.format_epilog(self.epilog) + + def format_help(self, formatter=None): + if formatter is None: + formatter = self.formatter + result = [] + if self.usage: + result.append(self.get_usage() + "\n") + if self.description: + result.append(self.format_description(formatter) + "\n") + result.append(self.format_option_help(formatter)) + result.append(self.format_epilog(formatter)) + return string.join(result, "") + + # used by test suite + def _get_encoding(self, file): + encoding = getattr(file, "encoding", None) + if not encoding: + encoding = sys.getdefaultencoding() + return encoding + + 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). + """ + if file is None: + file = sys.stdout + encoding = self._get_encoding(file) + file.write(encode_wrapper(self.format_help(), encoding, "replace")) + +# 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 = filter(lambda w, s=s: w[:len(s)] == s, wordmap.keys()) + # No exact match, so there had better be just one possibility. + if len(possibilities) == 1: + return possibilities[0] + elif not possibilities: + raise BadOptionError(s) + else: + # More than one possible completion: ambiguous prefix. + possibilities.sort() + raise AmbiguousOptionError(s, possibilities) + + +# 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/scons/scons-local-0.97/SCons/compat/_scons_sets.py b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_sets.py similarity index 100% rename from scons/scons-local-0.97/SCons/compat/_scons_sets.py rename to scons/scons-local-0.97.0d20071212/SCons/compat/_scons_sets.py diff --git a/scons/scons-local-0.97/SCons/compat/_scons_sets15.py b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_sets15.py similarity index 100% rename from scons/scons-local-0.97/SCons/compat/_scons_sets15.py rename to scons/scons-local-0.97.0d20071212/SCons/compat/_scons_sets15.py diff --git a/scons/scons-local-0.97/SCons/compat/_scons_subprocess.py b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_subprocess.py similarity index 99% rename from scons/scons-local-0.97/SCons/compat/_scons_subprocess.py rename to scons/scons-local-0.97.0d20071212/SCons/compat/_scons_subprocess.py index df7e7027f..4cb9e3032 100644 --- a/scons/scons-local-0.97/SCons/compat/_scons_subprocess.py +++ b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_subprocess.py @@ -373,7 +373,13 @@ class CalledProcessError(Exception): if mswindows: - import threading + try: + import threading + except ImportError: + # SCons: the threading module is only used by the communicate() + # method, which we don't actually use, so don't worry if we + # can't import it. + pass import msvcrt if 0: # <-- change this to use pywin32 instead of the _subprocess driver import pywintypes diff --git a/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_textwrap.py b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_textwrap.py new file mode 100644 index 000000000..1e0e41189 --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/SCons/compat/_scons_textwrap.py @@ -0,0 +1,373 @@ +"""Text wrapping and filling. +""" + +# Copyright (C) 1999-2001 Gregory P. Ward. +# Copyright (C) 2002, 2003 Python Software Foundation. +# Written by Greg Ward + +__revision__ = "$Id: textwrap.py,v 1.32.8.2 2004/05/13 01:48:15 gward Exp $" + +import string, re + +try: + unicode +except NameError: + class unicode: + pass + +# Do the right thing with boolean values for all known Python versions +# (so this module can be copied to projects that don't depend on Python +# 2.3, e.g. Optik and Docutils). +try: + True, False +except NameError: + (True, False) = (1, 0) + +__all__ = ['TextWrapper', 'wrap', 'fill'] + +# Hardcode the recognized whitespace characters to the US-ASCII +# whitespace characters. The main reason for doing this is that in +# ISO-8859-1, 0xa0 is non-breaking whitespace, so in certain locales +# that character winds up in string.whitespace. Respecting +# string.whitespace in those cases would 1) make textwrap treat 0xa0 the +# same as any other whitespace char, which is clearly wrong (it's a +# *non-breaking* space), 2) possibly cause problems with Unicode, +# since 0xa0 is not in range(128). +_whitespace = '\t\n\x0b\x0c\r ' + +class TextWrapper: + """ + Object for wrapping/filling text. The public interface consists of + the wrap() and fill() methods; the other methods are just there for + subclasses to override in order to tweak the default behaviour. + If you want to completely replace the main wrapping algorithm, + you'll probably have to override _wrap_chunks(). + + Several instance attributes control various aspects of wrapping: + width (default: 70) + the maximum width of wrapped lines (unless break_long_words + is false) + initial_indent (default: "") + string that will be prepended to the first line of wrapped + output. Counts towards the line's width. + subsequent_indent (default: "") + string that will be prepended to all lines save the first + of wrapped output; also counts towards each line's width. + expand_tabs (default: true) + Expand tabs in input text to spaces before further processing. + Each tab will become 1 .. 8 spaces, depending on its position in + its line. If false, each tab is treated as a single character. + replace_whitespace (default: true) + Replace all whitespace characters in the input text by spaces + after tab expansion. Note that if expand_tabs is false and + replace_whitespace is true, every tab will be converted to a + single space! + fix_sentence_endings (default: false) + Ensure that sentence-ending punctuation is always followed + by two spaces. Off by default because the algorithm is + (unavoidably) imperfect. + break_long_words (default: true) + Break words longer than 'width'. If false, those words will not + be broken, and some lines might be longer than 'width'. + """ + + whitespace_trans = string.maketrans(_whitespace, ' ' * len(_whitespace)) + + unicode_whitespace_trans = {} + try: + uspace = eval("ord(u' ')") + except SyntaxError: + # Python1.5 doesn't understand u'' syntax, in which case we + # won't actually use the unicode translation below, so it + # doesn't matter what value we put in the table. + uspace = ord(' ') + for x in map(ord, _whitespace): + unicode_whitespace_trans[x] = uspace + + # This funky little regex is just the trick for splitting + # text up into word-wrappable chunks. E.g. + # "Hello there -- you goof-ball, use the -b option!" + # splits into + # Hello/ /there/ /--/ /you/ /goof-/ball,/ /use/ /the/ /-b/ /option! + # (after stripping out empty strings). + wordsep_re = re.compile(r'(\s+|' # any whitespace + r'-*\w{2,}-(?=\w{2,}))') # hyphenated words + # Earlier Python's don't have the (?<= + # negative look-behind assertion. It doesn't + # matter for the simple input SCons is going to + # give it, so just comment it out. + #r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash + + # XXX will there be a locale-or-charset-aware version of + # string.lowercase in 2.3? + sentence_end_re = re.compile(r'[%s]' # lowercase letter + r'[\.\!\?]' # sentence-ending punct. + r'[\"\']?' # optional end-of-quote + % string.lowercase) + + + def __init__(self, + width=70, + initial_indent="", + subsequent_indent="", + expand_tabs=True, + replace_whitespace=True, + fix_sentence_endings=False, + break_long_words=True): + self.width = width + self.initial_indent = initial_indent + self.subsequent_indent = subsequent_indent + self.expand_tabs = expand_tabs + self.replace_whitespace = replace_whitespace + self.fix_sentence_endings = fix_sentence_endings + self.break_long_words = break_long_words + + + # -- Private methods ----------------------------------------------- + # (possibly useful for subclasses to override) + + def _munge_whitespace(self, text): + """_munge_whitespace(text : string) -> string + + Munge whitespace in text: expand tabs and convert all other + whitespace characters to spaces. Eg. " foo\tbar\n\nbaz" + becomes " foo bar baz". + """ + if self.expand_tabs: + text = string.expandtabs(text) + if self.replace_whitespace: + if type(text) == type(''): + text = string.translate(text, self.whitespace_trans) + elif isinstance(text, unicode): + text = string.translate(text, self.unicode_whitespace_trans) + return text + + + def _split(self, text): + """_split(text : string) -> [string] + + Split the text to wrap into indivisible chunks. Chunks are + not quite the same as words; see wrap_chunks() for full + details. As an example, the text + Look, goof-ball -- use the -b option! + breaks into the following chunks: + 'Look,', ' ', 'goof-', 'ball', ' ', '--', ' ', + 'use', ' ', 'the', ' ', '-b', ' ', 'option!' + """ + chunks = self.wordsep_re.split(text) + chunks = filter(None, chunks) + return chunks + + def _fix_sentence_endings(self, chunks): + """_fix_sentence_endings(chunks : [string]) + + Correct for sentence endings buried in 'chunks'. Eg. when the + original text contains "... foo.\nBar ...", munge_whitespace() + and split() will convert that to [..., "foo.", " ", "Bar", ...] + which has one too few spaces; this method simply changes the one + space to two. + """ + i = 0 + pat = self.sentence_end_re + while i < len(chunks)-1: + if chunks[i+1] == " " and pat.search(chunks[i]): + chunks[i+1] = " " + i = i + 2 + else: + i = i + 1 + + def _handle_long_word(self, chunks, cur_line, cur_len, width): + """_handle_long_word(chunks : [string], + cur_line : [string], + cur_len : int, width : int) + + Handle a chunk of text (most likely a word, not whitespace) that + is too long to fit in any line. + """ + space_left = max(width - cur_len, 1) + + # If we're allowed to break long words, then do so: put as much + # of the next chunk onto the current line as will fit. + if self.break_long_words: + cur_line.append(chunks[0][0:space_left]) + chunks[0] = chunks[0][space_left:] + + # Otherwise, we have to preserve the long word intact. Only add + # it to the current line if there's nothing already there -- + # that minimizes how much we violate the width constraint. + elif not cur_line: + cur_line.append(chunks.pop(0)) + + # If we're not allowed to break long words, and there's already + # text on the current line, do nothing. Next time through the + # main loop of _wrap_chunks(), we'll wind up here again, but + # cur_len will be zero, so the next line will be entirely + # devoted to the long word that we can't handle right now. + + def _wrap_chunks(self, chunks): + """_wrap_chunks(chunks : [string]) -> [string] + + Wrap a sequence of text chunks and return a list of lines of + length 'self.width' or less. (If 'break_long_words' is false, + some lines may be longer than this.) Chunks correspond roughly + to words and the whitespace between them: each chunk is + indivisible (modulo 'break_long_words'), but a line break can + come between any two chunks. Chunks should not have internal + whitespace; ie. a chunk is either all whitespace or a "word". + Whitespace chunks will be removed from the beginning and end of + lines, but apart from that whitespace is preserved. + """ + lines = [] + if self.width <= 0: + raise ValueError("invalid width %r (must be > 0)" % self.width) + + while chunks: + + # Start the list of chunks that will make up the current line. + # cur_len is just the length of all the chunks in cur_line. + cur_line = [] + cur_len = 0 + + # Figure out which static string will prefix this line. + if lines: + indent = self.subsequent_indent + else: + indent = self.initial_indent + + # Maximum width for this line. + width = self.width - len(indent) + + # First chunk on line is whitespace -- drop it, unless this + # is the very beginning of the text (ie. no lines started yet). + if string.strip(chunks[0]) == '' and lines: + del chunks[0] + + while chunks: + l = len(chunks[0]) + + # Can at least squeeze this chunk onto the current line. + if cur_len + l <= width: + cur_line.append(chunks.pop(0)) + cur_len = cur_len + l + + # Nope, this line is full. + else: + break + + # The current line is full, and the next chunk is too big to + # fit on *any* line (not just this one). + if chunks and len(chunks[0]) > width: + self._handle_long_word(chunks, cur_line, cur_len, width) + + # If the last chunk on this line is all whitespace, drop it. + if cur_line and string.strip(cur_line[-1]) == '': + del cur_line[-1] + + # Convert current line back to a string and store it in list + # of all lines (return value). + if cur_line: + lines.append(indent + string.join(cur_line, '')) + + return lines + + + # -- Public interface ---------------------------------------------- + + def wrap(self, text): + """wrap(text : string) -> [string] + + Reformat the single paragraph in 'text' so it fits in lines of + no more than 'self.width' columns, and return a list of wrapped + lines. Tabs in 'text' are expanded with string.expandtabs(), + and all other whitespace characters (including newline) are + converted to space. + """ + text = self._munge_whitespace(text) + indent = self.initial_indent + chunks = self._split(text) + if self.fix_sentence_endings: + self._fix_sentence_endings(chunks) + return self._wrap_chunks(chunks) + + def fill(self, text): + """fill(text : string) -> string + + Reformat the single paragraph in 'text' to fit in lines of no + more than 'self.width' columns, and return a new string + containing the entire wrapped paragraph. + """ + return string.join(self.wrap(text), "\n") + + +# -- Convenience interface --------------------------------------------- + +def wrap(text, width=70, **kwargs): + """Wrap a single paragraph of text, returning a list of wrapped lines. + + Reformat the single paragraph in 'text' so it fits in lines of no + more than 'width' columns, and return a list of wrapped lines. By + default, tabs in 'text' are expanded with string.expandtabs(), and + all other whitespace characters (including newline) are converted to + space. See TextWrapper class for available keyword args to customize + wrapping behaviour. + """ + kw = kwargs.copy() + kw['width'] = width + w = apply(TextWrapper, (), kw) + return w.wrap(text) + +def fill(text, width=70, **kwargs): + """Fill a single paragraph of text, returning a new string. + + Reformat the single paragraph in 'text' to fit in lines of no more + than 'width' columns, and return a new string containing the entire + wrapped paragraph. As with wrap(), tabs are expanded and other + whitespace characters converted to space. See TextWrapper class for + available keyword args to customize wrapping behaviour. + """ + kw = kwargs.copy() + kw['width'] = width + w = apply(TextWrapper, (), kw) + return w.fill(text) + + +# -- Loosely related functionality ------------------------------------- + +def dedent(text): + """dedent(text : string) -> string + + Remove any whitespace than can be uniformly removed from the left + of every line in `text`. + + This can be used e.g. to make triple-quoted strings line up with + the left edge of screen/whatever, while still presenting it in the + source code in indented form. + + For example: + + def test(): + # end first line with \ to avoid the empty line! + s = '''\ + hello + world + ''' + print repr(s) # prints ' hello\n world\n ' + print repr(dedent(s)) # prints 'hello\n world\n' + """ + lines = text.expandtabs().split('\n') + margin = None + for line in lines: + content = line.lstrip() + if not content: + continue + indent = len(line) - len(content) + if margin is None: + margin = indent + else: + margin = min(margin, indent) + + if margin is not None and margin > 0: + for i in range(len(lines)): + lines[i] = lines[i][margin:] + + return string.join(lines, '\n') diff --git a/scons/scons-local-0.97/SCons/compat/builtins.py b/scons/scons-local-0.97.0d20071212/SCons/compat/builtins.py similarity index 83% rename from scons/scons-local-0.97/SCons/compat/builtins.py rename to scons/scons-local-0.97.0d20071212/SCons/compat/builtins.py index 7a0a2a82f..9b834314d 100644 --- a/scons/scons-local-0.97/SCons/compat/builtins.py +++ b/scons/scons-local-0.97.0d20071212/SCons/compat/builtins.py @@ -35,6 +35,8 @@ the earliest ones we support. This module checks for the following __builtin__ names: + all() + any() bool() dict() True @@ -53,10 +55,40 @@ the FUNCTIONS or DATA output, that means those names are already built in to this version of Python and we don't need to add them from this module. """ -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/compat/builtins.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/compat/builtins.py 2523 2007/12/12 09:37:41 knight" import __builtin__ +try: + all +except NameError: + # Pre-2.5 Python has no all() function. + def all(iterable): + """ + Returns True if all elements of the iterable are true. + """ + for element in iterable: + if not element: + return False + return True + __builtin__.all = all + all = all + +try: + any +except NameError: + # Pre-2.5 Python has no any() function. + def any(iterable): + """ + Returns True if any element of the iterable is true. + """ + for element in iterable: + if element: + return True + return False + __builtin__.any = any + any = any + try: bool except NameError: @@ -76,11 +108,13 @@ try: dict except NameError: # Pre-2.2 Python has no dict() keyword. - def dict(*arg, **kwargs): + def dict(seq=[], **kwargs): """ New dictionary initialization. """ - d = apply(types.DictType, arg) + d = {} + for k, v in seq: + d[k] = v d.update(kwargs) return d __builtin__.dict = dict diff --git a/scons/scons-local-0.97/SCons/cpp.py b/scons/scons-local-0.97.0d20071212/SCons/cpp.py similarity index 99% rename from scons/scons-local-0.97/SCons/cpp.py rename to scons/scons-local-0.97.0d20071212/SCons/cpp.py index 2f0ee4c0b..ce1b5163f 100644 --- a/scons/scons-local-0.97/SCons/cpp.py +++ b/scons/scons-local-0.97.0d20071212/SCons/cpp.py @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/cpp.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/cpp.py 2523 2007/12/12 09:37:41 knight" __doc__ = """ SCons C Pre-Processor module diff --git a/scons/scons-local-0.97/SCons/dblite.py b/scons/scons-local-0.97.0d20071212/SCons/dblite.py similarity index 100% rename from scons/scons-local-0.97/SCons/dblite.py rename to scons/scons-local-0.97.0d20071212/SCons/dblite.py diff --git a/scons/scons-local-0.97/SCons/exitfuncs.py b/scons/scons-local-0.97.0d20071212/SCons/exitfuncs.py similarity index 94% rename from scons/scons-local-0.97/SCons/exitfuncs.py rename to scons/scons-local-0.97.0d20071212/SCons/exitfuncs.py index 9d7ca48c8..4c8fa4f3e 100644 --- a/scons/scons-local-0.97/SCons/exitfuncs.py +++ b/scons/scons-local-0.97.0d20071212/SCons/exitfuncs.py @@ -27,7 +27,7 @@ Register functions which are executed when SCons exits for any reason. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/exitfuncs.py 0.97.D001 2007/05/17 11:35:19 knight" +__revision__ = "src/engine/SCons/exitfuncs.py 2523 2007/12/12 09:37:41 knight" diff --git a/scons/scons-local-0.97.0d20071212/scons-0.97.0d20071212.egg-info b/scons/scons-local-0.97.0d20071212/scons-0.97.0d20071212.egg-info new file mode 100644 index 000000000..604062f4d --- /dev/null +++ b/scons/scons-local-0.97.0d20071212/scons-0.97.0d20071212.egg-info @@ -0,0 +1,13 @@ +Metadata-Version: 1.0 +Name: scons +Version: 0.97.0d20071212 +Summary: Open Source next-generation build tool. +Improved, cross-platform substitute for the classic Make +utility. In short, SCons is an easier, more reliable +and faster way to build software. +Home-page: http://www.scons.org/ +Author: Steven Knight +Author-email: knight@baldmt.com +License: UNKNOWN +Description: UNKNOWN +Platform: UNKNOWN diff --git a/scons/scons-local-0.97/SCons/Optik/__init__.py b/scons/scons-local-0.97/SCons/Optik/__init__.py deleted file mode 100644 index 667ed2318..000000000 --- a/scons/scons-local-0.97/SCons/Optik/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -"""optik - -A powerful, extensible, and easy-to-use command-line parser for Python. - -By Greg Ward - -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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/__init__.py 0.97.D001 2007/05/17 11:35:19 knight" - -# 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/scons/scons-local-0.97/SCons/Optik/errors.py b/scons/scons-local-0.97/SCons/Optik/errors.py deleted file mode 100644 index 4a6ee0643..000000000 --- a/scons/scons-local-0.97/SCons/Optik/errors.py +++ /dev/null @@ -1,55 +0,0 @@ -"""optik.errors - -Exception classes used by Optik. -""" - -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/errors.py 0.97.D001 2007/05/17 11:35:19 knight" - -# 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/scons/scons-local-0.97/SCons/Optik/option.py b/scons/scons-local-0.97/SCons/Optik/option.py deleted file mode 100644 index 04b313e63..000000000 --- a/scons/scons-local-0.97/SCons/Optik/option.py +++ /dev/null @@ -1,388 +0,0 @@ -"""optik.option - -Defines the Option class and some standard value-checking functions. -""" - -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/option.py 0.97.D001 2007/05/17 11:35:19 knight" - -# 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/scons/scons-local-0.97/SCons/Optik/option_parser.py b/scons/scons-local-0.97/SCons/Optik/option_parser.py deleted file mode 100644 index 57c55ac90..000000000 --- a/scons/scons-local-0.97/SCons/Optik/option_parser.py +++ /dev/null @@ -1,730 +0,0 @@ -"""optik.option_parser - -Provides the OptionParser and Values classes. -""" - -__revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/option_parser.py 0.97.D001 2007/05/17 11:35:19 knight" - -# 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). - """ - # SCons: don't import wrap_text from distutils, use the - # copy we've included below, so we can avoid being dependent - # on having the right version of distutils installed. - #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,", "))) - -# SCons: Include a snarfed copy of wrap_text(), so we're not dependent -# on the right version of distutils being installed. -import re - -WS_TRANS = string.maketrans(string.whitespace, ' ' * len(string.whitespace)) - -def wrap_text (text, width): - """wrap_text(text : string, width : int) -> [string] - - Split 'text' into multiple lines of no more than 'width' characters - each, and return the list of strings that results. - """ - - if text is None: - return [] - if len(text) <= width: - return [text] - - text = string.expandtabs(text) - text = string.translate(text, WS_TRANS) - chunks = re.split(r'( +|-+)', text) - chunks = filter(None, chunks) # ' - ' results in empty strings - lines = [] - - while chunks: - - cur_line = [] # list of chunks (to-be-joined) - cur_len = 0 # length of current line - - while chunks: - l = len(chunks[0]) - if cur_len + l <= width: # can squeeze (at least) this chunk in - cur_line.append(chunks[0]) - del chunks[0] - cur_len = cur_len + l - else: # this line is full - # drop last chunk if all space - if cur_line and cur_line[-1][0] == ' ': - del cur_line[-1] - break - - if chunks: # any chunks left to process? - - # if the current line is still empty, then we had a single - # chunk that's too big too fit on a line -- so we break - # down and break it up at the line width - if cur_len == 0: - cur_line.append(chunks[0][0:width]) - chunks[0] = chunks[0][width:] - - # all-whitespace chunks at the end of a line can be discarded - # (and we know from the re.split above that if a chunk has - # *any* whitespace, it is *all* whitespace) - if chunks[0][0] == ' ': - del chunks[0] - - # and store this line in the list-of-all-lines -- as a single - # string, of course! - lines.append(string.join(cur_line, '')) - - # while chunks - - return lines - -# wrap_text () diff --git a/scons/scons-local-0.97/SCons/Sig/MD5.py b/scons/scons-local-0.97/SCons/Sig/MD5.py deleted file mode 100644 index ac521682b..000000000 --- a/scons/scons-local-0.97/SCons/Sig/MD5.py +++ /dev/null @@ -1,104 +0,0 @@ -"""SCons.Sig.MD5 - -The MD5 signature package for the SCons software construction -utility. - -""" - -# -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation -# -# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Sig/MD5.py 0.97.D001 2007/05/17 11:35:19 knight" - -import imp -import string - -# Force Python to load the builtin "md5" module. If we do this with a -# normal import statement, then case-insensitive systems (Windows) get -# confused and thinks there's a case mismatch with *this* MD5.py module. -file, name, desc = imp.find_module('md5') -try: - md5 = imp.load_module('md5', file, name, desc) -finally: - if file: - file.close() - -def current(new, old): - """Return whether a new signature is up-to-date with - respect to an old signature. - """ - return new == old - -try: - md5.new('').hexdigest -except AttributeError: - # The md5 objects created by the module have no native hexdigest() - # method (*cough* 1.5.2 *cough*) so provide an equivalent. - class new_md5: - def __init__(self, s): - self.m = md5.new(str(s)) - #def copy(self): - # return self.m.copy() - def digest(self): - return self.m.digest() - def hexdigest(self): - h = string.hexdigits - r = '' - for c in self.m.digest(): - i = ord(c) - r = r + h[(i >> 4) & 0xF] + h[i & 0xF] - return r - def update(self, s): - return self.m.update(s) - -else: - new_md5 = lambda s: md5.new(str(s)) - -def collect(signatures): - """ - Collect a list of signatures into an aggregate signature. - - signatures - a list of signatures - returns - the aggregate signature - """ - if len(signatures) == 1: - return signatures[0] - else: - return new_md5(string.join(signatures, ', ')).hexdigest() - -def signature(obj): - """Generate a signature for an object - """ - try: - gc = obj.get_contents - except AttributeError: - raise AttributeError, "unable to fetch contents of '%s'" % str(obj) - return new_md5(gc()).hexdigest() - -def to_string(signature): - """Convert a signature to a string""" - return signature - -def from_string(string): - """Convert a string to a signature""" - return string diff --git a/scons/scons-local-0.97/SCons/Sig/TimeStamp.py b/scons/scons-local-0.97/SCons/Sig/TimeStamp.py deleted file mode 100644 index b928dcb61..000000000 --- a/scons/scons-local-0.97/SCons/Sig/TimeStamp.py +++ /dev/null @@ -1,75 +0,0 @@ -"""SCons.Sig.TimeStamp - -The TimeStamp signature package for the SCons software construction -utility. - -""" - -# -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation -# -# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Sig/TimeStamp.py 0.97.D001 2007/05/17 11:35:19 knight" - -def current(new, old): - """Return whether a new timestamp is up-to-date with - respect to an old timestamp. - """ - return not old is None and new <= old - -def collect(signatures): - """ - Collect a list of timestamps, returning - the most-recent timestamp from the list - - signatures - a list of timestamps - returns - the most recent timestamp - """ - - if len(signatures) == 0: - return 0 - elif len(signatures) == 1: - return signatures[0] - else: - return max(signatures) - -def signature(obj): - """Generate a timestamp. - """ - return obj.get_timestamp() - -def to_string(signature): - """Convert a timestamp to a string""" - return str(signature) - -def from_string(string): - """Convert a string to a timestamp""" - try: - return int(string) - except ValueError: - # if the signature isn't an int, then - # the user probably just switched from - # MD5 signatures to timestamp signatures, - # so ignore the error: - return None - - diff --git a/scons/scons-local-0.97/SCons/Tool/javac.py b/scons/scons-local-0.97/SCons/Tool/javac.py deleted file mode 100644 index 506bad43f..000000000 --- a/scons/scons-local-0.97/SCons/Tool/javac.py +++ /dev/null @@ -1,116 +0,0 @@ -"""SCons.Tool.javac - -Tool-specific initialization for javac. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - -# -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation -# -# 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Tool/javac.py 0.97.D001 2007/05/17 11:35:19 knight" - -import os -import os.path -import string - -import SCons.Action -import SCons.Builder -from SCons.Node.FS import _my_normcase -from SCons.Tool.JavaCommon import parse_java_file -import SCons.Util - -def classname(path): - """Turn a string (path name) into a Java class name.""" - return string.replace(os.path.normpath(path), os.sep, '.') - -def emit_java_classes(target, source, env): - """Create and return lists of source java files - and their corresponding target class files. - """ - java_suffix = env.get('JAVASUFFIX', '.java') - class_suffix = env.get('JAVACLASSSUFFIX', '.class') - - slist = [] - js = _my_normcase(java_suffix) - for sdir in source: - def visit(arg, dirname, names, js=js, dirnode=sdir.rdir()): - java_files = filter(lambda n, js=js: - _my_normcase(n[-len(js):]) == js, - names) - # The on-disk entries come back in arbitrary order. Sort them - # so our target and source lists are determinate. - java_files.sort() - mydir = dirnode.Dir(dirname) - java_paths = map(lambda f, d=mydir: d.File(f), java_files) - arg.extend(java_paths) - os.path.walk(sdir.rdir().get_abspath(), visit, slist) - - tlist = [] - for f in slist: - pkg_dir, classes = parse_java_file(f.get_abspath()) - if pkg_dir: - for c in classes: - t = target[0].Dir(pkg_dir).File(c+class_suffix) - t.attributes.java_classdir = target[0] - t.attributes.java_classname = classname(pkg_dir + os.sep + c) - tlist.append(t) - elif classes: - for c in classes: - t = target[0].File(c+class_suffix) - t.attributes.java_classdir = target[0] - t.attributes.java_classname = classname(c) - tlist.append(t) - else: - # This is an odd end case: no package and no classes. - # Just do our best based on the source file name. - base = str(f)[:-len(java_suffix)] - t = target[0].File(base + class_suffix) - t.attributes.java_classdir = target[0] - t.attributes.java_classname = classname(base) - tlist.append(t) - - return tlist, slist - -JavaAction = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') - -JavaBuilder = SCons.Builder.Builder(action = JavaAction, - emitter = emit_java_classes, - target_factory = SCons.Node.FS.Dir, - source_factory = SCons.Node.FS.Dir) - -def generate(env): - """Add Builders and construction variables for javac to an Environment.""" - env['BUILDERS']['Java'] = JavaBuilder - - env['JAVAC'] = 'javac' - env['JAVACFLAGS'] = SCons.Util.CLVar('') - env['JAVACCOM'] = '$JAVAC $JAVACFLAGS -d ${TARGET.attributes.java_classdir} -sourcepath ${SOURCE.dir.rdir()} $SOURCES' - env['JAVACLASSSUFFIX'] = '.class' - env['JAVASUFFIX'] = '.java' - -def exists(env): - return env.Detect('javac')