diff --git a/lib/spack/spack/hooks/sbang.py b/lib/spack/spack/hooks/sbang.py index 1c18c46dc65..ce2cf3435d2 100644 --- a/lib/spack/spack/hooks/sbang.py +++ b/lib/spack/spack/hooks/sbang.py @@ -110,6 +110,10 @@ def filter_shebang(path): # Store the file permissions, the patched version needs the same. saved_mode = os.stat(path).st_mode + # Change non-writable files to be writable if needed. + if not os.access(path, os.W_OK): + os.chmod(path, saved_mode | stat.S_IWUSR) + # No need to delete since we'll move it and overwrite the original. patched = tempfile.NamedTemporaryFile('wb', delete=False) patched.write(new_sbang_line) diff --git a/lib/spack/spack/test/sbang.py b/lib/spack/spack/test/sbang.py index e9beebc43d5..6d26bd1ba87 100644 --- a/lib/spack/spack/test/sbang.py +++ b/lib/spack/spack/test/sbang.py @@ -374,3 +374,14 @@ def test_shebang_exceeds_spack_shebang_limit(shebang_limits_system_8_spack_16, t with open(file, 'rb') as f: assert b'sbang' not in f.read() + + +def test_sbang_hook_handles_non_writable_files_preserving_permissions(tmpdir): + path = str(tmpdir.join('file.sh')) + with open(path, 'w') as f: + f.write(long_line) + os.chmod(path, 0o555) + sbang.filter_shebang(path) + with open(path, 'r') as f: + assert 'sbang' in f.readline() + assert os.stat(path).st_mode & 0o777 == 0o555