summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2003-02-26 17:40:22 (GMT)
committerSteven Knight <knight@baldmt.com>2003-02-26 17:40:22 (GMT)
commitc98c5391f5afa134589db88ebe986368a1b6097f (patch)
tree1a7e0f06222b16f346e09b1dcfc185e470fbd3e5 /src
parent8a816e6362b715a238183ae25551dbb6df7cddc3 (diff)
downloadSCons-c98c5391f5afa134589db88ebe986368a1b6097f.zip
SCons-c98c5391f5afa134589db88ebe986368a1b6097f.tar.gz
SCons-c98c5391f5afa134589db88ebe986368a1b6097f.tar.bz2
Fix str(Node.FS) in an SConscript file, and add a separate src_dir argument to SConscript(). (Charles Crain)
Diffstat (limited to 'src')
-rw-r--r--src/CHANGES.txt7
-rw-r--r--src/engine/SCons/Node/FS.py44
-rw-r--r--src/engine/SCons/Node/FSTests.py20
-rw-r--r--src/engine/SCons/Scanner/CTests.py1
-rw-r--r--src/engine/SCons/Scanner/FortranTests.py1
-rw-r--r--src/engine/SCons/Script/SConscript.py40
-rw-r--r--src/engine/SCons/Script/__init__.py8
7 files changed, 94 insertions, 27 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index a913314..ccdf159 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -14,6 +14,13 @@ RELEASE 0.12 - XXX
- Added support for the Perforce source code management system.
+ - Fix str(Node.FS) so that it returns a path relative to the calling
+ SConscript file's directory, not the top-level directory.
+
+ - Added support for a separate src_dir argument to SConscript()
+ that allows explicit specification of where the source files
+ for an SConscript file can be found.
+
From Steven Knight:
- Added an INSTALL construction variable that can be set to a function
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 8d5a45f..a6dd7ae 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 recurse_get_path(self, dir, path_elems):
+ return path_elems
+
def src_builder(self):
return None
@@ -201,6 +204,7 @@ class Entry(SCons.Node.Node):
self.name = name
self.fs = fs
+ self.relpath = {}
assert directory, "A directory must be provided"
@@ -222,8 +226,8 @@ class Entry(SCons.Node.Node):
def __str__(self):
"""A FS node's string representation is its path name."""
if self.duplicate or self.has_builder():
- return self.path
- return self.srcnode().path
+ return self.get_path()
+ return self.srcnode().get_path()
def get_contents(self):
"""Fetch the contents of the entry.
@@ -297,6 +301,32 @@ class Entry(SCons.Node.Node):
self._srcnode = self
return self._srcnode
+ def recurse_get_path(self, dir, path_elems):
+ """Recursively build a path relative to a supplied directory
+ node."""
+ if self != dir:
+ path_elems.append(self.name)
+ path_elems = self.dir.recurse_get_path(dir, path_elems)
+ return path_elems
+
+ def get_path(self, dir=None):
+ """Return path relative to the current working directory of the
+ FS object that owns us."""
+ if not dir:
+ dir = self.fs.getcwd()
+ try:
+ return self.relpath[dir]
+ except KeyError:
+ if self == dir:
+ # Special case, return "." as the path
+ ret = '.'
+ else:
+ path_elems = self.recurse_get_path(dir, [])
+ path_elems.reverse()
+ ret = string.join(path_elems, os.sep)
+ self.relpath[dir] = ret
+ return ret
+
def set_src_builder(self, builder):
"""Set the source code builder for this node."""
self.sbuilder = builder
@@ -474,12 +504,16 @@ class FS:
directory = self._cwd
return (os.path.normpath(name), directory)
- def chdir(self, dir):
+ def chdir(self, dir, change_os_dir=0):
"""Change the current working directory for lookups.
+ If change_os_dir is true, we will also change the "real" cwd
+ to match.
"""
self.__setTopLevelDir()
if not dir is None:
self._cwd = dir
+ if change_os_dir:
+ os.chdir(dir.abspath)
def Entry(self, name, directory = None, create = 1, klass=None):
"""Lookup or create a generic Entry node with the specified name.
@@ -863,11 +897,11 @@ class File(Entry):
def get_contents(self):
if not self.rexists():
return ''
- return open(self.rstr(), "rb").read()
+ return open(self.rfile().abspath, "rb").read()
def get_timestamp(self):
if self.rexists():
- return os.path.getmtime(self.rstr())
+ return os.path.getmtime(self.rfile().abspath)
else:
return 0
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 1e8bc92..5e4bb52 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -190,8 +190,8 @@ class BuildDirTestCase(unittest.TestCase):
assert str(f1) == os.path.normpath('src/test.in'), str(f1)
# Build path does not exist
assert not f1.exists()
- # But source path does
- assert f1.srcnode().exists()
+ # ...but the actual file is not there...
+ assert not os.path.exists(f1.abspath)
# And duplicate=0 should also work just like a Repository
assert f1.rexists()
# rfile() should point to the source path
@@ -270,6 +270,16 @@ class BuildDirTestCase(unittest.TestCase):
# Verify the Mkdir and Link actions are called
f9 = fs.File('build/var2/new_dir/test9.out')
+ # Test for an interesting pathological case...we have a source
+ # file in a build path, but not in a source path. This can
+ # happen if you switch from duplicate=1 to duplicate=0, then
+ # delete a source file. At one time, this would cause exists()
+ # to return a 1 but get_contents() to throw.
+ test.write([ 'work', 'build', 'var1', 'asourcefile' ], 'stuff')
+ f10 = fs.File('build/var1/asourcefile')
+ assert f10.exists()
+ assert f10.get_contents() == 'stuff', f10.get_contents()
+
save_Mkdir = SCons.Node.FS.Mkdir
dir_made = []
def mkdir_func(target, source, env, dir_made=dir_made):
@@ -801,9 +811,11 @@ class FSTestCase(unittest.TestCase):
fs = SCons.Node.FS.FS()
assert str(fs.getcwd()) == ".", str(fs.getcwd())
fs.chdir(fs.Dir('subdir'))
- assert str(fs.getcwd()) == "subdir", str(fs.getcwd())
+ # The cwd's path is always "."
+ assert str(fs.getcwd()) == ".", str(fs.getcwd())
+ assert fs.getcwd().path == 'subdir', fs.getcwd().path
fs.chdir(fs.Dir('../..'))
- assert str(fs.getcwd()) == test.workdir, str(fs.getcwd())
+ assert fs.getcwd().path == test.workdir, fs.getcwd().path
f1 = fs.File(test.workpath("do_i_exist"))
assert not f1.exists()
diff --git a/src/engine/SCons/Scanner/CTests.py b/src/engine/SCons/Scanner/CTests.py
index 332f7e1..c865e6e 100644
--- a/src/engine/SCons/Scanner/CTests.py
+++ b/src/engine/SCons/Scanner/CTests.py
@@ -324,6 +324,7 @@ class CScannerTestCase10(unittest.TestCase):
path = s.path(env)
test.write('include/fa.cpp', test.read('fa.cpp'))
deps = s(fs.File('#include/fa.cpp'), env, path)
+ fs.chdir(fs.Dir('..'))
deps_match(self, deps, [ 'include/fa.h', 'include/fb.h' ])
test.unlink('include/fa.cpp')
diff --git a/src/engine/SCons/Scanner/FortranTests.py b/src/engine/SCons/Scanner/FortranTests.py
index b2cf14c..7564c1e 100644
--- a/src/engine/SCons/Scanner/FortranTests.py
+++ b/src/engine/SCons/Scanner/FortranTests.py
@@ -338,6 +338,7 @@ class FortranScannerTestCase12(unittest.TestCase):
path = s.path(env)
test.write('include/fff4.f', test.read('fff4.f'))
deps = s(fs.File('#include/fff4.f'), env, path)
+ fs.chdir(fs.Dir('..'))
deps_match(self, deps, ['include/f4.f'])
test.unlink('include/fff4.f')
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index 4c54879..dfcfe5b 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -163,7 +163,17 @@ def GetSConscriptFilenames(ls, kw):
if not src_dir:
src_dir, fname = os.path.split(str(files[0]))
else:
- fname = os.path.split(files[0])[1]
+ if not isinstance(src_dir, SCons.Node.Node):
+ src_dir = SCons.Node.FS.default_fs.Dir(src_dir)
+ fn = files[0]
+ if not isinstance(fn, SCons.Node.Node):
+ fn = SCons.Node.FS.default_fs.File(fn)
+ if fn.is_under(src_dir):
+ # Get path relative to the source directory.
+ fname = fn.get_path(src_dir)
+ else:
+ # Fast way to only get the terminal path component of a Node.
+ fname = fn.get_path(fn.dir)
BuildDir(build_dir, src_dir, duplicate)
files = [os.path.join(str(build_dir), fname)]
@@ -187,7 +197,13 @@ def SConscript(*ls, **kw):
else:
f = SCons.Node.FS.default_fs.File(str(fn))
_file_ = None
+ old_dir = SCons.Node.FS.default_fs.getcwd()
+ SCons.Node.FS.default_fs.chdir(SCons.Node.FS.default_fs.Dir('#'),
+ change_os_dir=1)
if f.rexists():
+ # Change directory to top of source tree to make sure
+ # the os's cwd and the cwd of SCons.Node.FS.default_fs
+ # match so we can open the SConscript.
_file_ = open(f.rstr(), "r")
elif f.has_builder():
# The SConscript file apparently exists in a source
@@ -199,17 +215,13 @@ def SConscript(*ls, **kw):
s = str(f)
if os.path.exists(s):
_file_ = open(s, "r")
-
if _file_:
- SCons.Node.FS.default_fs.chdir(f.dir)
- if sconscript_chdir:
- old_dir = os.getcwd()
- os.chdir(str(f.dir))
-
+ SCons.Node.FS.default_fs.chdir(f.dir,
+ change_os_dir=sconscript_chdir)
# prepend the SConscript directory to sys.path so
# that Python modules in the SConscript directory can
# be easily imported
- sys.path = [os.path.abspath(str(f.dir))] + sys.path
+ sys.path = [ f.dir.abspath ] + sys.path
# This is the magic line that actually reads up and
# executes the stuff in the SConscript file. We
@@ -227,7 +239,8 @@ def SConscript(*ls, **kw):
frame = stack.pop()
SCons.Node.FS.default_fs.chdir(frame.prev_dir)
if old_dir:
- os.chdir(old_dir)
+ SCons.Node.FS.default_fs.chdir(old_dir,
+ change_os_dir=sconscript_chdir)
results.append(frame.retval)
@@ -390,11 +403,10 @@ def Clean(target, files):
else:
nodes.extend(SCons.Node.arg2nodes(f, SCons.Node.FS.default_fs.Entry))
- s = str(target)
- if clean_targets.has_key(s):
- clean_targets[s].extend(nodes)
- else:
- clean_targets[s] = nodes
+ try:
+ clean_targets[target].extend(nodes)
+ except KeyError:
+ clean_targets[target] = nodes
def AddPreAction(files, action):
nodes = SCons.Node.arg2nodes(files, SCons.Node.FS.default_fs.Entry)
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index 41b95dc..3716d2e 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -153,8 +153,8 @@ class CleanTask(SCons.Taskmaster.Task):
if (self.targets[0].has_builder() or self.targets[0].side_effect) \
and not os.path.isdir(str(self.targets[0])):
display("Removed " + str(self.targets[0]))
- if SCons.Script.SConscript.clean_targets.has_key(str(self.targets[0])):
- files = SCons.Script.SConscript.clean_targets[str(self.targets[0])]
+ if SCons.Script.SConscript.clean_targets.has_key(self.targets[0]):
+ files = SCons.Script.SConscript.clean_targets[self.targets[0]]
for f in files:
SCons.Util.fs_delete(str(f), 0)
@@ -168,8 +168,8 @@ class CleanTask(SCons.Taskmaster.Task):
else:
if removed:
display("Removed " + str(t))
- if SCons.Script.SConscript.clean_targets.has_key(str(self.targets[0])):
- files = SCons.Script.SConscript.clean_targets[str(self.targets[0])]
+ if SCons.Script.SConscript.clean_targets.has_key(self.targets[0]):
+ files = SCons.Script.SConscript.clean_targets[self.targets[0]]
for f in files:
SCons.Util.fs_delete(str(f))