From 5aaf9d3bad67e5ac33a342478e4449e4c71f039c Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Tue, 18 Feb 2003 08:04:29 +0000 Subject: Add support for fetching files from rcs. --- doc/man/scons.1 | 281 ++++++++++++++++++++++++++++++++++- src/CHANGES.txt | 4 + src/engine/MANIFEST.in | 5 + src/engine/SCons/Builder.py | 6 +- src/engine/SCons/Environment.py | 9 ++ src/engine/SCons/EnvironmentTests.py | 12 ++ src/engine/SCons/Node/FS.py | 37 +++++ src/engine/SCons/Node/FSTests.py | 29 ++++ src/engine/SCons/Node/NodeTests.py | 19 ++- src/engine/SCons/Node/__init__.py | 43 +++++- src/engine/SCons/Tool/BitKeeper.py | 62 ++++++++ src/engine/SCons/Tool/CVS.py | 61 ++++++++ src/engine/SCons/Tool/RCS.py | 54 +++++++ src/engine/SCons/Tool/SCCS.py | 53 +++++++ src/engine/SCons/Tool/Subversion.py | 61 ++++++++ src/engine/SCons/Tool/__init__.py | 4 +- test/BitKeeper.py | 157 +++++++++++++++++++ test/CVS.py | 125 ++++++++++++++++ test/RCS.py | 140 +++++++++++++++++ test/SCCS.py | 86 +++++++++++ test/Subversion.py | 126 ++++++++++++++++ 21 files changed, 1363 insertions(+), 11 deletions(-) create mode 100644 src/engine/SCons/Tool/BitKeeper.py create mode 100644 src/engine/SCons/Tool/CVS.py create mode 100644 src/engine/SCons/Tool/RCS.py create mode 100644 src/engine/SCons/Tool/SCCS.py create mode 100644 src/engine/SCons/Tool/Subversion.py create mode 100644 test/BitKeeper.py create mode 100644 test/CVS.py create mode 100644 test/RCS.py create mode 100644 test/SCCS.py create mode 100644 test/Subversion.py diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 1bf9157..f026b72 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -1349,6 +1349,45 @@ env.Append(CCFLAGS = ' -g', FOO = ['foo.yyy']) .EE .TP +.RI BitKeeper( repository ", " module ) +A factory function that +returns a Builder object +to be used to fetch source files +from the specified +BitKeeper +.IR repository . +The returned Builder +is intended to be passed to the +.B SourceCode +function. + +The optional specified +.I module +will be added to the beginning +of all repository path names; +this can be used, in essence, +to strip initial directory names +from the repository path names, +so that you only have to +replicate part of the repository +directory hierarchy in your +local build directory: + +.ES +# Will fetch foo/bar/src.c +# from /usr/local/BKsources/foo/bar/src.c. +env.SourceCode('.', env.BitKeeper('/usr/local/BKsources')) + +# Will fetch bar/src.c +# from /usr/local/BKsources/foo/bar/src.c. +env.SourceCode('.', env.BitKeeper('/usr/local/BKsources', 'foo')) + +# Will fetch src.c +# from /usr/local/BKsources/foo/bar/src.c. +env.SourceCode('.', env.BitKeeper('/usr/local/BKsources', 'foo/bar')) +.EE + +.TP .RI Command( target ", " source ", " commands ) Executes a specific action (or list of actions) @@ -1394,6 +1433,45 @@ env3 = env.Copy(CCFLAGS = '-g') .EE .TP +.RI CVS( repository ", " module ) +A factory function that +returns a Builder object +to be used to fetch source files +from the specified +CVS +.IR repository . +The returned Builder +is intended to be passed to the +.B SourceCode +function. + +The optional specified +.I module +will be added to the beginning +of all repository path names; +this can be used, in essence, +to strip initial directory names +from the repository path names, +so that you only have to +replicate part of the repository +directory hierarchy in your +local build directory: + +.ES +# Will fetch foo/bar/src.c +# from /usr/local/CVSROOT/foo/bar/src.c. +env.SourceCode('.', env.CVS('/usr/local/CVSROOT')) + +# Will fetch bar/src.c +# from /usr/local/CVSROOT/foo/bar/src.c. +env.SourceCode('.', env.CVS('/usr/local/CVSROOT', 'foo')) + +# Will fetch src.c +# from /usr/local/CVSROOT/foo/bar/src.c. +env.SourceCode('.', env.CVS('/usr/local/CVSROOT', 'foo/bar')) +.EE + +.TP .RI Depends( target ", " dependency ) Specifies an explicit dependency; the target file(s) will be rebuilt @@ -1487,16 +1565,43 @@ env.Prepend(CCFLAGS = '-g ', FOO = ['foo.yyy']) .EE .TP +.RI RCS( ) +A factory function that +returns a Builder object +to be used to fetch source files +from RCS. +The returned Builder +is intended to be passed to the +.B SourceCode +function: +.ES +env.SourceCode('.', env.RCS()) +.EE + +.TP .RI Replace( key = val ", [...])" Replaces construction variables in the Environment with the specified keyword arguments. -(Note: "Update()" is a deprecated synonym for this method.) .ES env.Replace(CCFLAGS = '-g', FOO = 'foo.xxx') .EE .TP +.RI SCCS( ) +A factory function that +returns a Builder object +to be used to fetch source files +from SCCS. +The returned Builder +is intended to be passed to the +.B SourceCode +function: +.ES +env.SourceCode('.', env.SCCS()) +.EE + +.TP .RI SideEffect( side_effect , target ) Declares .I side_effect @@ -1520,6 +1625,96 @@ Consequently, you only need to use this method for side-effect targets that are built as a result of multiple build commands. +.TP +.RI SourceCode( entries , builder ) +Arrange for non-existent source files to +be fetched from a source code system +using the specified +.IR builder . +The specified +.I entries +may be a Node, string or list of both, +and may represent either individual +source files or directories in which +source files can be found. +For any non-existent source files, +.B scons +will search up the directory tree +and use the first +.B SourceCode +builder it finds. +The specified +.I builder +may be +.BR None , +in which case +.B scons +will not use a builder to fetch +source files for the specified +.IR entries , +even if a +.B SourceCode +builder has been specified +for a directory higher up the tree. +Note that if the specified +.I builder +is one you create by hand, +it must have an associated +construction environment to use +when fetching a source file. +.B scons +provides a set of canned factory +functions that return appropriate +Builders for various popular +source code management systems. +Canonical examples of invocation include: +.ES +env.SourceCode('.', env.BitKeeper('/usr/local/BKsources')) +env.SourceCode('src', env.CVS('/usr/local/CVSROOT')) +env.SourceCode('/', env.RCS()) +env.SourceCode(['f1.c', 'f2.c'], env.SCCS()) +env.SourceCode('.', env.Subversion('file:///usr/local/Subversion')) +env.SourceCode('no_source.c', None) +.EE + +.TP +.RI Subversion( repository ", " module ) +A factory function that +returns a Builder object +to be used to fetch source files +from the specified Subversion +.IR repository . +The returned Builder +is intended to be passed to the +.B SourceCode +function. + +The optional specified +.I module +will be added to the beginning +of all repository path names; +this can be used, in essence, +to strip initial directory names +from the repository path names, +so that you only have to +replicate part of the repository +directory hierarchy in your +local build directory: + +.ES +# Will fetch foo/bar/src.c +# from /usr/local/Subversion/foo/bar/src.c. +env.SourceCode('.', env.Subversion('file:///usr/local/Subversion')) + +# Will fetch bar/src.c +# from /usr/local/Subversion/foo/bar/src.c. +env.SourceCode('.', env.Subversion('file:///usr/local/Subversion', 'foo')) + +# Will fetch src.c +# from /usr/local/Subversion/foo/bar/src.c. +env.SourceCode('.', env.Subversion('file:///usr/local/Subversion', 'foo/bar')) +.EE + .SS Construction Variables .\" XXX From Gary Ruben, 23 April 2002: .\" I think it would be good to have an example with each construction @@ -1570,6 +1765,16 @@ after first running the file through the C preprocessor. Any options specified in the $ASFLAGS and $CPPFLAGS construction variables are included on this command line. +.IP BITKEEPER +The BitKeeper executable. + +.IP BITKEEPERCOM +The command line used to +fetch source files from a BitKeeper repository. + +.IP BITKEEPERFLAGS +General options that are passed to BitKeeper. + .IP BUILDERS A dictionary mapping the names of the builders available through this environment @@ -1619,6 +1824,15 @@ SCons also treats (upper case) files as C files. +.IP CO +The RCS "checkout" executable, +used to fetch source files from RCS. +See the related variables +.B RCSCOM +and +.BR RCSFLAGS , +below. + .IP _concat A function used to produce variables like $_CPPINCFLAGS. It takes six arguments: a prefix to concatenate onto each element, a list of elements, a @@ -1631,7 +1845,6 @@ before concatenation. env['_CPPINCFLAGS'] = '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, locals(), globals(), RDirs)} $)', .EE - .IP CPPFLAGS C preprocessor options. These will be included in any command that uses the C preprocessor, @@ -1696,6 +1909,16 @@ include $_CPPINCFLAGS: env = Environment(CCCOM="my_compiler $_CPPINCFLAGS -c -o $TARGET $SOURCE") .EE +.IP CVS +The CVS executable. + +.IP CVSCOM +The command line used to +fetch source files from a CVS repository. + +.IP CVSFLAGS +General options that are passed to CVS. + .IP CXX The C++ compiler. @@ -2135,6 +2358,21 @@ The command line used by the RES builder. .IP RCFLAGS The flags passed to the resource compiler by the RES builder. +.IP RCS +The RCS executable. +Note that this variable is not actually used +to fetch source files from RCS; +see the +.B CO +construction variable, above. + +.IP RCSCOM +The command line used to +fetch source files from RCS. + +.IP RCSFLAGS +General options that are passed to RCS. + .IP RDirs A function that converts a file name into a list of Dir instances by searching the repositories. @@ -2142,6 +2380,16 @@ searching the repositories. .IP SCANNERS A list of the available implicit dependency scanners. [CScan] by default. +.IP SCCS +The SCCS executable. + +.IP SCCSCOM +The command line used to +fetch source files from SCCS. + +.IP SCCSFLAGS +General options that are passed to SCCS. + .IP SHCC The C compiler used for generating shared-library objects. @@ -2233,6 +2481,17 @@ is that arguments to the command. is a dictionary of the environment variables in which the command should be executed. +.IP SUBVERSION +The Subversion executable (usually named +.BR svn ). + +.IP SUBVERSIONCOM +The command line used to +fetch source files from a Subversion repository. + +.IP SUBVERSIONFLAGS +General options that are passed to Subversion. + .IP TAR The tar archiver. @@ -3189,6 +3448,24 @@ and .I action arguments must not both be used for the same Builder. +.IP env +A construction environment that can be used +to fetch source code using this Builder. +(Note that this environment is +.I not +used for normal builds of normal target files, +which use the environment that was +used to call the Builder for the target file.) + +.IP overrides +A dictionary of construction variables +that will be set in the executing +construction environment when this +Builder is invoked. +The canonical example here would be +to set a construction variable to +the repository of a source code system. + Any additional keyword arguments supplied when a Builder object is called will be associated with the target diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 944fcb6..dce8e34 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -19,6 +19,10 @@ RELEASE 0.12 - XXX - Remove deprecated features: the "name" argument to Builder objects, and the Environment.Update() method. + - Add an Environment.SourceCode() method to support fetching files + from source code systems. Add factory methods that create Builders + to support BitKeeper, CVS, RCS, SCCS and Subversion. + RELEASE 0.11 - Tue, 11 Feb 2003 05:24:33 -0600 diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in index 1746de9..6a6cb6a 100644 --- a/src/engine/MANIFEST.in +++ b/src/engine/MANIFEST.in @@ -33,6 +33,8 @@ SCons/Taskmaster.py SCons/Tool/__init__.py SCons/Tool/386asm.py SCons/Tool/ar.py +SCons/Tool/BitKeeper.py +SCons/Tool/CVS.py SCons/Tool/default.py SCons/Tool/dvipdf.py SCons/Tool/dvips.py @@ -56,11 +58,14 @@ SCons/Tool/nasm.py SCons/Tool/pdflatex.py SCons/Tool/pdftex.py SCons/Tool/PharLapCommon.py +SCons/Tool/RCS.py +SCons/Tool/SCCS.py SCons/Tool/sgiar.py SCons/Tool/sgias.py SCons/Tool/sgicc.py SCons/Tool/sgif77.py SCons/Tool/sgilink.py +SCons/Tool/Subversion.py SCons/Tool/tar.py SCons/Tool/tex.py SCons/Tool/yacc.py diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index cf85a4a..b6839e4 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -216,12 +216,16 @@ class BuilderBase: source_factory = None, scanner = None, emitter = None, - multi = 0): + multi = 0, + env = None, + overrides = {}): self.name = name self.action = SCons.Action.Action(action) self.multi = multi self.prefix = prefix self.suffix = suffix + self.env = env + self.overrides = overrides self.set_src_suffix(src_suffix) diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index 97d20f9..c2a1ab6 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -367,6 +367,15 @@ class Environment: ret = ret[0] return ret + def SourceCode(self, entry, builder): + """Arrange for a source code builder for (part of) a tree.""" + entries = SCons.Node.arg2nodes(entry, self.fs.Entry) + for entry in entries: + entry.set_src_builder(builder) + if len(entries) == 1: + return entries[0] + return entries + def SideEffect(self, side_effect, target): """Tell scons that side_effects are built as side effects of building targets.""" diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index 657f190..e313939 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -473,6 +473,18 @@ class EnvironmentTestCase(unittest.TestCase): assert 'foo1.in' in map(lambda x: x.path, t.sources) assert 'foo2.in' in map(lambda x: x.path, t.sources) + def test_SourceCode(self): + """Test the SourceCode() method.""" + env = Environment() + e = env.SourceCode('foo', None) + s = e.src_builder() + assert s is None, s + + b = Builder() + env.SourceCode(e, b) + s = e.src_builder() + assert s is b, s + def test_SideEffect(self): """Test the SideEffect() method""" env = Environment() diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 651d280..5a8687e 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -168,6 +168,9 @@ class ParentOfRoot: def get_dir(self): return None + def src_builder(self): + return None + if os.path.normcase("TeSt") == os.path.normpath("TeSt"): def _my_normcase(x): return x @@ -294,6 +297,24 @@ class Entry(SCons.Node.Node): self._srcnode = self return self._srcnode + def set_src_builder(self, builder): + """Set the source code builder for this node.""" + self.sbuilder = builder + + def src_builder(self): + """Fetch the source code builder for this node. + + If there isn't one, we cache the source code builder specified + for the directory (which in turn will cache the value from its + parent directory, and so on up to the file system root). + """ + try: + scb = self.sbuilder + except AttributeError: + scb = self.dir.src_builder() + self.sbuilder = scb + return scb + # This is for later so we can differentiate between Entry the class and Entry # the method of the FS class. _classEntry = Entry @@ -995,6 +1016,22 @@ class File(Entry): if self.fs.CachePath and self.fs.cache_force and os.path.exists(self.path): CachePush(self, None, None) + def has_builder(self): + """Return whether this Node has a builder or not. + + If this Node doesn't have an explicit builder, this is where we + figure out, on the fly, if there's a source code builder for it. + """ + try: + b = self.builder + except AttributeError: + if not os.path.exists(self.path): + b = self.src_builder() + else: + b = None + self.builder = b + return not b is None + def prepare(self): """Prepare for this file to be created.""" diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index fa32c25..f1160c1 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -1168,6 +1168,34 @@ class StringDirTestCase(unittest.TestCase): assert str(f) == os.path.join('sub', 'file') assert not f.exists() +class has_builderTestCase(unittest.TestCase): + def runTest(self): + """Test the has_builder() method""" + test = TestCmd(workdir = '') + fs = SCons.Node.FS.FS(test.workpath('')) + os.chdir(test.workpath('')) + test.subdir('sub') + + d = fs.Dir('sub', '.') + f1 = fs.File('f1', d) + f2 = fs.File('f2', d) + f3 = fs.File('f3', d) + + h = f1.has_builder() + assert not h, h + + b1 = Builder(fs.File) + d.set_src_builder(b1) + + test.write(['sub', 'f2'], "sub/f2\n") + h = f1.has_builder() # cached from previous has_builder() call + assert not h, h + h = f2.has_builder() + assert not h, h + h = f3.has_builder() + assert h, h + assert f3.builder is b1, f3.builder + class prepareTestCase(unittest.TestCase): def runTest(self): """Test the prepare() method""" @@ -1328,6 +1356,7 @@ if __name__ == "__main__": suite.addTest(RepositoryTestCase()) suite.addTest(find_fileTestCase()) suite.addTest(StringDirTestCase()) + suite.addTest(has_builderTestCase()) suite.addTest(prepareTestCase()) suite.addTest(get_actionsTestCase()) suite.addTest(CacheDirTestCase()) diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 86dcc56..b47106d 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -110,7 +110,7 @@ class ExceptBuilder2: class Environment: def Dictionary(self, *args): return {} - def Override(selv, overrides): + def Override(self, overrides): return overrides class Scanner: @@ -166,7 +166,7 @@ class NodeTestCase(unittest.TestCase): node.overrides = { "foo" : 1, "bar" : 2 } node.build() assert built_it - assert built_target[0] == node, build_target[0] + assert built_target[0] == node, built_target[0] assert built_source == ["rrr", "sss"], built_source assert built_args["foo"] == 1, built_args assert built_args["bar"] == 2, built_args @@ -186,6 +186,21 @@ class NodeTestCase(unittest.TestCase): # [Charles C. 1/7/2002] Uhhh, why are there no asserts here? built_it = None + jjj = MyNode("jjj") + b = Builder() + jjj.builder_set(b) + # NOTE: No env_set()! We should pull the environment from the builder. + b.env = Environment() + b.overrides = { "on" : 3, "off" : 4 } + e.builder = b + jjj.build() + assert built_it + assert built_target[0] == jjj, built_target[0] + assert built_source == [], built_source + assert built_args["on"] == 3, built_args + assert built_args["off"] == 4, built_args + + built_it = None built_order = 0 node = MyNode("xxx") node.builder_set(Builder()) diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index 600c478..27ff4db 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -89,15 +89,21 @@ class Node: pass def __init__(self): + # Note that we no longer explicitly initialize a self.builder + # attribute to None here. That's because the self.builder + # attribute may be created on-the-fly later by a subclass (the + # canonical example being a builder to fetch a file from a + # source code system like CVS or Subversion). + self.sources = [] # source files used to build node self.depends = [] # explicit dependencies (from Depends) self.implicit = None # implicit (scanned) dependencies (None means not scanned yet) self.ignore = [] # dependencies to ignore self.parents = {} self.wkids = None # Kids yet to walk, when it's an array - self.builder = None self.source_scanner = None # implicit scanner from scanner map self.target_scanner = None # explicit scanner from this node's Builder + self.env = None self.state = None self.precious = None @@ -116,12 +122,32 @@ class Node: Annotate(self) def generate_build_env(self): - return self.env.Override(self.overrides) + """Generate the appropriate Environment to build this node.""" + if self.env is None: + # The node itself doesn't have an associated Environment + # (which kind of implies it's a source code file, but who + # knows...). Regardless of why, use the environment (if + # any) associated with the Builder itself. + env = self.builder.env + overrides = self.builder.overrides + else: + # The normal case: use the Environment used to specify how + # this Node is to be built. + env = self.env + overrides = self.overrides + return env.Override(overrides) def _for_each_action(self, func): + """Call a function for each action required to build a node. + + The purpose here is to have one place for the logic that + collects and executes all of the actions for a node's builder, + even though multiple sections of code elsewhere need this logic + to do different things.""" if not self.has_builder(): - return None - action_list = self.pre_actions + self.builder.get_actions() + \ + return + action_list = self.pre_actions + \ + self.builder.get_actions() + \ self.post_actions if not action_list: return @@ -193,7 +219,14 @@ class Node: class(es), generating a bazillion extra calls and slowing things down immensely. """ - return not self.builder is None + try: + b = self.builder + 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 + return not b is None def builder_sig_adapter(self): """Create an adapter for calculating a builder's signature. diff --git a/src/engine/SCons/Tool/BitKeeper.py b/src/engine/SCons/Tool/BitKeeper.py new file mode 100644 index 0000000..94e084f --- /dev/null +++ b/src/engine/SCons/Tool/BitKeeper.py @@ -0,0 +1,62 @@ +"""SCons.Tool.BitKeeper.py + +Tool-specific initialization for the BitKeeper source code control +system. + +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__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os.path + +import SCons.Builder + +def generate(env, platform): + """Add a Builder factory function and construction variables for + BitKeeper to an Environment.""" + + def BitKeeperFactory(repos, module='', env=env): + """ """ + # fail if repos is not an absolute path name? + if module != '': + module = os.path.join(module, '') + return SCons.Builder.Builder(action = "$BITKEEPERCOM", + env = env, + overrides = {'BKREPOSITORY':repos, + 'BKMODULE':module}) + + setattr(env, 'BitKeeper', BitKeeperFactory) + + env['BITKEEPER'] = 'bk' + env['BITKEEPERFLAGS'] = '' + env['BITKEEPERCOM'] = '$BITKEEPER get $BITKEEPERFLAGS -p $BKREPOSITORY/$BKMODULE$TARGET > $TARGET' + +def exists(env): + return env.Detect('bk') diff --git a/src/engine/SCons/Tool/CVS.py b/src/engine/SCons/Tool/CVS.py new file mode 100644 index 0000000..c8b1f68 --- /dev/null +++ b/src/engine/SCons/Tool/CVS.py @@ -0,0 +1,61 @@ +"""SCons.Tool.CVS.py + +Tool-specific initialization for CVS. + +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__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os.path + +import SCons.Builder + +def generate(env, platform): + """Add a Builder factory function and construction variables for + CVS to an Environment.""" + + def CVSFactory(repos, module='', env=env): + """ """ + # fail if repos is not an absolute path name? + if module != '': + module = os.path.join(module, '') + return SCons.Builder.Builder(action = '$CVSCOM', + env = env, + overrides = {'CVSREPOSITORY':repos, + 'CVSMODULE':module}) + + setattr(env, 'CVS', CVSFactory) + + env['CVS'] = 'cvs' + env['CVSFLAGS'] = '' + env['CVSCOM'] = '$CVS $CVSFLAGS -d $CVSREPOSITORY co -p $CVSMODULE$TARGET > $TARGET' + +def exists(env): + return env.Detect('cvs') diff --git a/src/engine/SCons/Tool/RCS.py b/src/engine/SCons/Tool/RCS.py new file mode 100644 index 0000000..1f5489b --- /dev/null +++ b/src/engine/SCons/Tool/RCS.py @@ -0,0 +1,54 @@ +"""SCons.Tool.RCS.py + +Tool-specific initialization for RCS. + +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__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import SCons.Builder + +def generate(env, platform): + """Add a Builder factory function and construction variables for + RCS to an Environment.""" + + def RCSFactory(env=env): + """ """ + return SCons.Builder.Builder(action = '$RCSCOM', env = env) + + setattr(env, 'RCS', RCSFactory) + + env['CO'] = 'co' + env['RCS'] = 'rcs' + env['RCSFLAGS'] = '' + env['RCSCOM'] = '$CO $RCSFLAGS -p $TARGET,v > $TARGET' + +def exists(env): + return env.Detect('rcs') diff --git a/src/engine/SCons/Tool/SCCS.py b/src/engine/SCons/Tool/SCCS.py new file mode 100644 index 0000000..1b5d480 --- /dev/null +++ b/src/engine/SCons/Tool/SCCS.py @@ -0,0 +1,53 @@ +"""SCons.Tool.SCCS.py + +Tool-specific initialization for SCCS. + +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__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import SCons.Builder + +def generate(env, platform): + """Add a Builder factory function and construction variables for + SCCS to an Environment.""" + + def SCCSFactory(env=env): + """ """ + return SCons.Builder.Builder(action = '$SCCSCOM', env = env) + + setattr(env, 'SCCS', SCCSFactory) + + env['SCCS'] = 'sccs' + env['SCCSFLAGS'] = '' + env['SCCSCOM'] = '$SCCS $SCCSFLAGS get $TARGET' + +def exists(env): + return env.Detect('sccs') diff --git a/src/engine/SCons/Tool/Subversion.py b/src/engine/SCons/Tool/Subversion.py new file mode 100644 index 0000000..cec3eaf --- /dev/null +++ b/src/engine/SCons/Tool/Subversion.py @@ -0,0 +1,61 @@ +"""SCons.Tool.Subversion.py + +Tool-specific initialization for Subversion. + +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__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os.path + +import SCons.Builder + +def generate(env, platform): + """Add a Builder factory function and construction variables for + Subversion to an Environment.""" + + def SubversionFactory(repos, module='', env=env): + """ """ + # fail if repos is not an absolute path name? + if module != '': + module = os.path.join(module, '') + return SCons.Builder.Builder(action = '$SUBVERSIONCOM', + env = env, + overrides = {'SUBVERSIONREPOSITORY':repos, + 'SUBVERSIONMODULE':module}) + + setattr(env, 'Subversion', SubversionFactory) + + env['SUBVERSION'] = 'svn' + env['SUBVERSIONFLAGS'] = '' + env['SUBVERSIONCOM'] = '$SUBVERSION $SUBVERSIONFLAGS cat $SUBVERSIONREPOSITORY/$SUBVERSIONMODULE$TARGET > $TARGET' + +def exists(env): + return env.Detect('svn') diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index d2df5bb..b367d32 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -200,9 +200,11 @@ def tool_list(platform, env): else: cxx_compiler = FindTool(['g++'], env) - other_tools = FindAllTools(['dvipdf', 'dvips', + other_tools = FindAllTools(['BitKeeper', 'CVS', + 'dvipdf', 'dvips', 'latex', 'lex', 'pdflatex', 'pdftex', + 'RCS', 'SCCS', 'Subversion', 'tar', 'tex', 'yacc'], env) tools = ([linker, c_compiler, cxx_compiler, diff --git a/test/BitKeeper.py b/test/BitKeeper.py new file mode 100644 index 0000000..7994a96 --- /dev/null +++ b/test/BitKeeper.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +""" +Test fetching source files from BitKeeper. +""" + +import os + +import TestSCons + +test = TestSCons.TestSCons() + +bk = test.where_is('bk') +if not bk: + print "Could not find BitKeeper, skipping test(s)." + test.no_result(1) + +try: + login = os.getlogin() +except AttributeError: + try: + login = os.environ['USER'] + except KeyError: + login = 'USER' + +host = os.uname()[1] + +email = "%s@%s" % (login, host) + +test.subdir('BitKeeper', 'import', 'work1', 'work2', 'work3') + +# Set up the BitKeeper repository. +bkroot = test.workpath('BitKeeper') +bk_conf = test.workpath('bk.conf') + +# BitKeeper's licensing restrictions require a configuration file that +# specifies you're not using it multi-user. This seems to be the +# minimal configuration that satisfies these requirements. +test.write(bk_conf, """\ +description:test project 'foo' +logging:none +email:%s +single_user:%s +single_host:%s +""" % (email, login, host)) + +# Plus, we need to set the external environment variable that gets it to +# shut up and not prompt us to accept the license. +os.environ['BK_LICENSE'] = 'ACCEPTED' + +test.run(chdir = bkroot, + program = bk, + arguments = 'setup -f -c %s foo' % bk_conf) + +test.write(['import', 'aaa.in'], "import/aaa.in\n") +test.write(['import', 'bbb.in'], "import/bbb.in\n") +test.write(['import', 'ccc.in'], "import/ccc.in\n") + +test.run(chdir = 'import', + program = bk, + arguments = 'import -q -f -tplain . %s/foo' % bkroot) + +# Test the most straightforward BitKeeper checkouts, using the module name. +test.write(['work1', 'SConstruct'], """ +def cat(env, source, target): + target = str(target[0]) + source = map(str, source) + f = open(target, "wb") + for src in source: + f.write(open(src, "rb").read()) + f.close() +env = Environment(BUILDERS={'Cat':Builder(action=cat)}) +env.Cat('aaa.out', 'foo/aaa.in') +env.Cat('bbb.out', 'foo/bbb.in') +env.Cat('ccc.out', 'foo/ccc.in') +env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) +env.SourceCode('.', env.BitKeeper(r'%s')) +""" % bkroot) + +test.subdir(['work1', 'foo']) +test.write(['work1', 'foo', 'bbb.in'], "work1/foo/bbb.in\n") + +test.run(chdir = 'work1', + arguments = '.', + stdout = test.wrap_stdout("""\ +bk get -p %s/foo/aaa.in > foo/aaa.in +cat("aaa.out", "foo/aaa.in") +cat("bbb.out", "foo/bbb.in") +bk get -p %s/foo/ccc.in > foo/ccc.in +cat("ccc.out", "foo/ccc.in") +cat("all", ["aaa.out", "bbb.out", "ccc.out"]) +""" % (bkroot, bkroot)), + stderr = """\ +%s/foo/aaa.in 1.1: 1 lines +%s/foo/ccc.in 1.1: 1 lines +""" % (bkroot, bkroot)) + +test.fail_test(test.read(['work1', 'all']) != "import/aaa.in\nwork1/foo/bbb.in\nimport/ccc.in\n") + +# Test BitKeeper checkouts when the module name is specified. +test.write(['work2', 'SConstruct'], """ +def cat(env, source, target): + target = str(target[0]) + source = map(str, source) + f = open(target, "wb") + for src in source: + f.write(open(src, "rb").read()) + f.close() +env = Environment(BUILDERS={'Cat':Builder(action=cat)}, + BITKEEPERFLAGS='-q') +env.Cat('aaa.out', 'aaa.in') +env.Cat('bbb.out', 'bbb.in') +env.Cat('ccc.out', 'ccc.in') +env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) +env.SourceCode('.', env.BitKeeper(r'%s', 'foo')) +""" % bkroot) + +test.write(['work2', 'bbb.in'], "work2/bbb.in\n") + +test.run(chdir = 'work2', + arguments = '.', + stdout = test.wrap_stdout("""\ +bk get -q -p %s/foo/aaa.in > aaa.in +cat("aaa.out", "aaa.in") +cat("bbb.out", "bbb.in") +bk get -q -p %s/foo/ccc.in > ccc.in +cat("ccc.out", "ccc.in") +cat("all", ["aaa.out", "bbb.out", "ccc.out"]) +""" % (bkroot, bkroot))) + +test.fail_test(test.read(['work2', 'all']) != "import/aaa.in\nwork2/bbb.in\nimport/ccc.in\n") + +test.pass_test() diff --git a/test/CVS.py b/test/CVS.py new file mode 100644 index 0000000..c94ae8b --- /dev/null +++ b/test/CVS.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +""" +Test fetching source files from CVS. +""" + +import os + +import TestSCons + +test = TestSCons.TestSCons() + +cvs = test.where_is('cvs') +if not cvs: + print "Could not find CVS, skipping test(s)." + test.no_result(1) + +test.subdir('CVS', 'import', 'work1', 'work2', 'work3') + +# Set up the CVS repository. +cvsroot = test.workpath('CVS') + +os.environ['CVSROOT'] = cvsroot +test.run(program = cvs, arguments = 'init') + +test.write(['import', 'aaa.in'], "import/aaa.in\n") +test.write(['import', 'bbb.in'], "import/bbb.in\n") +test.write(['import', 'ccc.in'], "import/ccc.in\n") + +test.run(chdir = 'import', + program = cvs, + arguments = '-q import -m "import" foo v v-r') + +# Test the most straightforward CVS checkouts, using the module name. +test.write(['work1', 'SConstruct'], """ +def cat(env, source, target): + target = str(target[0]) + source = map(str, source) + f = open(target, "wb") + for src in source: + f.write(open(src, "rb").read()) + f.close() +env = Environment(BUILDERS={'Cat':Builder(action=cat)}, + CVSFLAGS='-Q') +env.Cat('aaa.out', 'foo/aaa.in') +env.Cat('bbb.out', 'foo/bbb.in') +env.Cat('ccc.out', 'foo/ccc.in') +env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) +env.SourceCode('.', env.CVS(r'%s')) +""" % cvsroot) + +test.subdir(['work1', 'foo']) +test.write(['work1', 'foo', 'bbb.in'], "work1/foo/bbb.in\n") + +test.run(chdir = 'work1', + arguments = '.', + stdout = test.wrap_stdout("""\ +cvs -Q -d %s co -p foo/aaa.in > foo/aaa.in +cat("aaa.out", "foo/aaa.in") +cat("bbb.out", "foo/bbb.in") +cvs -Q -d %s co -p foo/ccc.in > foo/ccc.in +cat("ccc.out", "foo/ccc.in") +cat("all", ["aaa.out", "bbb.out", "ccc.out"]) +""" % (cvsroot, cvsroot))) + +test.fail_test(test.read(['work1', 'all']) != "import/aaa.in\nwork1/foo/bbb.in\nimport/ccc.in\n") + +# Test CVS checkouts when the module name is specified. +test.write(['work2', 'SConstruct'], """ +def cat(env, source, target): + target = str(target[0]) + source = map(str, source) + f = open(target, "wb") + for src in source: + f.write(open(src, "rb").read()) + f.close() +env = Environment(BUILDERS={'Cat':Builder(action=cat)}, + CVSFLAGS='-q') +env.Cat('aaa.out', 'aaa.in') +env.Cat('bbb.out', 'bbb.in') +env.Cat('ccc.out', 'ccc.in') +env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) +env.SourceCode('.', env.CVS(r'%s', 'foo')) +""" % cvsroot) + +test.write(['work2', 'bbb.in'], "work2/bbb.in\n") + +test.run(chdir = 'work2', + arguments = '.', + stdout = test.wrap_stdout("""\ +cvs -q -d %s co -p foo/aaa.in > aaa.in +cat("aaa.out", "aaa.in") +cat("bbb.out", "bbb.in") +cvs -q -d %s co -p foo/ccc.in > ccc.in +cat("ccc.out", "ccc.in") +cat("all", ["aaa.out", "bbb.out", "ccc.out"]) +""" % (cvsroot, cvsroot))) + +test.fail_test(test.read(['work2', 'all']) != "import/aaa.in\nwork2/bbb.in\nimport/ccc.in\n") + +test.pass_test() diff --git a/test/RCS.py b/test/RCS.py new file mode 100644 index 0000000..6c0e597 --- /dev/null +++ b/test/RCS.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +""" +Test fetching source files from RCS. +""" + +import os.path + +import TestSCons + +test = TestSCons.TestSCons() + +rcs = test.where_is('rcs') +if not rcs: + print "Could not find RCS, skipping test(s)." + test.no_result(1) + +ci = test.where_is('ci') +if not ci: + print "Could not find `ci' command, skipping test(s)." + test.no_result(1) + +# Test checkouts from local RCS files +test.subdir('work1') + +for file in ['aaa.in', 'bbb.in', 'ccc.in']: + test.write(['work1', file], "work1/%s\n" % file) + args = "-f -t%s %s" % (file, file) + test.run(chdir = 'work1', program = ci, arguments = args, stderr = None) + +test.no_result(os.path.exists(test.workpath('work1', 'aaa.in'))) +test.no_result(os.path.exists(test.workpath('work1', 'bbb.in'))) +test.no_result(os.path.exists(test.workpath('work1', 'ccc.in'))) + +test.write(['work1', 'SConstruct'], """ +def cat(env, source, target): + target = str(target[0]) + source = map(str, source) + f = open(target, "wb") + for src in source: + f.write(open(src, "rb").read()) + f.close() +env = Environment(BUILDERS={'Cat':Builder(action=cat)}) +env.Cat('aaa.out', 'aaa.in') +env.Cat('bbb.out', 'bbb.in') +env.Cat('ccc.out', 'ccc.in') +env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) +env.SourceCode('.', env.RCS()) +""") + +test.write(['work1', 'bbb.in'], "checked-out work1/bbb.in\n") + +test.run(chdir = 'work1', + arguments = '.', + stdout = test.wrap_stdout("""\ +co -p aaa.in,v > aaa.in +cat("aaa.out", "aaa.in") +cat("bbb.out", "bbb.in") +co -p ccc.in,v > ccc.in +cat("ccc.out", "ccc.in") +cat("all", ["aaa.out", "bbb.out", "ccc.out"]) +"""), + stderr = """\ +aaa.in,v --> standard output +revision 1.1 +ccc.in,v --> standard output +revision 1.1 +""") + +test.fail_test(test.read(['work1', 'all']) != "work1/aaa.in\nchecked-out work1/bbb.in\nwork1/ccc.in\n") + +# Test RCS checkouts from an RCS subdirectory. +test.subdir('work2', ['work2', 'RCS']) + +for file in ['aaa.in', 'bbb.in', 'ccc.in']: + test.write(['work2', file], "work2/%s\n" % file) + args = "-f -t%s %s" % (file, file) + test.run(chdir = 'work2', program = ci, arguments = args, stderr = None) + +test.no_result(os.path.exists(test.workpath('work2', 'aaa.in'))) +test.no_result(os.path.exists(test.workpath('work2', 'bbb.in'))) +test.no_result(os.path.exists(test.workpath('work2', 'ccc.in'))) + +test.write(['work2', 'SConstruct'], """ +def cat(env, source, target): + target = str(target[0]) + source = map(str, source) + f = open(target, "wb") + for src in source: + f.write(open(src, "rb").read()) + f.close() +env = Environment(BUILDERS={'Cat':Builder(action=cat)}, + RCSFLAGS='-q') +env.Cat('aaa.out', 'aaa.in') +env.Cat('bbb.out', 'bbb.in') +env.Cat('ccc.out', 'ccc.in') +env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) +env.SourceCode('.', env.RCS()) +""") + +test.write(['work2', 'bbb.in'], "checked-out work2/bbb.in\n") + +test.run(chdir = 'work2', + arguments = '.', + stdout = test.wrap_stdout("""\ +co -q -p aaa.in,v > aaa.in +cat("aaa.out", "aaa.in") +cat("bbb.out", "bbb.in") +co -q -p ccc.in,v > ccc.in +cat("ccc.out", "ccc.in") +cat("all", ["aaa.out", "bbb.out", "ccc.out"]) +""")) + +test.fail_test(test.read(['work2', 'all']) != "work2/aaa.in\nchecked-out work2/bbb.in\nwork2/ccc.in\n") + +test.pass_test() diff --git a/test/SCCS.py b/test/SCCS.py new file mode 100644 index 0000000..a25f222 --- /dev/null +++ b/test/SCCS.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +""" +Test fetching source files from SCCS. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +sccs = test.where_is('sccs') +if not sccs: + print "Could not find SCCS, skipping test(s)." + test.no_result(1) + +# Test checkouts from local SCCS files. +test.subdir('work1') + +test.preserve() + +for file in ['aaa.in', 'bbb.in', 'ccc.in']: + test.write(['work1', file], "work1/%s\n" % file) + args = "create %s" % file + test.run(chdir = 'work1', program = sccs, arguments = args, stderr = None) + test.unlink(['work1', file]) + test.unlink(['work1', ','+file]) + +test.write(['work1', 'SConstruct'], """ +def cat(env, source, target): + target = str(target[0]) + source = map(str, source) + f = open(target, "wb") + for src in source: + f.write(open(src, "rb").read()) + f.close() +env = Environment(BUILDERS={'Cat':Builder(action=cat)}) +env.Cat('aaa.out', 'aaa.in') +env.Cat('bbb.out', 'bbb.in') +env.Cat('ccc.out', 'ccc.in') +env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) +env.SourceCode('.', env.SCCS()) +""") + +test.write(['work1', 'bbb.in'], "checked-out work1/bbb.in\n") + +test.run(chdir = 'work1', + arguments = '.', + stdout = test.wrap_stdout("""\ +sccs get aaa.in +cat("aaa.out", "aaa.in") +cat("bbb.out", "bbb.in") +sccs get ccc.in +cat("ccc.out", "ccc.in") +cat("all", ["aaa.out", "bbb.out", "ccc.out"]) +"""), stderr = """\ +aaa.in 1.1: 1 lines +ccc.in 1.1: 1 lines +""") + +test.fail_test(test.read(['work1', 'all']) != "work1/aaa.in\nchecked-out work1/bbb.in\nwork1/ccc.in\n") + +test.pass_test() diff --git a/test/Subversion.py b/test/Subversion.py new file mode 100644 index 0000000..648a131 --- /dev/null +++ b/test/Subversion.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +""" +Test fetching source files from Subversion. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +svn = test.where_is('svn') +if not svn: + print "Could not find Subversion, skipping test(s)." + test.no_result(1) + +svnadmin = test.where_is('svnadmin') +if not svn: + print "Could not find Subversion, skipping test(s)." + test.no_result(1) + +test.subdir('Subversion', 'import', 'work1', 'work2', 'work3') + +# Set up the Subversion repository. +svnrootpath = test.workpath('Subversion') +svnrooturl = 'file://' + svnrootpath + +test.run(program = svnadmin, arguments = 'create %s' % svnrootpath) + +test.write(['import', 'aaa.in'], "import/aaa.in\n") +test.write(['import', 'bbb.in'], "import/bbb.in\n") +test.write(['import', 'ccc.in'], "import/ccc.in\n") + +test.run(chdir = 'import', + program = svn, + arguments = 'import %s . foo -m"import foo"' % svnrooturl) + +# Test the most straightforward Subversion checkouts, using the module name. +test.write(['work1', 'SConstruct'], """ +def cat(env, source, target): + target = str(target[0]) + source = map(str, source) + f = open(target, "wb") + for src in source: + f.write(open(src, "rb").read()) + f.close() +env = Environment(BUILDERS={'Cat':Builder(action=cat)}) +env.Cat('aaa.out', 'foo/aaa.in') +env.Cat('bbb.out', 'foo/bbb.in') +env.Cat('ccc.out', 'foo/ccc.in') +env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) +env.SourceCode('.', env.Subversion(r'%s')) +""" % svnrooturl) + +test.subdir(['work1', 'foo']) +test.write(['work1', 'foo', 'bbb.in'], "work1/foo/bbb.in\n") + +test.run(chdir = 'work1', + arguments = '.', + stdout = test.wrap_stdout("""\ +svn cat %s/foo/aaa.in > foo/aaa.in +cat("aaa.out", "foo/aaa.in") +cat("bbb.out", "foo/bbb.in") +svn cat %s/foo/ccc.in > foo/ccc.in +cat("ccc.out", "foo/ccc.in") +cat("all", ["aaa.out", "bbb.out", "ccc.out"]) +""" % (svnrooturl, svnrooturl))) + +test.fail_test(test.read(['work1', 'all']) != "import/aaa.in\nwork1/foo/bbb.in\nimport/ccc.in\n") + +# Test Subversion checkouts when the module name is specified. +test.write(['work2', 'SConstruct'], """ +def cat(env, source, target): + target = str(target[0]) + source = map(str, source) + f = open(target, "wb") + for src in source: + f.write(open(src, "rb").read()) + f.close() +env = Environment(BUILDERS={'Cat':Builder(action=cat)}) +env.Cat('aaa.out', 'aaa.in') +env.Cat('bbb.out', 'bbb.in') +env.Cat('ccc.out', 'ccc.in') +env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) +env.SourceCode('.', env.Subversion(r'%s', 'foo')) +""" % svnrooturl) + +test.write(['work2', 'bbb.in'], "work2/bbb.in\n") + +test.run(chdir = 'work2', + arguments = '.', + stdout = test.wrap_stdout("""\ +svn cat %s/foo/aaa.in > aaa.in +cat("aaa.out", "aaa.in") +cat("bbb.out", "bbb.in") +svn cat %s/foo/ccc.in > ccc.in +cat("ccc.out", "ccc.in") +cat("all", ["aaa.out", "bbb.out", "ccc.out"]) +""" % (svnrooturl, svnrooturl))) + +test.fail_test(test.read(['work2', 'all']) != "import/aaa.in\nwork2/bbb.in\nimport/ccc.in\n") + +test.pass_test() -- cgit v0.12