summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-10-16 04:13:14 (GMT)
committerSteven Knight <knight@baldmt.com>2002-10-16 04:13:14 (GMT)
commitbd91e792df09aebec78f7972e17eab873dc71246 (patch)
tree5b544223c15435fac1669b7d0f2c978483cf61fa /src
parent3f747760055842fd7ea89770cc568761d5729117 (diff)
downloadSCons-bd91e792df09aebec78f7972e17eab873dc71246.zip
SCons-bd91e792df09aebec78f7972e17eab873dc71246.tar.gz
SCons-bd91e792df09aebec78f7972e17eab873dc71246.tar.bz2
Refactor Repository and BuildDir. (Charles Crain)
Diffstat (limited to 'src')
-rw-r--r--src/CHANGES.txt6
-rw-r--r--src/engine/SCons/EnvironmentTests.py50
-rw-r--r--src/engine/SCons/Node/FS.py548
-rw-r--r--src/engine/SCons/Node/FSTests.py213
-rw-r--r--src/engine/SCons/Scanner/C.py6
-rw-r--r--src/engine/SCons/Scanner/Fortran.py6
-rw-r--r--src/engine/SCons/Script/__init__.py5
-rw-r--r--src/engine/SCons/Util.py34
8 files changed, 497 insertions, 371 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 42ce7e8..d542c0d 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -15,9 +15,11 @@ RELEASE 0.09 -
- Add a Prepend() method to Environments, to append values to
the beginning of construction variables.
- From Steven Knight:
+ From Charles Crain and Steven Knight:
+
+ - Add Repository() functionality.
- - Add Repository() functionality.
+ From Steven Knight:
- Fix auto-deduction of target names so that deduced targets end
up in the same subdirectory as the source.
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index 45b6901..2211bf8 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -485,26 +485,16 @@ class EnvironmentTestCase(unittest.TestCase):
def test_autogenerate(dict):
"""Test autogenerating variables in a dictionary."""
- def Dir(name):
- dir = SCons.Node.FS.default_fs.Dir('/xx')
- return SCons.Node.FS.default_fs.Dir(name, dir)
-
- def File(name):
- dir = SCons.Node.FS.default_fs.Dir('/xx')
- return SCons.Node.FS.default_fs.File(name, dir)
-
- def RDirs(pathlist, Dir=Dir):
- def path_dirs(rep, path, Dir=Dir):
- if rep:
- path = os.path.join(rep, path)
- return Dir(path)
-
- return SCons.Node.FS.default_fs.Rsearchall(pathlist, path_dirs)
+ def RDirs(pathlist):
+ return SCons.Node.FS.default_fs.Rsearchall(pathlist,
+ clazz=SCons.Node.FS.Dir,
+ must_exist=0,
+ cwd=SCons.Node.FS.default_fs.Dir('xx'))
env = Environment(LIBS = [ 'foo', 'bar', 'baz' ],
LIBLINKPREFIX = 'foo',
LIBLINKSUFFIX = 'bar',
- Dir=Dir, File=File, RDirs=RDirs)
+ RDirs=RDirs)
flags = env.subst_list('$_LIBFLAGS', 1)[0]
assert len(flags) == 3, flags
assert flags[0] == 'foofoobar', \
@@ -520,18 +510,18 @@ class EnvironmentTestCase(unittest.TestCase):
INCPREFIX = 'foo ',
INCSUFFIX = 'bar',
FOO = 'baz',
- Dir=Dir, File=File, RDirs=RDirs)
+ RDirs=RDirs)
flags = env.subst_list('$_CPPINCFLAGS', 1)[0]
assert len(flags) == 8, flags
assert flags[0] == '$(', \
flags[0]
assert flags[1] == os.path.normpath('foo'), \
flags[1]
- assert flags[2] == os.path.normpath('/xx/foobar'), \
+ assert flags[2] == os.path.normpath('xx/foobar'), \
flags[2]
assert flags[3] == os.path.normpath('foo'), \
flags[3]
- assert flags[4] == os.path.normpath('/xx/baz/barbar'), \
+ assert flags[4] == os.path.normpath('xx/baz/barbar'), \
flags[4]
assert flags[5] == os.path.normpath('foo'), \
flags[5]
@@ -544,18 +534,18 @@ class EnvironmentTestCase(unittest.TestCase):
INCPREFIX = 'foo ',
INCSUFFIX = 'bar',
FOO = 'baz',
- Dir=Dir, File=File, RDirs=RDirs)
+ RDirs=RDirs)
flags = env.subst_list('$_F77INCFLAGS', 1)[0]
assert len(flags) == 8, flags
assert flags[0] == '$(', \
flags[0]
assert flags[1] == os.path.normpath('foo'), \
flags[1]
- assert flags[2] == os.path.normpath('/xx/foobar'), \
+ assert flags[2] == os.path.normpath('xx/foobar'), \
flags[2]
assert flags[3] == os.path.normpath('foo'), \
flags[3]
- assert flags[4] == os.path.normpath('/xx/baz/barbar'), \
+ assert flags[4] == os.path.normpath('xx/baz/barbar'), \
flags[4]
assert flags[5] == os.path.normpath('foo'), \
flags[5]
@@ -565,7 +555,7 @@ class EnvironmentTestCase(unittest.TestCase):
flags[7]
env = Environment(CPPPATH = '', F77PATH = '', LIBPATH = '',
- Dir=Dir, File=File, RDirs=RDirs)
+ RDirs=RDirs)
assert len(env.subst_list('$_CPPINCFLAGS')[0]) == 0
assert len(env.subst_list('$_F77INCFLAGS')[0]) == 0
assert len(env.subst_list('$_LIBDIRFLAGS')[0]) == 0
@@ -576,21 +566,21 @@ class EnvironmentTestCase(unittest.TestCase):
INCPREFIX = '-I ',
INCSUFFIX = 'XXX',
FOO = 'baz',
- Dir=Dir, File=File, RDirs=RDirs)
+ RDirs=RDirs)
flags = env.subst_list('$_CPPINCFLAGS', 1)[0]
assert flags[0] == '$(', \
flags[0]
assert flags[1] == '-I', \
flags[1]
- assert flags[2] == os.path.normpath('/xx/fooXXX'), \
+ assert flags[2] == os.path.normpath('xx/fooXXX'), \
flags[2]
assert flags[3] == '-I', \
flags[3]
- assert flags[4] == os.path.normpath('/rep1/fooXXX'), \
+ assert flags[4] == os.path.normpath('/rep1/xx/fooXXX'), \
flags[4]
assert flags[5] == '-I', \
flags[5]
- assert flags[6] == os.path.normpath('/rep2/fooXXX'), \
+ assert flags[6] == os.path.normpath('/rep2/xx/fooXXX'), \
flags[6]
assert flags[7] == '-I', \
flags[7]
@@ -598,15 +588,15 @@ class EnvironmentTestCase(unittest.TestCase):
flags[8]
assert flags[9] == '-I', \
flags[9]
- assert flags[10] == os.path.normpath('/xx/baz/barXXX'), \
+ assert flags[10] == os.path.normpath('xx/baz/barXXX'), \
flags[10]
assert flags[11] == '-I', \
flags[11]
- assert flags[12] == os.path.normpath('/rep1/baz/barXXX'), \
+ assert flags[12] == os.path.normpath('/rep1/xx/baz/barXXX'), \
flags[12]
assert flags[13] == '-I', \
flags[13]
- assert flags[14] == os.path.normpath('/rep2/baz/barXXX'), \
+ assert flags[14] == os.path.normpath('/rep2/xx/baz/barXXX'), \
flags[14]
assert flags[15] == '-I', \
flags[15]
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 1ac7566..aa6482d 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -41,6 +41,7 @@ import SCons.Node
from UserDict import UserDict
import sys
from SCons.Errors import UserError
+import SCons.Warnings
try:
import os
@@ -62,20 +63,26 @@ class ParentOfRoot:
This class is an instance of the Null object pattern.
"""
def __init__(self):
- self.duplicate = 1
self.abspath = ''
self.path = ''
- self.srcpath = ''
self.abspath_ = ''
self.path_ = ''
- self.srcpath_ = ''
-
+ self.name=''
+ self.duplicate=0
+ self.srcdir=None
+
def is_under(self, dir):
return 0
def up(self):
return None
+ def getRepositories(self):
+ return []
+
+ def get_dir(self):
+ return None
+
if os.path.normcase("TeSt") == os.path.normpath("TeSt"):
def _my_normcase(x):
return x
@@ -83,15 +90,128 @@ else:
def _my_normcase(x):
return string.upper(x)
+class Entry(SCons.Node.Node):
+ """A generic class for file system entries. This class is for
+ when we don't know yet whether the entry being looked up is a file
+ or a directory. Instances of this class can morph into either
+ Dir or File objects by a later, more precise lookup.
+
+ Note: this class does not define __cmp__ and __hash__ for efficiency
+ reasons. SCons does a lot of comparing of Entry objects, and so that
+ operation must be as fast as possible, which means we want to use
+ Python's built-in object identity comparison.
+ """
+
+ def __init__(self, name, directory, fs):
+ """Initialize a generic file system Entry.
+
+ 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
+ signatures."""
+ SCons.Node.Node.__init__(self)
+
+ self.name = name
+ self.fs = fs
+
+ assert directory, "A directory must be provided"
+
+ self.abspath = directory.abspath_ + name
+ if directory.path == '.':
+ self.path = name
+ else:
+ self.path = directory.path_ + name
+
+ self.path_ = self.path
+ self.abspath_ = self.abspath
+ self.dir = directory
+ self.cwd = None # will hold the SConscript directory for target nodes
+ self.duplicate = directory.duplicate
+
+ def get_dir(self):
+ return self.dir
+
+ def __str__(self):
+ """A FS node's string representation is its path name."""
+ if self.duplicate or self.builder:
+ return self.path
+ return self.srcnode().path
+
+ 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."""
+ if os.path.isfile(self.abspath):
+ self.__class__ = File
+ self._morph()
+ return File.get_contents(self)
+ if os.path.isdir(self.abspath):
+ self.__class__ = Dir
+ self._morph()
+ return Dir.get_contents(self)
+ raise AttributeError
+
+ def exists(self):
+ try:
+ return self._exists
+ except AttributeError:
+ self._exists = os.path.exists(self.abspath)
+ return self._exists
-def exists_path(rep, path):
- """Return a path if it's already a Node or it exists in the
- real filesystem."""
- if rep:
- path = os.path.join(rep, path)
- if os.path.exists(path):
- return path
- return None
+ def rexists(self):
+ if not hasattr(self, '_rexists'):
+ self._rexists = self.rfile().exists()
+ return self._rexists
+
+ def get_parents(self):
+ parents = SCons.Node.Node.get_parents(self)
+ if self.dir and not isinstance(self.dir, ParentOfRoot):
+ parents.append(self.dir)
+ return parents
+
+ def current(self, calc):
+ """If the underlying path doesn't exist, we know the node is
+ not current without even checking the signature, so return 0.
+ Otherwise, return None to indicate that signature calculation
+ should proceed as normal to find out if the node is current."""
+ bsig = calc.bsig(self)
+ if not self.exists():
+ return 0
+ return calc.current(self, bsig)
+
+ def is_under(self, dir):
+ if self is dir:
+ return 1
+ else:
+ return self.dir.is_under(dir)
+
+ def set_local(self):
+ self._local = 1
+
+ def srcnode(self):
+ """If this node is in a build path, return the node
+ corresponding to its source file. Otherwise, return
+ ourself."""
+ try:
+ return self._srcnode
+ except AttributeError:
+ dir=self.dir
+ name=self.name
+ while dir:
+ if dir.srcdir:
+ self._srcnode = self.fs.Entry(name, dir.srcdir,
+ klass=self.__class__)
+ return self._srcnode
+ name = dir.name + os.sep + name
+ dir=dir.get_dir()
+ self._srcnode = self
+ return self._srcnode
+
+# This is for later so we can differentiate between Entry the class and Entry
+# the method of the FS class.
+_classEntry = Entry
class FS:
@@ -110,7 +230,6 @@ class FS:
self.pathTop = path
self.Root = {}
self.Top = None
- self.Repositories = []
def set_toplevel_dir(self, path):
assert not self.Top, "You can only set the top-level path on an FS object that has not had its File, Dir, or Entry methods called yet."
@@ -120,7 +239,6 @@ class FS:
if not self.Top:
self.Top = self.__doLookup(Dir, os.path.normpath(self.pathTop))
self.Top.path = '.'
- self.Top.srcpath = '.'
self.Top.path_ = '.' + os.sep
self._cwd = self.Top
@@ -137,7 +255,7 @@ class FS:
return node
if not isinstance(node, klass):
raise TypeError, "Tried to lookup %s '%s' as a %s." % \
- (node.__class__.__name__, str(node), klass.__name__)
+ (node.__class__.__name__, node.path, klass.__name__)
return node
def __doLookup(self, fsclass, name, directory = None, create = 1):
@@ -173,7 +291,6 @@ class FS:
dir = Dir(drive, ParentOfRoot(), self)
dir.path = dir.path + os.sep
dir.abspath = dir.abspath + os.sep
- dir.srcpath = dir.srcpath + os.sep
self.Root[drive] = dir
directory = dir
path_comp = path_comp[1:]
@@ -192,7 +309,7 @@ class FS:
# look at the actual filesystem and make sure there isn't
# a file already there
- path = os.path.join(str(directory), path_name)
+ path = directory.path_ + path_name
if os.path.isfile(path):
raise TypeError, \
"File %s found where directory expected." % path
@@ -210,7 +327,7 @@ class FS:
# make sure we don't create File nodes when there is actually
# a directory at that path on the disk, and vice versa
- path = os.path.join(str(directory), path_comp[-1])
+ path = directory.path_ + path_comp[-1]
if fsclass == File:
if os.path.isdir(path):
raise TypeError, \
@@ -301,12 +418,12 @@ class FS:
def BuildDir(self, build_dir, src_dir, duplicate=1):
"""Link the supplied build directory to the source directory
for purposes of building files."""
+
self.__setTopLevelDir()
if not isinstance(src_dir, SCons.Node.Node):
src_dir = self.Dir(src_dir)
if not isinstance(build_dir, SCons.Node.Node):
build_dir = self.Dir(build_dir)
- build_dir.duplicate = duplicate
if not src_dir.is_under(self.Top):
raise UserError, "Source directory must be under top of build tree."
if src_dir.is_under(build_dir):
@@ -316,24 +433,47 @@ class FS:
def Repository(self, *dirs):
"""Specify Repository directories to search."""
for d in dirs:
- self.Repositories.append(self.Dir(d))
+ if not isinstance(d, SCons.Node.Node):
+ d = self.Dir(d)
+ self.__setTopLevelDir()
+ self.Top.addRepository(d)
- def Rsearch(self, path, func = exists_path):
+ def Rsearch(self, path, clazz=_classEntry, cwd=None):
"""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
else:
- n = func(None, path)
- if n:
+ name, d = self.__transformPath(path, cwd)
+ n = self.__doLookup(clazz, name, d)
+ if n.exists():
return n
- for rep in self.Repositories:
- n = func(rep.path, path)
- if n:
- return n
+ d = n.get_dir()
+ name = n.name
+ # Search repositories of all directories that this file is under.
+ while d:
+ for rep in d.getRepositories():
+ try:
+ rnode = self.__doLookup(clazz, name, rep)
+ # Only find the node if it exists and it is not
+ # a derived file. If for some reason, we are
+ # explicitly building a file IN a Repository, we
+ # don't want it to show up in the build tree.
+ # This is usually the case with BuildDir().
+ # We only want to find pre-existing files.
+ if rnode.exists() and \
+ (isinstance(rnode, Dir) or not rnode.builder):
+ return rnode
+ except TypeError:
+ pass # Wrong type of node.
+ # Prepend directory name
+ name = d.name + os.sep + name
+ # Go up one directory
+ d = d.get_dir()
return None
+
- def Rsearchall(self, pathlist, func = exists_path):
+ def Rsearchall(self, pathlist, must_exist=1, clazz=_classEntry, cwd=None):
"""Search for a list of somethings in the Repository list."""
ret = []
if SCons.Util.is_String(pathlist):
@@ -344,133 +484,39 @@ class FS:
if isinstance(path, SCons.Node.Node):
ret.append(path)
else:
- n = func(None, path)
- if n:
+ name, d = self.__transformPath(path, cwd)
+ n = self.__doLookup(clazz, name, d)
+ if not must_exist or n.exists():
ret.append(n)
- if not os.path.isabs(path):
- if path[0] == '#':
- path = path[1:]
- for rep in self.Repositories:
- n = func(rep.path, path)
- if n:
- ret.append(n)
+ if isinstance(n, Dir):
+ # If this node is a directory, then any repositories
+ # attached to this node can be repository paths.
+ ret.extend(filter(lambda x, me=must_exist, clazz=clazz: isinstance(x, clazz) and (not me or x.exists()),
+ n.getRepositories()))
+
+ d = n.get_dir()
+ name = n.name
+ # Search repositories of all directories that this file is under.
+ while d:
+ for rep in d.getRepositories():
+ try:
+ rnode = self.__doLookup(clazz, name, rep)
+ # Only find the node if it exists (or must_exist is zero)
+ # and it is not a derived file. If for some reason, we
+ # are explicitly building a file IN a Repository, we don't
+ # want it to show up in the build tree. This is usually the
+ # case with BuildDir(). We only want to find pre-existing files.
+ if (not must_exist or rnode.exists()) and \
+ (not rnode.builder or isinstance(rnode, Dir)):
+ ret.append(rnode)
+ except TypeError:
+ pass # Wrong type of node.
+ # Prepend directory name
+ name = d.name + os.sep + name
+ # Go up one directory
+ d = d.get_dir()
return ret
-
-class Entry(SCons.Node.Node):
- """A generic class for file system entries. This class if for
- when we don't know yet whether the entry being looked up is a file
- or a directory. Instances of this class can morph into either
- Dir or File objects by a later, more precise lookup.
-
- Note: this class does not define __cmp__ and __hash__ for efficiency
- reasons. SCons does a lot of comparing of Entry objects, and so that
- operation must be as fast as possible, which means we want to use
- Python's built-in object identity comparison.
- """
-
- def __init__(self, name, directory, fs):
- """Initialize a generic file system Entry.
-
- 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
- signatures."""
- SCons.Node.Node.__init__(self)
-
- self.name = name
-
- assert directory, "A directory must be provided"
-
- self.duplicate = directory.duplicate
- self.abspath = directory.abspath_ + name
- if str(directory.path) == '.':
- self.path = name
- else:
- self.path = directory.path_ + name
-
- self.path_ = self.path
- self.abspath_ = self.abspath
- self.dir = directory
- self.__doSrcpath(self.duplicate)
- self.srcpath_ = self.srcpath
- self.cwd = None # will hold the SConscript directory for target nodes
- self._local = None
- self.fs = fs # The filesystem that this entry is part of
-
- def get_dir(self):
- return self.dir
-
- def adjust_srcpath(self, duplicate):
- self.__doSrcpath(duplicate)
-
- def __doSrcpath(self, duplicate):
- self.duplicate = duplicate
- if str(self.dir.srcpath) == '.':
- self.srcpath = self.name
- else:
- self.srcpath = self.dir.srcpath_ + self.name
-
- def __str__(self):
- """A FS node's string representation is its path name."""
- if self.duplicate or self.builder:
- return self.path
- else:
- return self.srcpath
-
- 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."""
- if os.path.isfile(self.abspath):
- self.__class__ = File
- self._morph()
- return File.get_contents(self)
- if os.path.isdir(self.abspath):
- self.__class__ = Dir
- self._morph()
- return Dir.get_contents(self)
- raise AttributeError
-
- def exists(self):
- if not hasattr(self, '_exists'):
- self._exists = os.path.exists(str(self))
- return self._exists
-
- def rexists(self):
- if not hasattr(self, '_rexists'):
- self._rexists = os.path.exists(self.rstr())
- return self._rexists
-
- def get_parents(self):
- parents = SCons.Node.Node.get_parents(self)
- if self.dir and not isinstance(self.dir, ParentOfRoot):
- parents.append(self.dir)
- return parents
-
- def current(self, calc):
- """If the underlying path doesn't exist, we know the node is
- not current without even checking the signature, so return 0.
- Otherwise, return None to indicate that signature calculation
- should proceed as normal to find out if the node is current."""
- bsig = calc.bsig(self)
- if not self.exists():
- return 0
- return calc.current(self, bsig)
-
- def is_under(self, dir):
- if self is dir:
- return 1
- else:
- return self.dir.is_under(dir)
-
- def set_local(self):
- self._local = 1
-
-
-
# XXX TODO?
# Annotate with the creator
# rel_path
@@ -497,15 +543,53 @@ class Dir(Entry):
self.path_ = self.path + os.sep
self.abspath_ = self.abspath + os.sep
- self.srcpath_ = self.srcpath + os.sep
-
+ self.repositories = []
+ self.srcdir = None
+
self.entries = {}
self.entries['.'] = self
self.entries['..'] = self.dir
self.cwd = self
self.builder = 1
self._sconsign = None
-
+
+ def __clearRepositoryCache(self, duplicate=None):
+ """Called when we change the repository(ies) for a directory.
+ This clears any cached information that is invalidated by changing
+ the repository."""
+
+ for node in self.entries.values():
+ if node != self.dir:
+ if node != self and isinstance(node, Dir):
+ node.__clearRepositoryCache(duplicate)
+ else:
+ try:
+ del node._srcreps
+ except AttributeError:
+ pass
+ try:
+ del node._rfile
+ except AttributeError:
+ pass
+ try:
+ del node._rexists
+ except AttributeError:
+ pass
+ try:
+ del node._exists
+ except AttributeError:
+ pass
+ try:
+ del node._srcnode
+ except AttributeError:
+ pass
+ if duplicate != None:
+ node.duplicate=duplicate
+
+ def __resetDuplicate(self, node):
+ if node != self:
+ node.duplicate = node.get_dir().duplicate
+
def Dir(self, name):
"""Create a directory node named 'name' relative to this directory."""
return self.fs.Dir(name, self)
@@ -513,23 +597,32 @@ class Dir(Entry):
def File(self, name):
"""Create file node named 'name' relatove to this directory."""
return self.fs.File(name, self)
-
- def __doReparent(self, duplicate):
- for ent in self.entries.values():
- if not ent is self and not ent is self.dir:
- ent.adjust_srcpath(duplicate)
-
- def adjust_srcpath(self, duplicate):
- Entry.adjust_srcpath(self, duplicate)
- self.srcpath_ = self.srcpath + os.sep
- self.__doReparent(duplicate)
def link(self, srcdir, duplicate):
"""Set this directory as the build directory for the
supplied source directory."""
- self.srcpath = srcdir.path
- self.srcpath_ = srcdir.path_
- self.__doReparent(duplicate)
+ self.srcdir = srcdir
+ self.duplicate = duplicate
+ self.__clearRepositoryCache(duplicate)
+
+ def getRepositories(self):
+ """Returns a list of repositories for this directory."""
+ if self.srcdir and not self.duplicate:
+ try:
+ return self._srcreps
+ except AttributeError:
+ self._srcreps = self.fs.Rsearchall(self.srcdir.path,
+ clazz=Dir,
+ must_exist=0,
+ cwd=self.fs.Top) \
+ + self.repositories
+ return self._srcreps
+ return self.repositories
+
+ def addRepository(self, dir):
+ if not dir in self.repositories and dir != self:
+ self.repositories.append(dir)
+ self.__clearRepositoryCache()
def up(self):
return self.entries['..']
@@ -595,32 +688,6 @@ class Dir(Entry):
self._sconsign = SCons.Sig.SConsignFile(self)
return self._sconsign
- def __str__(self):
- # Reimplemented from Entry since, unlike for
- # Entry and File, we want to return the source
- # path *even if* the builder is non-zero
- # (which it always is for a directory)
- if self.duplicate:
- return self.path
- else:
- return self.srcpath
-
- def exists(self):
- # Again, directories are special...we don't care if their
- # source path exists, we only care about the path.
- if not hasattr(self, '_exists'):
- self._exists = os.path.exists(self.path)
- return self._exists
-
- def rexists(self):
- # Again, directories are special...we don't care if their
- # source path exists, we only care about the path.
- if not hasattr(self, '_rexists'):
- self._rexists = os.path.exists(self.rstr())
- return self._rexists
-
-
-
# XXX TODO?
# base_suf
# suffix
@@ -648,12 +715,8 @@ class File(Entry):
def RDirs(self, pathlist):
"""Search for a list of directories in the Repository list."""
- def path_dirs(rep, path, Dir=self.Dir):
- if rep:
- path = os.path.join(rep, path)
- return Dir(path)
-
- return self.fs.Rsearchall(pathlist, path_dirs)
+ return self.fs.Rsearchall(pathlist, clazz=Dir, must_exist=0,
+ cwd=self.cwd)
def generate_build_env(self):
env = SCons.Node.Node.generate_build_env(self)
@@ -665,6 +728,7 @@ class File(Entry):
def _morph(self):
"""Turn a file system node into a File object."""
self.created = 0
+ self._local = 0
def root(self):
return self.dir.root()
@@ -733,56 +797,7 @@ class File(Entry):
return scanner.scan(self, env, target)
else:
return []
-
- def exists(self):
- if not hasattr(self, '_exists'):
- 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)
- self._exists = os.path.exists(str(self))
- return self._exists
-
- def rexists(self):
- if not hasattr(self, '_rexists'):
- if self.path != self.srcpath:
- if os.path.exists(self.srcpath):
- if self.duplicate and not self.created:
- self.created = 1
- if os.path.exists(self.path):
- os.unlink(self.path)
- self.__createDir()
- file_link(self.srcpath, self.path)
- self._rexists = 1
- return self._rexists
- for rep in self.fs.Repositories:
- if not os.path.isabs(self.path):
- f = os.path.join(rep.path, self.path)
- if os.path.exists(f):
- self._rexists = 1
- return self._rexists
- f = os.path.join(rep.path, self.srcpath)
- if os.path.exists(f):
- if self.duplicate and not self.created:
- self.created = 1
- if os.path.exists(self.path):
- os.unlink(self.path)
- self.__createDir()
- file_link(f, self.path)
- else:
- self.srcpath = f
- self.srcpath_ = f + os.sep
- self._rexists = 1
- return self._rexists
- self._rexists = None
- else:
- self._rexists = Entry.rexists(self)
- return self._rexists
-
+
def scanner_key(self):
return os.path.splitext(self.name)[1]
@@ -829,6 +844,26 @@ class File(Entry):
return 1
return None
+ def exists(self):
+ # Duplicate from source path if we are set up to do this.
+ if self.duplicate and not self.builder and not self.created:
+ src=self.srcnode().rfile()
+ if src.exists() and src.abspath != self.abspath:
+ try:
+ os.unlink(self.abspath)
+ except OSError:
+ pass
+ self.__createDir()
+ file_link(src.abspath,
+ self.abspath)
+ self.created = 1
+
+ # Set our exists cache accordingly
+ self._exists=1
+ self._rexists=1
+ return 1
+ return Entry.exists(self)
+
def current(self, calc):
bsig = calc.bsig(self)
if not self.exists():
@@ -853,20 +888,15 @@ class File(Entry):
def rfile(self):
if not hasattr(self, '_rfile'):
self._rfile = self
- if not os.path.isabs(self.path) and not os.path.isfile(self.path):
- def file_node(dir, path, fs=self.fs):
- if dir:
- path = os.path.join(dir, path)
- if os.path.isfile(path):
- return fs.File(path)
- return None
- n = self.fs.Rsearch(self.path, file_node)
+ if not self.exists():
+ n = self.fs.Rsearch(self.path, clazz=File,
+ cwd=self.fs.Top)
if n:
self._rfile = n
return self._rfile
def rstr(self):
- return os.path.normpath(str(self.rfile()))
+ return str(self.rfile())
default_fs = FS()
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 51d4a6f..0c7bd69 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -82,23 +82,23 @@ class BuildDirTestCase(unittest.TestCase):
f1 = fs.File('build/test1')
fs.BuildDir('build', 'src')
f2 = fs.File('build/test2')
- assert f1.srcpath == os.path.normpath('src/test1'), f1.srcpath
- assert f2.srcpath == os.path.normpath('src/test2'), f2.srcpath
+ assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
+ assert f2.srcnode().path == os.path.normpath('src/test2'), f2.srcnode().path
fs = SCons.Node.FS.FS()
f1 = fs.File('build/test1')
fs.BuildDir('build', '.')
f2 = fs.File('build/test2')
- assert f1.srcpath == 'test1', f1.srcpath
- assert f2.srcpath == 'test2', f2.srcpath
+ assert f1.srcnode().path == 'test1', f1.srcnode().path
+ assert f2.srcnode().path == 'test2', f2.srcnode().path
fs = SCons.Node.FS.FS()
fs.BuildDir('build/var1', 'src')
fs.BuildDir('build/var2', 'src')
f1 = fs.File('build/var1/test1')
f2 = fs.File('build/var2/test1')
- assert f1.srcpath == os.path.normpath('src/test1'), f1.srcpath
- assert f2.srcpath == os.path.normpath('src/test1'), f2.srcpath
+ assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
+ assert f2.srcnode().path == os.path.normpath('src/test1'), f2.srcnode().path
fs = SCons.Node.FS.FS()
fs.BuildDir('../var1', 'src')
@@ -106,56 +106,136 @@ class BuildDirTestCase(unittest.TestCase):
f1 = fs.File('../var1/test1')
f2 = fs.File('../var2/test1')
assert hasattr(f1, 'overrides')
- assert f1.srcpath == os.path.normpath('src/test1'), f1.srcpath
- assert f2.srcpath == os.path.normpath('src/test1'), f2.srcpath
+ assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
+ assert f2.srcnode().path == os.path.normpath('src/test1'), f2.srcnode().path
+
+ # Set up some files
+ test.subdir('work', ['work', 'src'])
+ test.subdir(['work', 'build'], ['work', 'build', 'var1'])
+ test.subdir(['work', 'build', 'var2'])
+ test.subdir('rep1', ['rep1', 'src'])
+ test.subdir(['rep1', 'build'], ['rep1', 'build', 'var1'])
+ test.subdir(['rep1', 'build', 'var2'])
+
+ # A source file in the source directory
+ test.write([ 'work', 'src', 'test.in' ], 'test.in')
+
+ # A source file in the repository
+ test.write([ 'rep1', 'src', 'test2.in' ], 'test2.in')
+
+ # Some source files in the build directory
+ test.write([ 'work', 'build', 'var2', 'test.in' ], 'test.old')
+ test.write([ 'work', 'build', 'var2', 'test2.in' ], 'test2.old')
- fs = SCons.Node.FS.FS()
+ # An old derived file in the build directories
+ test.write([ 'work', 'build', 'var1', 'test.out' ], 'test.old')
+ test.write([ 'work', 'build', 'var2', 'test.out' ], 'test.old')
+
+ # And just in case we are weird, a derived file in the source
+ # dir.
+ test.write([ 'work', 'src', 'test.out' ], 'test.out.src')
+
+ # A derived file in the repository
+ test.write([ 'rep1', 'build', 'var1', 'test2.out' ], 'test2.out_rep')
+ test.write([ 'rep1', 'build', 'var2', 'test2.out' ], 'test2.out_rep')
+
+ fs = SCons.Node.FS.FS(test.workpath('work'))
fs.BuildDir('build/var1', 'src', duplicate=0)
fs.BuildDir('build/var2', 'src')
- f1 = fs.File('build/var1/test')
+ f1 = fs.File('build/var1/test.in')
f1out = fs.File('build/var1/test.out')
f1out.builder = 1
- f2 = fs.File('build/var2/test')
+ f1out_2 = fs.File('build/var1/test2.out')
+ f1out_2.builder = 1
+ f2 = fs.File('build/var2/test.in')
f2out = fs.File('build/var2/test.out')
f2out.builder = 1
-
- assert f1.srcpath == os.path.normpath('src/test'), f1.srcpath
- assert f1out.srcpath == os.path.normpath('src/test.out'), f1out.srcpath
- assert str(f1) == os.path.normpath('src/test'), str(f1)
- assert str(f1out) == os.path.normpath('build/var1/test.out'), str(f1out)
- assert f2.srcpath == os.path.normpath('src/test'), f2.srcpath
- assert f2out.srcpath == os.path.normpath('src/test.out'), f2out.srcpath
- assert str(f2) == os.path.normpath('build/var2/test'), str(f2)
- assert str(f2out) == os.path.normpath('build/var2/test.out'), str(f2out)
-
- assert not f1.exists()
- assert not f1out.exists()
- assert not f2.exists()
- assert not f2out.exists()
-
- test.subdir('src')
- test.write(['src', 'test'], "src/test\n")
- test.write(['src', 'test'], "src/test.out\n")
-
+ f2out_2 = fs.File('build/var2/test2.out')
+ f2out_2.builder = 1
+ fs.Repository(test.workpath('rep1'))
+
+ assert f1.srcnode().path == os.path.normpath('src/test.in'),\
+ f1.srcnode().path
+ # str(node) returns source path for duplicate = 0
+ assert str(f1) == os.path.normpath('src/test.in'), str(f1)
+ # Build path does not exist
assert not f1.exists()
- assert not f1out.exists()
- assert not f2.exists()
- assert not f2out.exists()
-
- f1.built()
- f2.built()
-
- assert f1.exists()
- assert not f1out.exists()
- assert not f2.exists()
- assert not f2out.exists()
-
- d1 = fs.Dir('build/var1')
- d2 = fs.Dir('build/var2')
-
- assert str(d1) == 'src', str(d1)
- assert str(d2) == os.path.normpath('build/var2'), str(d2)
+ # But source path does
+ assert f1.srcnode().exists()
+ # And duplicate=0 should also work just like a Repository
+ assert f1.rexists()
+ # rfile() should point to the source path
+ assert f1.rfile().path == os.path.normpath('src/test.in'),\
+ f1.rfile().path
+
+ assert f2.srcnode().path == os.path.normpath('src/test.in'),\
+ f2.srcnode().path
+ # str(node) returns build path for duplicate = 1
+ assert str(f2) == os.path.normpath('build/var2/test.in'), str(f2)
+ # Build path exists
+ assert f2.exists()
+ # ...and should copy the file from src to build path
+ assert test.read(['work', 'build', 'var2', 'test.in']) == 'test.in',\
+ test.read(['work', 'build', 'var2', 'test.in'])
+ # Since exists() is true, so should rexists() be
+ assert f2.rexists()
+ f3 = fs.File('build/var1/test2.in')
+ f4 = fs.File('build/var2/test2.in')
+
+ assert f3.srcnode().path == os.path.normpath('src/test2.in'),\
+ f3.srcnode().path
+ # str(node) returns source path for duplicate = 0
+ assert str(f3) == os.path.normpath('src/test2.in'), str(f3)
+ # Build path does not exist
+ assert not f3.exists()
+ # Source path does not either
+ assert not f3.srcnode().exists()
+ # But we do have a file in the Repository
+ assert f3.rexists()
+ # rfile() should point to the source path
+ assert f3.rfile().path == test.workpath('rep1/src/test2.in'),\
+ f3.rfile().path
+
+ assert f4.srcnode().path == os.path.normpath('src/test2.in'),\
+ f4.srcnode().path
+ # str(node) returns build path for duplicate = 1
+ assert str(f4) == os.path.normpath('build/var2/test2.in'), str(f4)
+ # Build path should exist
+ assert f4.exists()
+ # ...and copy over the file into the local build path
+ assert test.read(['work', 'build', 'var2', 'test2.in']) == 'test2.in'
+ # should exist in repository, since exists() is true
+ assert f4.rexists()
+ # rfile() should point to ourselves
+ assert f4.rfile().path == os.path.normpath('build/var2/test2.in'),\
+ f4.rfile().path
+
+ f5 = fs.File('build/var1/test.out')
+ f6 = fs.File('build/var2/test.out')
+
+ assert f5.exists()
+ # We should not copy the file from the source dir, since this is
+ # a derived file.
+ assert test.read(['work', 'build', 'var1', 'test.out']) == 'test.old'
+
+ assert f6.exists()
+ # We should not copy the file from the source dir, since this is
+ # a derived file.
+ assert test.read(['work', 'build', 'var2', 'test.out']) == 'test.old'
+ f7 = fs.File('build/var1/test2.out')
+ f8 = fs.File('build/var2/test2.out')
+
+ assert not f7.exists()
+ assert f7.rexists()
+ assert f7.rfile().path == test.workpath('rep1/build/var1/test2.out'),\
+ f7.rfile().path
+
+ assert not f8.exists()
+ assert f8.rexists()
+ assert f8.rfile().path == test.workpath('rep1/build/var2/test2.out'),\
+ f8.rfile().path
+
# Test to see if file_link() works...
test.subdir('src','build')
test.write('src/foo', 'foo\n')
@@ -664,8 +744,9 @@ class RepositoryTestCase(unittest.TestCase):
fs.Repository(os.path.join('bar', 'foo'))
fs.Repository('bar')
- assert len(fs.Repositories) == 4, fs.Repositories
- r = map(lambda x, np=os.path.normpath: np(str(x)), fs.Repositories)
+ rep = fs.Dir('#').getRepositories()
+ assert len(rep) == 4, map(str, rep)
+ r = map(lambda x, np=os.path.normpath: np(str(x)), rep)
assert r == ['foo',
os.path.join('foo', 'bar'),
os.path.join('bar', 'foo'),
@@ -703,15 +784,6 @@ class RepositoryTestCase(unittest.TestCase):
assert fs.Rsearch('f2')
assert fs.Rsearch(f3) is f3
- def my_exists(rep, path):
- if rep:
- path = os.path.join(rep, path)
- return os.path.exists(path)
-
- assert not fs.Rsearch('f1', my_exists)
- assert fs.Rsearch('f2', my_exists)
- assert fs.Rsearch('f3', my_exists)
-
list = fs.Rsearchall(fs.Dir('d1'))
assert len(list) == 1, list
assert list[0].path == 'd1', list[0].path
@@ -727,36 +799,41 @@ class RepositoryTestCase(unittest.TestCase):
assert list == [], list
test.subdir(['work', 'd2'])
+ fs.File('d2').built() # Clear exists cache
list = fs.Rsearchall('d2')
- assert list == ['d2'], list
+ assert map(str, list) == ['d2'], list
test.subdir(['rep2', 'd2'])
+ fs.File('../rep2/d2').built() # Clear exists cache
list = fs.Rsearchall('d2')
- assert list == ['d2', test.workpath('rep2', 'd2')], list
+ assert map(str, list) == ['d2', test.workpath('rep2', 'd2')], list
test.subdir(['rep1', 'd2'])
+ fs.File('../rep1/d2').built() # Clear exists cache
list = fs.Rsearchall('d2')
- assert list == ['d2',
- test.workpath('rep1', 'd2'),
- test.workpath('rep2', 'd2')], list
+ assert map(str, list) == ['d2',
+ test.workpath('rep1', 'd2'),
+ test.workpath('rep2', 'd2')], list
list = fs.Rsearchall(['d3', 'd4'])
assert list == [], list
test.subdir(['work', 'd3'])
- list = fs.Rsearchall(['d3', 'd4'])
+ fs.File('d3').built() # Clear exists cache
+ list = map(str, fs.Rsearchall(['d3', 'd4']))
assert list == ['d3'], list
test.subdir(['rep3', 'd4'])
- list = fs.Rsearchall(['d3', 'd4'])
+ fs.File('../rep3/d4').built() # Clear exists cache
+ list = map(str, fs.Rsearchall(['d3', 'd4']))
assert list == ['d3', test.workpath('rep3', 'd4')], list
- list = fs.Rsearchall(string.join(['d3', 'd4'], os.pathsep))
+ list = map(str, fs.Rsearchall(string.join(['d3', 'd4'], os.pathsep)))
assert list == ['d3', test.workpath('rep3', 'd4')], list
work_d4 = fs.File(os.path.join('work', 'd4'))
- list = fs.Rsearchall(['d3', work_d4])
- assert list == ['d3', work_d4], list
+ list = map(str, fs.Rsearchall(['d3', work_d4]))
+ assert list == ['d3', str(work_d4)], list
fs.BuildDir('build', '.')
diff --git a/src/engine/SCons/Scanner/C.py b/src/engine/SCons/Scanner/C.py
index d12fd45..47b6ea7 100644
--- a/src/engine/SCons/Scanner/C.py
+++ b/src/engine/SCons/Scanner/C.py
@@ -79,12 +79,8 @@ def scan(node, env, target, fs = SCons.Node.FS.default_fs):
# node.includes - the result of include_re.findall()
if not hasattr(target, 'cpppath'):
- def Dir(rep, path, dir=target.cwd, fs=fs):
- if rep:
- path = os.path.join(rep, path)
- return fs.Dir(path, dir)
try:
- target.cpppath = tuple(fs.Rsearchall(env['CPPPATH'], Dir))
+ target.cpppath = tuple(fs.Rsearchall(SCons.Util.mapPaths(env['CPPPATH'], target.cwd), clazz=SCons.Node.FS.Dir))
except KeyError:
target.cpppath = ()
diff --git a/src/engine/SCons/Scanner/Fortran.py b/src/engine/SCons/Scanner/Fortran.py
index 5e0d6d3..fd8c971 100644
--- a/src/engine/SCons/Scanner/Fortran.py
+++ b/src/engine/SCons/Scanner/Fortran.py
@@ -77,12 +77,8 @@ def scan(node, env, target, fs = SCons.Node.FS.default_fs):
# node.includes - the result of include_re.findall()
if not hasattr(target, 'f77path'):
- def Dir(rep, path, dir=target.cwd, fs=fs):
- if rep:
- path = os.path.join(rep, path)
- return fs.Dir(path, dir)
try:
- target.f77path = tuple(fs.Rsearchall(env['F77PATH'], Dir))
+ target.f77path = tuple(fs.Rsearchall(SCons.Util.mapPaths(env['F77PATH'], target.cwd), clazz=SCons.Node.FS.Dir))
except KeyError:
target.f77path = ()
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index 65d900c..a0bab35 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -997,8 +997,9 @@ def _main():
# -U with default targets
default_targets = SCons.Script.SConscript.default_targets
def check_dir(x):
- cwd = SCons.Node.FS.default_fs.Dir(x.cwd.srcpath)
- return cwd == target_top
+ reps = SCons.Node.FS.default_fs.Rsearchall(str(x.cwd), must_exist=0,
+ clazz=SCons.Node.FS.Dir)
+ return target_top in reps
default_targets = filter(check_dir, default_targets)
SCons.Script.SConscript.default_targets = default_targets
target_top = None
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 63c992e..3a39c4e 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -370,6 +370,40 @@ def Split(arg):
else:
return [arg]
+def mapPaths(paths, dir):
+ """Takes a single node or string, or a list of nodes and/or
+ strings. We leave the nodes untouched, but we put the strings
+ under the supplied directory node dir, if they are not an absolute
+ path.
+
+ For instance, the following:
+
+ n = SCons.Node.FS.default_fs.File('foo')
+ mapPaths([ n, 'foo', '/bar' ],
+ SCons.Node.FS.default_fs.Dir('baz'))
+
+ ...would return:
+
+ [ n, 'baz/foo', '/bar' ]
+ """
+
+ def mapPathFunc(path, dir=dir):
+ if dir and is_String(path):
+ if not path:
+ return str(dir)
+ if os.path.isabs(path) or path[0] == '#':
+ return path
+ return dir.path_ + path
+ return path
+
+ if not is_List(paths):
+ paths = [ paths ]
+ ret = map(mapPathFunc, paths)
+ if len(ret) == 1:
+ ret = ret[0]
+ return ret
+
+
if hasattr(types, 'UnicodeType'):
def is_String(e):
return type(e) is types.StringType \