diff options
author | Mats Wichmann <mats@linux.com> | 2021-04-15 14:41:51 (GMT) |
---|---|---|
committer | Mats Wichmann <mats@linux.com> | 2021-04-18 17:18:25 (GMT) |
commit | 59c4c2ca4fce8392852e5e907bbb9e89b1daae15 (patch) | |
tree | 077edb7f9251b97aa2035ad654efcd590463fcf1 | |
parent | 1850bdd13c7668aac493b9f5b896578813e60ca9 (diff) | |
download | SCons-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-x | CHANGES.txt | 1 | ||||
-rwxr-xr-x | RELEASE.txt | 3 | ||||
-rw-r--r-- | SCons/Tool/install.py | 82 | ||||
-rw-r--r-- | SCons/Tool/install.xml | 6 |
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> |