From e9f3ef785ddcc599003534d8641551182a3fbc2a Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Thu, 28 Oct 2021 14:49:23 +0200 Subject: Fix sbang hook for non-writable files (#27007) * Fix sbang hook for non-writable files PR #26793 seems to have broken the sbang hook for files with missing write permissions. Installing perl now breaks with the following error: ``` ==> [2021-10-28-12:09:26.832759] Error: PermissionError: [Errno 13] Permission denied: '$SPACK/opt/spack/linux-fedora34-zen2/gcc-11.2.1/perl-5.34.0-afuweplnhphcojcowsc2mb5ngncmczk4/bin/cpanm' ``` Temporarily add write permissions to the original file so it can be overwritten with the patched one. And test that file permissions are preserved in sbang even for non-writable files Co-authored-by: Harmen Stoppels --- lib/spack/spack/hooks/sbang.py | 4 ++++ lib/spack/spack/test/sbang.py | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/spack/spack/hooks/sbang.py b/lib/spack/spack/hooks/sbang.py index 1c18c46dc6..ce2cf3435d 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 e9beebc43d..6d26bd1ba8 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 -- cgit v1.2.3-70-g09d2