summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMats Wichmann <mats@linux.com>2021-04-15 14:41:51 (GMT)
committerMats Wichmann <mats@linux.com>2021-04-18 17:18:25 (GMT)
commit59c4c2ca4fce8392852e5e907bbb9e89b1daae15 (patch)
tree077edb7f9251b97aa2035ad654efcd590463fcf1
parent1850bdd13c7668aac493b9f5b896578813e60ca9 (diff)
downloadSCons-59c4c2ca4fce8392852e5e907bbb9e89b1daae15.zip
SCons-59c4c2ca4fce8392852e5e907bbb9e89b1daae15.tar.gz
SCons-59c4c2ca4fce8392852e5e907bbb9e89b1daae15.tar.bz2
Restore setting of write bits on Install'd files
SCons had undocumented behavior that Install and InstallVersionedLib unconditionally changed the files they copied to writable - shutil.copy2(), the underlying function used for copying, preserves mode bits. Restore this behavior so Install won't fail in a project where it had previously run, if any of the sources were read-only. Fixes #3927 Signed-off-by: Mats Wichmann <mats@linux.com>
-rwxr-xr-xCHANGES.txt1
-rwxr-xr-xRELEASE.txt3
-rw-r--r--SCons/Tool/install.py82
-rw-r--r--SCons/Tool/install.xml6
4 files changed, 65 insertions, 27 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index c259c77..e3ed2c4 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -74,6 +74,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
- Don't strip spaces in INSTALLSTR by using raw subst (issue 2018)
- Deprecate Python 3.5 as a supported version.
- CPPDEFINES now expands construction variable references (issue 2363)
+ - Restore behavior that Install()'d files are writable (issue 3927)
From Dillan Mills:
- Add support for the (TARGET,SOURCE,TARGETS,SOURCES,CHANGED_TARGETS,CHANGED_SOURCES}.relpath property.
diff --git a/RELEASE.txt b/RELEASE.txt
index fe4d82f..db64ee8 100755
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -59,6 +59,9 @@ FIXES
- DocbookXslt tool: The XSLT stylesheet file is now initialized to an env.File() Node,
such that dependencies work correctly in hierarchical builds (eg when using
DocbookXslt in SConscript('subdir/SConscript') context.
+ - The Install builder will now set the writable mode on the file(s) it
+ copies. This restores the (previously undocumented) SCons behavior
+ that regressed as of 4.0.0.
IMPROVEMENTS
diff --git a/SCons/Tool/install.py b/SCons/Tool/install.py
index d73d678..9910264 100644
--- a/SCons/Tool/install.py
+++ b/SCons/Tool/install.py
@@ -31,6 +31,7 @@ selection method.
#
import os
+import stat
from shutil import copy2, copymode, copystat
import SCons.Action
@@ -152,11 +153,14 @@ def scons_copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
#
# Functions doing the actual work of the Install Builder.
#
-def copyFunc(dest, source, env):
- """Install a source file or directory into a destination by copying,
+def copyFunc(dest, source, env) -> int:
+ """Install a source file or directory into a destination by copying.
- Mode/permissions bits will be copied as well.
+ Mode/permissions bits will be copied as well, except that the target
+ will be made writable.
+ Returns:
+ POSIX-style error code - 0 for success, non-zero for fail
"""
if os.path.isdir(source):
if os.path.exists(dest):
@@ -169,19 +173,24 @@ def copyFunc(dest, source, env):
scons_copytree(source, dest, dirs_exist_ok=True)
else:
copy2(source, dest)
- copymode(source, dest)
+ st = os.stat(source)
+ os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
return 0
#
# Functions doing the actual work of the InstallVersionedLib Builder.
#
-def copyFuncVersionedLib(dest, source, env):
- """Install a versioned library into a destination by copying,
+def copyFuncVersionedLib(dest, source, env) -> int:
+ """Install a versioned library into a destination by copying.
- Mode/permissions bits will be copied as well.
Any required symbolic links for other library names are created.
+ Mode/permissions bits will be copied as well, except that the target
+ will be made writable.
+
+ Returns:
+ POSIX-style error code - 0 for success, non-zero for fail
"""
if os.path.isdir(source):
raise SCons.Errors.UserError("cannot install directory `%s' as a version library" % str(source) )
@@ -192,7 +201,8 @@ def copyFuncVersionedLib(dest, source, env):
except:
pass
copy2(source, dest)
- copymode(source, dest)
+ st = os.stat(source)
+ os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
installShlibLinks(dest, source, env)
return 0
@@ -223,38 +233,58 @@ def installShlibLinks(dest, source, env):
CreateLibSymlinks(env, symlinks)
return
-def installFunc(target, source, env):
- """Install a source file into a target using the function specified
- as the INSTALL construction variable."""
+def installFunc(target, source, env) -> int:
+ """Install a source file into a target.
+
+ Uses the function specified in the INSTALL construction variable.
+
+ Returns:
+ POSIX-style error code - 0 for success, non-zero for fail
+ """
+
try:
install = env['INSTALL']
except KeyError:
raise SCons.Errors.UserError('Missing INSTALL construction variable.')
- assert len(target)==len(source), \
- "Installing source %s into target %s: target and source lists must have same length."%(list(map(str, source)), list(map(str, target)))
- for t,s in zip(target,source):
- if install(t.get_path(),s.get_path(),env):
+ assert len(target) == len(source), (
+ "Installing source %s into target %s: "
+ "target and source lists must have same length."
+ % (list(map(str, source)), list(map(str, target)))
+ )
+ for t, s in zip(target, source):
+ if install(t.get_path(), s.get_path(), env):
return 1
return 0
-def installFuncVersionedLib(target, source, env):
- """Install a versioned library into a target using the function specified
- as the INSTALLVERSIONEDLIB construction variable."""
+def installFuncVersionedLib(target, source, env) -> int:
+ """Install a versioned library into a target.
+
+ Uses the function specified in the INSTALL construction variable.
+
+ Returns:
+ POSIX-style error code - 0 for success, non-zero for fail
+ """
+
try:
install = env['INSTALLVERSIONEDLIB']
except KeyError:
- raise SCons.Errors.UserError('Missing INSTALLVERSIONEDLIB construction variable.')
-
- assert len(target)==len(source), \
- "Installing source %s into target %s: target and source lists must have same length."%(list(map(str, source)), list(map(str, target)))
- for t,s in zip(target,source):
+ raise SCons.Errors.UserError(
+ 'Missing INSTALLVERSIONEDLIB construction variable.'
+ )
+
+ assert len(target) == len(source), (
+ "Installing source %s into target %s: "
+ "target and source lists must have same length."
+ % (list(map(str, source)), list(map(str, target)))
+ )
+ for t, s in zip(target, source):
if hasattr(t.attributes, 'shlibname'):
tpath = os.path.join(t.get_dir(), t.attributes.shlibname)
else:
tpath = t.get_path()
- if install(tpath,s.get_path(),env):
+ if install(tpath, s.get_path(), env):
return 1
return 0
@@ -461,12 +491,12 @@ def generate(env):
try:
env['INSTALL']
except KeyError:
- env['INSTALL'] = copyFunc
+ env['INSTALL'] = copyFunc
try:
env['INSTALLVERSIONEDLIB']
except KeyError:
- env['INSTALLVERSIONEDLIB'] = copyFuncVersionedLib
+ env['INSTALLVERSIONEDLIB'] = copyFuncVersionedLib
def exists(env):
return 1
diff --git a/SCons/Tool/install.xml b/SCons/Tool/install.xml
index f4295a0..81e486f 100644
--- a/SCons/Tool/install.xml
+++ b/SCons/Tool/install.xml
@@ -46,7 +46,9 @@ which must be a directory.
The names of the specified source files or directories
remain the same within the destination directory. The
sources may be given as a string or as a node returned by
-a builder.
+a builder. Basic metadata from the source files is
+preserved, except that the target files will be marked
+as writable.
</para>
<example_commands>
@@ -118,6 +120,8 @@ See the note under &Install;.
<para>
Installs a versioned shared library. The symlinks appropriate to the
architecture will be generated based on symlinks of the source library.
+Basic metadata from the source library is preserved,
+except that the target file will be marked as writable.
</para>
<example_commands>