summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Node
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2004-03-06 14:09:36 (GMT)
committerSteven Knight <knight@baldmt.com>2004-03-06 14:09:36 (GMT)
commit10e229b7a8e466d9fe1d193fa66a2bcd3fec3ee6 (patch)
tree1eaf77423e1ed4a4604c215ea2e84384519f2d44 /src/engine/SCons/Node
parent0486b66e2cdef2d174ff9eba0198947c4f8a9635 (diff)
downloadSCons-10e229b7a8e466d9fe1d193fa66a2bcd3fec3ee6.zip
SCons-10e229b7a8e466d9fe1d193fa66a2bcd3fec3ee6.tar.gz
SCons-10e229b7a8e466d9fe1d193fa66a2bcd3fec3ee6.tar.bz2
scons.0.92 - Implement a --duplicate= option. (Christoph Wiedemann)
Diffstat (limited to 'src/engine/SCons/Node')
-rw-r--r--src/engine/SCons/Node/FS.py84
-rw-r--r--src/engine/SCons/Node/FSTests.py132
2 files changed, 138 insertions, 78 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index dbcaf8a..3bf2ee4 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -66,29 +66,77 @@ import SCons.Warnings
# there should be *no* changes to the external file system(s)...
#
+def _copy_func(src, dest):
+ shutil.copy2(src, dest)
+ st=os.stat(src)
+ os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
+
+Valid_Duplicates = ['hard-soft-copy', 'soft-hard-copy',
+ 'hard-copy', 'soft-copy', 'copy']
+
+Link_Funcs = [] # contains the callables of the specified duplication style
+
+def set_duplicate(duplicate):
+ # Fill in the Link_Funcs list according to the argument
+ # (discarding those not available on the platform).
+
+ # Set up the dictionary that maps the argument names to the
+ # underlying implementations. We do this inside this function,
+ # not in the top-level module code, so that we can remap os.link
+ # and os.symlink for testing purposes.
+ try:
+ _hardlink_func = os.link
+ except AttributeError:
+ _hardlink_func = None
+
+ try:
+ _softlink_func = os.symlink
+ except AttributeError:
+ _softlink_func = None
+
+ link_dict = {
+ 'hard' : _hardlink_func,
+ 'soft' : _softlink_func,
+ 'copy' : _copy_func
+ }
+
+ if not duplicate in Valid_Duplicates:
+ raise SCons.Errors.InternalError, ("The argument of set_duplicate "
+ "should be in Valid_Duplicates")
+ global Link_Funcs
+ Link_Funcs = []
+ for func in string.split(duplicate,'-'):
+ if link_dict[func]:
+ Link_Funcs.append(link_dict[func])
+
def LinkFunc(target, source, env):
- t = target[0]
- dest = t.path
- fs = t.fs
- src = source[0].path
+ # Relative paths cause problems with symbolic links, so
+ # we use absolute paths, which may be a problem for people
+ # who want to move their soft-linked src-trees around. Those
+ # people should use the 'hard-copy' mode, softlinks cannot be
+ # used for that; at least I have no idea how ...
+ src = source[0].abspath
+ dest = target[0].abspath
dir, file = os.path.split(dest)
- if dir and not fs.isdir(dir):
- fs.makedirs(dir)
- # Now actually link the files. First try to make a hard link. If that
- # fails, try a symlink. If that fails then just copy it.
- try :
- fs.link(src, dest)
- except (AttributeError, OSError):
- try :
- fs.symlink(src, dest)
- except (AttributeError, OSError):
- fs.copy2(src, dest)
- st = fs.stat(src)
- fs.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
+ if dir and not os.path.isdir(dir):
+ os.makedirs(dir)
+ if not Link_Funcs:
+ # Set a default order of link functions.
+ set_duplicate('hard-soft-copy')
+ # Now link the files with the previously specified order.
+ for func in Link_Funcs:
+ try:
+ func(src,dest)
+ break
+ except OSError:
+ if func == Link_Funcs[-1]:
+ # exception of the last link method (copy) are fatal
+ raise
+ else:
+ pass
return 0
Link = SCons.Action.Action(LinkFunc, None)
-
def LocalString(target, source, env):
return 'Local copy of %s from %s' % (target[0], source[0])
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 85ae4d9..63ac29d 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -413,15 +413,14 @@ class BuildDirTestCase(unittest.TestCase):
class LinkSimulator :
"""A class to intercept os.[sym]link() calls and track them."""
- def __init__( self ) :
+ def __init__( self, duplicate ) :
+ self.duplicate = duplicate
self._reset()
def _reset( self ) :
"""Reset the simulator if necessary"""
if not self._need_reset() : return # skip if not needed now
- self.link_called = False
- self.symlink_called = False
- self.copy_called = False
+ self.links_to_be_called = self.duplicate
def _need_reset( self ) :
"""
@@ -430,85 +429,98 @@ class BuildDirTestCase(unittest.TestCase):
or if all three methods have been tried already.
"""
return (
- ( not hasattr( self , "link_called" ) )
+ ( not hasattr( self , "links_to_be_called" ) )
or
- ( self.link_called and
- self.symlink_called and
- self.copy_called )
+ (self.links_to_be_called == "")
)
def link_fail( self , src , dest ) :
self._reset()
- assert not self.symlink_called , \
- "Wrong link order: symlink tried before hard link."
- assert not self.copy_called , \
- "Wrong link order: copy tried before hard link."
- self.link_called = True
+ l = string.split(self.links_to_be_called, "-")
+ next_link = l[0]
+ assert next_link == "hard", \
+ "Wrong link order: expected %s to be called "\
+ "instead of hard" % next_link
+ self.links_to_be_called = string.join(l[1:], '-')
raise OSError( "Simulating hard link creation error." )
def symlink_fail( self , src , dest ) :
self._reset()
- assert self.link_called , \
- "Wrong link order: hard link not tried before symlink."
- assert not self.copy_called , \
- "Wrong link order: copy tried before symlink link."
- self.symlink_called = True
+ l = string.split(self.links_to_be_called, "-")
+ next_link = l[0]
+ assert next_link == "soft", \
+ "Wrong link order: expected %s to be called "\
+ "instead of soft" % next_link
+ self.links_to_be_called = string.join(l[1:], '-')
raise OSError( "Simulating symlink creation error." )
def copy( self , src , dest ) :
self._reset()
- assert self.link_called , \
- "Wrong link order: hard link not tried before copy."
- assert self.symlink_called , \
- "Wrong link order: symlink not tried before copy."
- self.copy_called = True
+ l = string.split(self.links_to_be_called, "-")
+ next_link = l[0]
+ assert next_link == "copy", \
+ "Wrong link order: expected %s to be called "\
+ "instead of copy" % next_link
+ self.links_to_be_called = string.join(l[1:], '-')
# copy succeeds, but use the real copy
self._real_copy(src, dest)
# end class LinkSimulator
- simulator = LinkSimulator()
- # save the real functions for later restoration
- real_link = None
- real_symlink = None
try:
- real_link = os.link
- except AttributeError:
- pass
- try:
- real_symlink = os.symlink
- except AttributeError:
+ SCons.Node.FS.set_duplicate("no-link-order")
+ assert 0, "Expected exception when passing an invalid duplicate to set_duplicate"
+ except SCons.Errors.InternalError:
pass
- real_copy = shutil.copy2
- simulator._real_copy = real_copy # the simulator needs the real one
+
+ for duplicate in SCons.Node.FS.Valid_Duplicates:
+ simulator = LinkSimulator(duplicate)
- # override the real functions with our simulation
- os.link = simulator.link_fail
- os.symlink = simulator.symlink_fail
- shutil.copy2 = simulator.copy
+ # save the real functions for later restoration
+ real_link = None
+ real_symlink = None
+ try:
+ real_link = os.link
+ except AttributeError:
+ pass
+ try:
+ real_symlink = os.symlink
+ except AttributeError:
+ pass
+ real_copy = shutil.copy2
+ simulator._real_copy = real_copy # the simulator needs the real one
+
+ # override the real functions with our simulation
+ os.link = simulator.link_fail
+ os.symlink = simulator.symlink_fail
+ shutil.copy2 = simulator.copy
+ SCons.Node.FS.set_duplicate(duplicate)
+
+ src_foo = test.workpath('src', 'foo')
+ build_foo = test.workpath('build', 'foo')
- try:
- test.write('src/foo', 'src/foo\n')
try:
- os.chmod(test.workpath('src/foo'), stat.S_IRUSR)
- SCons.Node.FS.Link(fs.File(test.workpath('build/foo')),
- fs.File(test.workpath('src/foo')),
- None)
- os.chmod(test.workpath('src/foo'), stat.S_IRUSR | stat.S_IWRITE)
- finally:
- test.unlink( "src/foo" )
- test.unlink( "build/foo" )
+ test.write(src_foo, 'src/foo\n')
+ os.chmod(src_foo, stat.S_IRUSR)
+ try:
+ SCons.Node.FS.Link(fs.File(build_foo),
+ fs.File(src_foo),
+ None)
+ finally:
+ os.chmod(src_foo, stat.S_IRUSR | stat.S_IWRITE)
+ test.unlink(src_foo)
+ test.unlink(build_foo)
- finally:
- # restore the real functions
- if real_link:
- os.link = real_link
- else:
- delattr(os, 'link')
- if real_symlink:
- os.symlink = real_symlink
- else:
- delattr(os, 'symlink')
- shutil.copy2 = real_copy
+ finally:
+ # restore the real functions
+ if real_link:
+ os.link = real_link
+ else:
+ delattr(os, 'link')
+ if real_symlink:
+ os.symlink = real_symlink
+ else:
+ delattr(os, 'symlink')
+ shutil.copy2 = real_copy
class FSTestCase(unittest.TestCase):
def runTest(self):