Make the Install() method copy files (by default).
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 12 Feb 2003 03:52:10 +0000 (03:52 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 12 Feb 2003 03:52:10 +0000 (03:52 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@590 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
src/CHANGES.txt
src/engine/SCons/Defaults.py
src/engine/SCons/Environment.py
test/Install.py

index 40191bb5cb136a9e962424180b5824f8d30e83c4..1bf91579dc57dbb04b088c458293e27cab62dcb3 100644 (file)
@@ -1881,6 +1881,27 @@ in the $CPPPATH and $F77PATH construction variables
 when the $_CPPINCFLAGS and $_F77INCFLAGS
 variables are automatically generated.
 
+.IP INSTALL
+A function to be called to install a file into a
+destination file name.
+The default function copies the file into the destination
+(and sets the destination file's mode and permission bits
+to match the source file's).
+The function takes the following arguments:
+
+.ES
+def install(dest, source, env):
+.EE
+.IP
+.I dest
+is the path name of the destination file.
+.I source
+is the path name of the source file.
+.I env
+is the construction environment
+(a dictionary of construction values)
+in force for this file installation.
+
 .IP LATEX
 The LaTeX structured formatter and typesetter.
 
index a696a2dba9178b75dd05ae1ddaa08e5c66dda752..7533c9d141b1e92aca05d6c10569b54354341522 100644 (file)
 
 RELEASE 0.12 - XXX
 
+  From Steven Knight:
+
+  - Added an INSTALL construction variable that can be set to a function
+    to control how the Install() and InstallAs() Builders install files.
+    The default INSTALL function now copies, not links, files.
+
 
 
 RELEASE 0.11 - Tue, 11 Feb 2003 05:24:33 -0600
index 6a3659dc5e1c00fbd353a90ded2a4ef5c90b4df9..f0c2163fa0b88a496892abe70dc3d3208fcac294 100644 (file)
@@ -37,8 +37,10 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 
 import os
-import string
 import os.path
+import shutil
+import stat
+import string
 
 import SCons.Action
 import SCons.Builder
@@ -183,6 +185,14 @@ Program = SCons.Builder.Builder(action=[ StaticCheck, '$LINKCOM' ],
                                 src_builder='Object',
                                 scanner = ProgScan)
 
+def copyFunc(dest, source, env):
+    """Install a source file into a destination by copying it (and its
+    permission/mode bits)."""
+    shutil.copy2(source, dest)
+    st = os.stat(source)
+    os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
+    return 0
+
 def _concat(prefix, list, suffix, locals, globals, f=lambda x: x):
     """Creates a new list from 'list' by first interpolating each
     element in the list using 'locals' and 'globals' and then calling f
@@ -257,6 +267,7 @@ ConstructionEnvironment = {
     'PSPREFIX'   : '',
     'PSSUFFIX'   : '.ps',
     'ENV'        : {},
+    'INSTALL'    : copyFunc,
     '_concat'     : _concat,
     '_stripixes'  : _stripixes,
     '_LIBFLAGS'    : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, locals(), globals())}',
index f9c793d775b8740a3437fd4c63b6783d97ef69c1..6356776c3d986b78ea08d9b9000ad05bbf8eaf27 100644 (file)
@@ -34,6 +34,7 @@ import copy
 import os
 import os.path
 import re
+import shutil
 from UserDict import UserDict
 
 import SCons.Action
@@ -47,10 +48,19 @@ import SCons.Tool
 import SCons.Util
 import SCons.Warnings
 
+def installFunc(target, source, env):
+    """Install a source file into a target using the function specified
+    as the INSTALL construction variable."""
+    try:
+        install = env['INSTALL']
+    except KeyError:
+        raise SCons.Errors.UserError('Missing INSTALL construction variable.')
+    return install(target[0].path, source[0].path, env)
+
 def installString(target, source, env):
     return 'Install file: "%s" as "%s"' % (source[0], target[0])
 
-installAction = SCons.Action.Action(SCons.Node.FS.LinkFunc, installString)
+installAction = SCons.Action.Action(installFunc, installString)
 
 InstallBuilder = SCons.Builder.Builder(name='Install', action=installAction)
 
index a79dfc82424f04dc8da3b3dff264830f9f514053..629c136cd7beb5aa4679c667f39deb5008c63336 100644 (file)
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
+"""
+Verify that the Install() Builder works
+"""
+
 import os.path
 import sys
 import time
 import TestSCons
 
-if sys.platform == 'win32':
-    _exe = '.exe'
-    _obj = '.obj'
-else:
-    _exe = ''
-    _obj = '.o'
-
 test = TestSCons.TestSCons()
 
-foo1 = test.workpath('export/foo1' + _exe)
-foo2 = test.workpath('export/foo2' + _exe)
-
-test.write('SConstruct', """
-env=Environment()
-t=env.Program(target='foo1', source='f1.c')
-env.Install(dir='export', source=t)
-t=env.Program(target='foo2', source='f2.c')
-env.Install(dir='export', source=t)
+f1_out = test.workpath('export', 'f1.out')
+f2_out = test.workpath('export', 'f2.out')
+f3_out = test.workpath('export', 'f3.out')
+
+test.write('SConstruct', """\
+def cat(env, source, target):
+    target = str(target[0])
+    source = map(str, source)
+    f = open(target, "wb")
+    for src in source:
+        f.write(open(src, "rb").read())
+    f.close()
+
+def my_install(dest, source, env):
+    import shutil
+    shutil.copy2(source, dest)
+    open('my_install.out', 'ab').write(dest)
+
+env1 = Environment()
+env1.Append(BUILDERS={'Cat':Builder(action=cat)})
+env3 = env1.Copy(INSTALL = my_install)
+
+t = env1.Cat(target='f1.out', source='f1.in')
+env1.Install(dir='export', source=t)
+t = env1.Cat(target='f2.out', source='f2.in')
+env1.Install(dir='export', source=t)
+
+t = env3.Cat(target='f3.out', source='f3.in')
+env3.Install(dir='export', source=t)
 """)
 
-test.write('f1.c', r"""
-#include <stdio.h>
-
-int main(void)
-{
-   printf("f1.c\n");
-   return 0;
-}
-""")
-
-test.write('f2.c', r"""
-#include <stdio.h>
-
-int main(void)
-{
-   printf("f2.c\n");
-   return 0;
-}
-""")
+test.write('f1.in', "f1.in\n")
+test.write('f2.in', "f2.in\n")
+test.write('f3.in', "f3.in\n")
 
 test.run(arguments = '.')
 
-test.run(program = foo1, stdout = "f1.c\n")
-test.run(program = foo2, stdout = "f2.c\n")
+test.fail_test(test.read(f1_out) != "f1.in\n")
+test.fail_test(test.read(f2_out) != "f2.in\n")
+test.fail_test(test.read(f3_out) != "f3.in\n")
 
-# make sure the programs didn't get rebuilt, because nothing changed:
-oldtime1 = os.path.getmtime(foo1)
-oldtime2 = os.path.getmtime(foo2)
+test.fail_test(test.read('my_install.out') != os.path.join('export', 'f3.out'))
 
-test.write('f1.c', r"""
-#include <stdio.h>
+# make sure the programs didn't get rebuilt, because nothing changed:
+oldtime1 = os.path.getmtime(f1_out)
+oldtime2 = os.path.getmtime(f2_out)
 
-int main(void)
-{
-   printf("f1.c again\n");
-   return 0;
-}
-""")
+test.write('f1.in', "f1.in again\n")
 
 time.sleep(2) # introduce a small delay, to make the test valid
 
 test.run(arguments = '.')
 
-test.fail_test(oldtime1 == os.path.getmtime(foo1))
-test.fail_test(oldtime2 != os.path.getmtime(foo2))
+test.fail_test(oldtime1 == os.path.getmtime(f1_out))
+test.fail_test(oldtime2 != os.path.getmtime(f2_out))
+
+# Verify that we didn't link to the Installed file.
+open(f2_out, 'wb').write("xyzzy\n")
+test.fail_test(test.read('f2.out') != "f2.in\n")
 
 # Verify that scons prints an error message
 # if a target can not be unlinked before building it:
-test.write('f1.c', r"""
-#include <stdio.h>
-
-int main(void)
-{
-   printf("f1.c again again\n");
-   return 0;
-}
-""")
+test.write('f1.in', "f1.in again again\n")
 
-os.chmod(test.workpath('.'), 0555)
-f = open(test.workpath('f1' + _obj), 'rb')
+os.chmod(test.workpath('export'), 0555)
+f = open(f1_out, 'rb')
 
-test.run(arguments = foo1, stderr="scons: *** [Errno 13] Permission denied: 'f1%s'\n"%_obj, status=2)
+test.run(arguments = f1_out,
+         stderr="scons: *** [Errno 13] Permission denied: '%s'\n" % os.path.join('export', 'f1.out'),
+         status=2)
 
 f.close()