diff options
author | Steven Knight <knight@baldmt.com> | 2003-02-26 17:40:22 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2003-02-26 17:40:22 (GMT) |
commit | c98c5391f5afa134589db88ebe986368a1b6097f (patch) | |
tree | 1a7e0f06222b16f346e09b1dcfc185e470fbd3e5 /src | |
parent | 8a816e6362b715a238183ae25551dbb6df7cddc3 (diff) | |
download | SCons-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.txt | 7 | ||||
-rw-r--r-- | src/engine/SCons/Node/FS.py | 44 | ||||
-rw-r--r-- | src/engine/SCons/Node/FSTests.py | 20 | ||||
-rw-r--r-- | src/engine/SCons/Scanner/CTests.py | 1 | ||||
-rw-r--r-- | src/engine/SCons/Scanner/FortranTests.py | 1 | ||||
-rw-r--r-- | src/engine/SCons/Script/SConscript.py | 40 | ||||
-rw-r--r-- | src/engine/SCons/Script/__init__.py | 8 |
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)) |