else:
del kw['dir']
- def rstr(x):
- try:
- return x.rstr()
- except AttributeError:
- return str(x)
-
if kw.has_key('target'):
t = kw['target']
del kw['target']
cwd = t[0].cwd
except (IndexError, AttributeError):
pass
- dict['TARGETS'] = SCons.Util.PathList(map(os.path.normpath, map(rstr, t)))
+ dict['TARGETS'] = SCons.Util.PathList(map(os.path.normpath, map(str, t)))
if dict['TARGETS']:
dict['TARGET'] = dict['TARGETS'][0]
if kw.has_key('source'):
+ def rstr(x):
+ try:
+ return x.rstr()
+ except AttributeError:
+ return str(x)
s = kw['source']
del kw['source']
if not SCons.Util.is_List(s):
class N:
def __init__(self, name):
self.name = name
+ def __str__(self):
+ return self.name
def rstr(self):
return 'rstr-' + self.name
d = a.subst_dict(target = [N('t3'), 't4'], source = ['s3', N('s4')])
TARGETS = map(lambda x: str(x), d['TARGETS'])
TARGETS.sort()
- assert TARGETS == ['rstr-t3', 't4'], d['TARGETS']
+ assert TARGETS == ['t3', 't4'], d['TARGETS']
SOURCES = map(lambda x: str(x), d['SOURCES'])
SOURCES.sort()
assert SOURCES == ['rstr-s4', 's3'], d['SOURCES']
build_dir.link(src_dir, duplicate)
def Repository(self, *dirs):
- """Specify repository directories to search."""
+ """Specify Repository directories to search."""
for d in dirs:
self.Repositories.append(self.Dir(d))
def Rsearch(self, path, func = exists_path):
- """Search for something in a repository. Returns the first
+ """Search for something in a Repository. Returns the first
one found in the list, or None if there isn't one."""
if isinstance(path, SCons.Node.Node):
return path
return None
def Rsearchall(self, pathlist, func = exists_path):
- """Search for a list of somethings in the repository list."""
+ """Search for a list of somethings in the Repository list."""
ret = []
if SCons.Util.is_String(pathlist):
pathlist = string.split(pathlist, os.pathsep)
+ if not SCons.Util.is_List(pathlist):
+ pathlist = [pathlist]
for path in pathlist:
if isinstance(path, SCons.Node.Node):
ret.append(path)
if n:
ret.append(n)
if not os.path.isabs(path):
+ if path[0] == '#':
+ path = path[1:]
for dir in self.Repositories:
n = func(os.path.join(dir.path, path))
if n:
raise AttributeError
def exists(self):
- return os.path.exists(self.rstr())
+ return os.path.exists(self.path)
def cached_exists(self):
try:
self.exists_flag = self.exists()
return self.exists_flag
+ def rexists(self):
+ return os.path.exists(self.rstr())
+
def get_parents(self):
parents = SCons.Node.Node.get_parents(self)
if self.dir and not isinstance(self.dir, ParentOfRoot):
# XXX TODO?
# Annotate with the creator
-# is_under
# rel_path
# srcpath / srcdir
# link / is_linked
# source path exists, we only care about the path.
return os.path.exists(self.path)
+ def rexists(self):
+ # Again, directories are special...we don't care if their
+ # source path exists, we only care about the path.
+ return os.path.exists(self.rstr())
+
# XXX TODO?
-# rfile
-# precious
-# rpath
# rsrcpath
# source_exists
# derived_exists
# addsuffix
# accessible
# ignore
-# build
# bind
-# is_under
# relpath
class File(Entry):
return self.dir.root()
def get_contents(self):
- if not self.exists():
+ if not self.rexists():
return ''
return open(self.rstr(), "rb").read()
def get_timestamp(self):
- if self.exists():
+ if self.rexists():
return os.path.getmtime(self.rstr())
else:
return 0
+ def calc_signature(self, calc):
+ """
+ Select and calculate the appropriate build signature for a File.
+
+ self - the File node
+ calc - the signature calculation module
+ returns - the signature
+
+ This method does not store the signature in the node or
+ in the .sconsign file.
+ """
+
+ if self.builder:
+ if SCons.Sig.build_signature:
+ if not hasattr(self, 'bsig'):
+ self.set_bsig(calc.bsig(self.rfile()))
+ return self.get_bsig()
+ else:
+ if not hasattr(self, 'csig'):
+ self.set_csig(calc.csig(self.rfile()))
+ return self.get_csig()
+ elif not self.rexists():
+ return None
+ else:
+ if not hasattr(self, 'csig'):
+ self.set_csig(calc.csig(self.rfile()))
+ return self.get_csig()
+
def store_csig(self):
self.dir.sconsign().set_csig(self.name, self.get_csig())
file_link(self.srcpath, self.path)
return Entry.exists(self)
+ def rexists(self):
+ if self.duplicate and not self.created:
+ self.created = 1
+ if self.srcpath != self.path and \
+ os.path.exists(self.srcpath):
+ if os.path.exists(self.path):
+ os.unlink(self.path)
+ self.__createDir()
+ file_link(self.srcpath, self.path)
+ return Entry.rexists(self)
+
def scanner_key(self):
return os.path.splitext(self.name)[1]
else:
self.__createDir()
+ def current(self, calc):
+ bsig = calc.bsig(self)
+ if not self.exists():
+ # The file doesn't exist locally...
+ r = self.rfile()
+ if r != self:
+ # ...but there is one in a Repository...
+ if calc.current(r, bsig):
+ # ...and it's even up-to-date.
+ # XXX Future: copy locally if requested
+ return 1
+ self._rfile = self
+ return None
+ else:
+ return calc.current(self, bsig)
+
def rfile(self):
if not hasattr(self, '_rfile'):
self._rfile = self
import os.path
import string
import sys
+import time
import unittest
import SCons.Node.FS
from TestCmd import TestCmd
assert c == "", c
assert e.__class__ == SCons.Node.FS.Dir
- #XXX test get_timestamp()
+ test.write("tstamp", "tstamp\n")
+ # Okay, *this* manipulation accomodates Windows FAT file systems
+ # that only have two-second granularity on their timestamps.
+ # We round down the current time to the nearest even integer
+ # value, subtract two to make sure the timestamp is not "now,"
+ # and then convert it back to a float.
+ tstamp = float(int(time.time() / 2) * 2) - 2
+ os.utime(test.workpath("tstamp"), (tstamp - 2.0, tstamp))
+ f = fs.File("tstamp")
+ t = f.get_timestamp()
+ assert t == tstamp, "expected %f, got %f" % (tstamp, t)
+ test.unlink("tstamp")
#XXX test get_prevsiginfo()
exc_caught = 1
assert exc_caught, "Should have caught a TypeError"
+ # XXX test calc_signature()
+
+ # XXX test current()
+
class RepositoryTestCase(unittest.TestCase):
def runTest(self):
"""Test FS (file system) Repository operations
assert fs.Rsearch('f2', os.path.exists)
assert fs.Rsearch('f3', os.path.exists)
+ list = fs.Rsearchall(fs.Dir('d1'))
+ assert len(list) == 1, list
+ assert list[0].path == 'd1', list[0].path
+
list = fs.Rsearchall([fs.Dir('d1')])
assert len(list) == 1, list
assert list[0].path == 'd1', list[0].path
list = fs.Rsearchall('d2')
assert list == [], list
+ list = fs.Rsearchall('#d2')
+ assert list == [], list
+
test.subdir(['work', 'd2'])
list = fs.Rsearchall('d2')
assert list == ['d2'], list
work_d4 = fs.File(os.path.join('work', 'd4'))
list = fs.Rsearchall(['d3', work_d4])
assert list == ['d3', work_d4], list
+
+ f1 = fs.File(test.workpath("work", "i_do_not_exist"))
+ assert not f1.rexists()
+
+ test.write(["rep2", "i_exist"], "\n")
+ f1 = fs.File(test.workpath("work", "i_exist"))
+ assert f1.rexists()
+
+ test.write(["work", "i_exist_too"], "\n")
+ f1 = fs.File(test.workpath("work", "i_exist_too"))
+ assert f1.rexists()
+
+ test.write(["rep2", "tstamp"], "tstamp\n")
+ # Okay, *this* manipulation accomodates Windows FAT file systems
+ # that only have two-second granularity on their timestamps.
+ # We round down the current time to the nearest even integer
+ # value, subtract two to make sure the timestamp is not "now,"
+ # and then convert it back to a float.
+ tstamp = float(int(time.time() / 2) * 2) - 2
+ os.utime(test.workpath("rep2", "tstamp"), (tstamp - 2.0, tstamp))
+ f = fs.File("tstamp")
+ t = f.get_timestamp()
+ assert t == tstamp, "expected %f, got %f" % (tstamp, t)
+ test.unlink(["rep2", "tstamp"])
+
+ # Make sure get_contents() returns the binary contents.
+ test.write(["rep3", "contents"], "Con\x1aTents\n")
+ c = fs.File("contents").get_contents()
+ assert c == "Con\x1aTents\n", "got '%s'" % c
+ test.unlink(["rep3", "contents"])
+
+ # XXX test calc_signature()
+
+ # XXX test current()
class find_fileTestCase(unittest.TestCase):
def runTest(self):
def current(self):
return None
+ def rfile(self):
+ return self
+
def rstr(self):
return str(self)
if not hasattr(target, 'cpppath'):
def Dir(x, dir=target.cwd, fs=fs): return fs.Dir(x,dir)
try:
- target.cpppath = tuple(SCons.Node.arg2nodes(env['CPPPATH'],Dir))
+ target.cpppath = tuple(fs.Rsearchall(env['CPPPATH'], Dir))
except KeyError:
target.cpppath = ()
cpppath = target.cpppath
if not node.found_includes.has_key(cpppath):
- if node.exists():
+ if node.rexists():
# cache the includes list in node so we only scan it once:
if node.includes != None:
}
""")
-test.write('include/fa.h', "\n")
-test.write('include/fb.h', "\n")
-test.write('subdir/include/fa.h', "\n")
-test.write('subdir/include/fb.h', "\n")
+test.write(['include', 'fa.h'], "\n")
+test.write(['include', 'fb.h'], "\n")
+test.write(['subdir', 'include', 'fa.h'], "\n")
+test.write(['subdir', 'include', 'fb.h'], "\n")
+
+
+test.subdir('repository', ['repository', 'include'])
+test.subdir('work', ['work', 'src'])
+
+test.write(['repository', 'include', 'iii.h'], "\n")
+
+test.write(['work', 'src', 'fff.c'], """
+#include <iii.h>
+
+int main()
+{
+ return 0;
+}
+""")
# define some helpers:
deps_match(self, deps, [ 'include/fa.h', 'include/fb.h' ])
test.unlink('include/fa.cpp')
+class CScannerTestCase11(unittest.TestCase):
+ def runTest(self):
+ os.chdir(test.workpath('work'))
+ fs = SCons.Node.FS.FS(test.workpath('work'))
+ fs.Repository(test.workpath('repository'))
+ s = SCons.Scanner.C.CScan(fs=fs)
+ env = DummyEnvironment(['include'])
+ deps = s.scan(fs.File('src/fff.c'), env, DummyTarget())
+ deps_match(self, deps, [test.workpath('repository/include/iii.h')])
+ os.chdir(test.workpath(''))
+
def suite():
suite = unittest.TestSuite()
suite.addTest(CScannerTestCase1())
suite.addTest(CScannerTestCase8())
suite.addTest(CScannerTestCase9())
suite.addTest(CScannerTestCase10())
+ suite.addTest(CScannerTestCase11())
return suite
if __name__ == "__main__":
if not hasattr(target, 'f77path'):
def Dir(x, dir=target.cwd, fs=fs): return fs.Dir(x,dir)
try:
- target.f77path = tuple(SCons.Node.arg2nodes(env['F77PATH'],Dir))
+ target.f77path = tuple(fs.Rsearchall(env['F77PATH'], Dir))
except KeyError:
target.f77path = ()
try:
nodes = node.found_includes[f77path]
except KeyError:
- if node.exists():
+ if node.rexists():
# cache the includes list in node so we only scan it once:
if node.includes != None:
test.write('include/f4.f', "\n")
test.write('subdir/include/f4.f', "\n")
+
+test.subdir('repository', ['repository', 'include'])
+test.subdir('work', ['work', 'src'])
+
+test.write(['repository', 'include', 'iii.f'], "\n")
+
+test.write(['work', 'src', 'fff.f'], """
+ PROGRAM FOO
+ INCLUDE 'iii.f'
+ STOP
+ END
+""")
+
# define some helpers:
class DummyTarget:
deps_match(self, deps, ['include/f4.f'])
test.unlink('include/fff4.f')
+class FortranScannerTestCase13(unittest.TestCase):
+ def runTest(self):
+ os.chdir(test.workpath('work'))
+ fs = SCons.Node.FS.FS(test.workpath('work'))
+ fs.Repository(test.workpath('repository'))
+ s = SCons.Scanner.Fortran.FortranScan(fs=fs)
+ env = DummyEnvironment(['include'])
+ deps = s.scan(fs.File('src/fff.f'), env, DummyTarget())
+ deps_match(self, deps, [test.workpath('repository/include/iii.f')])
+ os.chdir(test.workpath(''))
+
def suite():
suite = unittest.TestSuite()
suite.addTest(FortranScannerTestCase1())
suite.addTest(FortranScannerTestCase10())
suite.addTest(FortranScannerTestCase11())
suite.addTest(FortranScannerTestCase12())
+ suite.addTest(FortranScannerTestCase13())
return suite
if __name__ == "__main__":
if fn == "-":
exec sys.stdin in stack[-1].globals
else:
- if isinstance(fn, SCons.Node.Node):
- f = fn
- else:
- f = SCons.Node.FS.default_fs.File(str(fn))
- if f.exists():
+ if isinstance(fn, SCons.Node.Node):
+ f = fn
+ else:
+ f = SCons.Node.FS.default_fs.File(str(fn))
+ if f.rexists():
file = open(f.rstr(), "r")
SCons.Node.FS.default_fs.chdir(f.dir)
if sconscript_chdir:
sfile = os.path.join(dirname, file)
if os.path.isfile(sfile):
return sfile
- if not os.path.isabs(file):
+ if not os.path.isabs(sfile):
for rep in repositories:
if os.path.isfile(os.path.join(rep, sfile)):
return sfile
self.exists_cache = self.exists()
return self.exists_cache
+ def rexists(self):
+ return not self.file.contents is None
+
def children(self):
return filter(lambda x, i=self.ignore: x not in i,
self.sources + self.depends)
--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright (c) 2001, 2002 Steven Knight
+#
+# 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 sys
+import TestSCons
+
+if sys.platform == 'win32':
+ _exe = '.exe'
+else:
+ _exe = ''
+
+
+
+test = TestSCons.TestSCons()
+
+#
+test.subdir('work',
+ ['work', 'src'],
+ ['work', 'include'],
+ 'repository',
+ ['repository', 'src'],
+ ['repository', 'include'])
+
+#
+workpath_repository = test.workpath('repository')
+work_include_my_string_h = test.workpath('work', 'include', 'my_string.h')
+work_src_xxx = test.workpath('work', 'src', 'xxx')
+repository_src_xxx = test.workpath('repository', 'src', 'xxx')
+
+opts = "-Y " + workpath_repository
+
+#
+test.write(['repository', 'SConstruct'], """
+env = Environment(CPPPATH = ['#src', '#include'])
+SConscript('src/SConscript', "env")
+""")
+
+test.write(['repository', 'src', 'SConscript'], """
+Import("env")
+env.Program(target = 'xxx', source = 'main.c')
+""")
+
+test.write(['repository', 'include', 'my_string.h'], r"""
+#define MY_STRING "repository/include/my_string.h"
+""")
+
+test.write(['repository', 'src', 'include.h'], r"""
+#include <my_string.h>
+#define LOCAL_STRING "repository/src/include.h"
+""")
+
+test.write(['repository', 'src', 'main.c'], r"""
+#include <include.h>
+int
+main(int argc, char *argv[])
+{
+ argv[argc++] = "--";
+ printf("%s\n", MY_STRING);
+ printf("%s\n", LOCAL_STRING);
+ printf("repository/src/main.c\n");
+ exit (0);
+}
+""")
+
+#
+test.run(chdir = 'repository', arguments = ".")
+
+test.run(program = repository_src_xxx, stdout =
+"""repository/include/my_string.h
+repository/src/include.h
+repository/src/main.c
+""")
+
+# Double-check that the Repository is up-to-date.
+#test.up_to_date(chdir = 'repository', arguments = ".")
+
+# Make the repository non-writable,
+# so we'll detect if we try to write into it accidentally.
+test.writable('repository', 0)
+
+# Because the Repository is completely up-to-date,
+# a build in an empty work directory should also be up-to-date.
+test.up_to_date(chdir = 'work', options = opts, arguments = ".")
+
+test.write(['work', 'include', 'my_string.h'], r"""
+#define MY_STRING "work/include/my_string.h"
+""")
+
+test.run(chdir = 'work', options = opts, arguments = ".")
+
+test.run(program = work_src_xxx, stdout =
+"""work/include/my_string.h
+repository/src/include.h
+repository/src/main.c
+""")
+
+test.write(['work', 'src', 'include.h'], r"""
+#include <my_string.h>
+#define LOCAL_STRING "work/src/include.h"
+""")
+
+test.run(chdir = 'work', options = opts, arguments = ".")
+
+test.run(program = work_src_xxx, stdout =
+"""work/include/my_string.h
+work/src/include.h
+repository/src/main.c
+""")
+
+#
+test.unlink(work_include_my_string_h)
+
+test.run(chdir = 'work', options = opts, arguments = ".")
+
+test.run(program = work_src_xxx, stdout =
+"""repository/include/my_string.h
+work/src/include.h
+repository/src/main.c
+""")
+
+#
+test.pass_test()
+__END__