Skip to content

Commit ccc90a8

Browse files
authored
Merge pull request #3808 from ComputeCanada/fix_bash_shebang_for
add support for fix_bash_shebang_for
2 parents 5f77fa0 + a2cb1bc commit ccc90a8

File tree

3 files changed

+58
-49
lines changed

3 files changed

+58
-49
lines changed

easybuild/framework/easyblock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2485,7 +2485,7 @@ def package_step(self):
24852485

24862486
def fix_shebang(self):
24872487
"""Fix shebang lines for specified files."""
2488-
for lang in ['perl', 'python']:
2488+
for lang in ['bash', 'perl', 'python']:
24892489
shebang_regex = re.compile(r'^#![ ]*.*[/ ]%s.*' % lang)
24902490
fix_shebang_for = self.cfg['fix_%s_shebang_for' % lang]
24912491
if fix_shebang_for:

easybuild/framework/easyconfig/default.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@
9595
'easybuild_version': [None, "EasyBuild-version this spec-file was written for", BUILD],
9696
'enhance_sanity_check': [False, "Indicate that additional sanity check commands & paths should enhance "
9797
"the existin sanity check, not replace it", BUILD],
98+
'fix_bash_shebang_for': [None, "List of files for which Bash shebang should be fixed "
99+
"to '#!/usr/bin/env bash' (glob patterns supported)", BUILD],
98100
'fix_perl_shebang_for': [None, "List of files for which Perl shebang should be fixed "
99101
"to '#!/usr/bin/env perl' (glob patterns supported)", BUILD],
100102
'fix_python_shebang_for': [None, "List of files for which Python shebang should be fixed "

test/framework/toy_build.py

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2951,6 +2951,7 @@ def test_fix_shebang(self):
29512951
# copy of bin/toy to use in fix_python_shebang_for and fix_perl_shebang_for
29522952
" 'cp -a %(installdir)s/bin/toy %(installdir)s/bin/toy.python',",
29532953
" 'cp -a %(installdir)s/bin/toy %(installdir)s/bin/toy.perl',",
2954+
" 'cp -a %(installdir)s/bin/toy %(installdir)s/bin/toy.sh',",
29542955

29552956
# hardcoded path to bin/python
29562957
" 'echo \"#!/usr/bin/python\\n# test\" > %(installdir)s/bin/t1.py',",
@@ -2987,9 +2988,26 @@ def test_fix_shebang(self):
29872988
# shebang bash
29882989
" 'echo \"#!/usr/bin/env bash\\n# test\" > %(installdir)s/bin/b2.sh',",
29892990

2991+
# tests for bash shebang
2992+
# hardcoded path to bin/bash
2993+
" 'echo \"#!/bin/bash\\n# test\" > %(installdir)s/bin/t1.sh',",
2994+
# hardcoded path to usr/bin/bash
2995+
" 'echo \"#!/usr/bin/bash\\n# test\" > %(installdir)s/bin/t2.sh',",
2996+
# already OK, should remain the same
2997+
" 'echo \"#!/usr/bin/env bash\\n# test\" > %(installdir)s/bin/t3.sh',",
2998+
# shebang with space, should strip the space
2999+
" 'echo \"#! /usr/bin/env bash\\n# test\" > %(installdir)s/bin/t4.sh',",
3000+
# no shebang sh
3001+
" 'echo \"# test\" > %(installdir)s/bin/t5.sh',",
3002+
# shebang python
3003+
" 'echo \"#!/usr/bin/env python\\n# test\" > %(installdir)s/bin/b1.py',",
3004+
# shebang perl
3005+
" 'echo \"#!/usr/bin/env perl\\n# test\" > %(installdir)s/bin/b1.pl',",
3006+
29903007
"]",
2991-
"fix_python_shebang_for = ['bin/t1.py', 'bin/*.py', 'nosuchdir/*.py', 'bin/toy.python', 'bin/b1.sh']",
2992-
"fix_perl_shebang_for = ['bin/*.pl', 'bin/b2.sh', 'bin/toy.perl']",
3008+
"fix_python_shebang_for = ['bin/t1.py', 'bin/t*.py', 'nosuchdir/*.py', 'bin/toy.python', 'bin/b1.sh']",
3009+
"fix_perl_shebang_for = ['bin/t*.pl', 'bin/b2.sh', 'bin/toy.perl']",
3010+
"fix_bash_shebang_for = ['bin/t*.sh', 'bin/b1.py', 'bin/b1.pl', 'bin/toy.sh']",
29933011
])
29943012
write_file(test_ec, test_ec_txt)
29953013
self.test_toy_build(ec_file=test_ec, raise_error=True)
@@ -2998,36 +3016,31 @@ def test_fix_shebang(self):
29983016

29993017
# bin/toy and bin/toy2 should *not* be patched, since they're binary files
30003018
toy_txt = read_file(os.path.join(toy_bindir, 'toy'), mode='rb')
3001-
for fn in ['toy.perl', 'toy.python']:
3019+
for fn in ['toy.sh', 'toy.perl', 'toy.python']:
30023020
fn_txt = read_file(os.path.join(toy_bindir, fn), mode='rb')
30033021
# no shebang added
30043022
self.assertFalse(fn_txt.startswith(b"#!/"))
30053023
# exact same file as original binary (untouched)
30063024
self.assertEqual(toy_txt, fn_txt)
30073025

3026+
regexes = {}
30083027
# no re.M, this should match at start of file!
3009-
py_shebang_regex = re.compile(r'^#!/usr/bin/env python\n# test$')
3010-
for pybin in ['t1.py', 't2.py', 't3.py', 't4.py', 't5.py', 't6.py', 't7.py']:
3011-
pybin_path = os.path.join(toy_bindir, pybin)
3012-
pybin_txt = read_file(pybin_path)
3013-
self.assertTrue(py_shebang_regex.match(pybin_txt),
3014-
"Pattern '%s' found in %s: %s" % (py_shebang_regex.pattern, pybin_path, pybin_txt))
3015-
3016-
# no re.M, this should match at start of file!
3017-
perl_shebang_regex = re.compile(r'^#!/usr/bin/env perl\n# test$')
3018-
for perlbin in ['t1.pl', 't2.pl', 't3.pl', 't4.pl', 't5.pl', 't6.pl', 't7.pl']:
3019-
perlbin_path = os.path.join(toy_bindir, perlbin)
3020-
perlbin_txt = read_file(perlbin_path)
3021-
self.assertTrue(perl_shebang_regex.match(perlbin_txt),
3022-
"Pattern '%s' found in %s: %s" % (perl_shebang_regex.pattern, perlbin_path, perlbin_txt))
3023-
3024-
# There are 2 bash files which shouldn't be influenced by fix_shebang
3025-
bash_shebang_regex = re.compile(r'^#!/usr/bin/env bash\n# test$')
3026-
for bashbin in ['b1.sh', 'b2.sh']:
3027-
bashbin_path = os.path.join(toy_bindir, bashbin)
3028-
bashbin_txt = read_file(bashbin_path)
3029-
self.assertTrue(bash_shebang_regex.match(bashbin_txt),
3030-
"Pattern '%s' found in %s: %s" % (bash_shebang_regex.pattern, bashbin_path, bashbin_txt))
3028+
regexes['py'] = re.compile(r'^#!/usr/bin/env python\n# test$')
3029+
regexes['pl'] = re.compile(r'^#!/usr/bin/env perl\n# test$')
3030+
regexes['sh'] = re.compile(r'^#!/usr/bin/env bash\n# test$')
3031+
3032+
# all scripts should have a shebang that matches their extension
3033+
scripts = {}
3034+
scripts['py'] = ['t1.py', 't2.py', 't3.py', 't4.py', 't5.py', 't6.py', 't7.py', 'b1.py']
3035+
scripts['pl'] = ['t1.pl', 't2.pl', 't3.pl', 't4.pl', 't5.pl', 't6.pl', 't7.pl', 'b1.pl']
3036+
scripts['sh'] = ['t1.sh', 't2.sh', 't3.sh', 't4.sh', 't5.sh', 'b1.sh', 'b2.sh']
3037+
3038+
for ext in ['sh', 'pl', 'py']:
3039+
for script in scripts[ext]:
3040+
bin_path = os.path.join(toy_bindir, script)
3041+
bin_txt = read_file(bin_path)
3042+
self.assertTrue(regexes[ext].match(bin_txt),
3043+
"Pattern '%s' found in %s: %s" % (regexes[ext].pattern, bin_path, bin_txt))
30313044

30323045
# now test with a custom env command
30333046
extra_args = ['--env-for-shebang=/usr/bin/env -S']
@@ -3037,36 +3050,30 @@ def test_fix_shebang(self):
30373050

30383051
# bin/toy and bin/toy2 should *not* be patched, since they're binary files
30393052
toy_txt = read_file(os.path.join(toy_bindir, 'toy'), mode='rb')
3040-
for fn in ['toy.perl', 'toy.python']:
3053+
for fn in ['toy.sh', 'toy.perl', 'toy.python']:
30413054
fn_txt = read_file(os.path.join(toy_bindir, fn), mode='rb')
30423055
# no shebang added
30433056
self.assertFalse(fn_txt.startswith(b"#!/"))
30443057
# exact same file as original binary (untouched)
30453058
self.assertEqual(toy_txt, fn_txt)
30463059

3060+
regexes_S = {}
30473061
# no re.M, this should match at start of file!
3048-
py_shebang_regex = re.compile(r'^#!/usr/bin/env -S python\n# test$')
3049-
for pybin in ['t1.py', 't2.py', 't3.py', 't4.py', 't5.py', 't6.py', 't7.py']:
3050-
pybin_path = os.path.join(toy_bindir, pybin)
3051-
pybin_txt = read_file(pybin_path)
3052-
self.assertTrue(py_shebang_regex.match(pybin_txt),
3053-
"Pattern '%s' found in %s: %s" % (py_shebang_regex.pattern, pybin_path, pybin_txt))
3054-
3055-
# no re.M, this should match at start of file!
3056-
perl_shebang_regex = re.compile(r'^#!/usr/bin/env -S perl\n# test$')
3057-
for perlbin in ['t1.pl', 't2.pl', 't3.pl', 't4.pl', 't5.pl', 't6.pl', 't7.pl']:
3058-
perlbin_path = os.path.join(toy_bindir, perlbin)
3059-
perlbin_txt = read_file(perlbin_path)
3060-
self.assertTrue(perl_shebang_regex.match(perlbin_txt),
3061-
"Pattern '%s' found in %s: %s" % (perl_shebang_regex.pattern, perlbin_path, perlbin_txt))
3062-
3063-
# There are 2 bash files which shouldn't be influenced by fix_shebang
3064-
bash_shebang_regex = re.compile(r'^#!/usr/bin/env bash\n# test$')
3065-
for bashbin in ['b1.sh', 'b2.sh']:
3066-
bashbin_path = os.path.join(toy_bindir, bashbin)
3067-
bashbin_txt = read_file(bashbin_path)
3068-
self.assertTrue(bash_shebang_regex.match(bashbin_txt),
3069-
"Pattern '%s' found in %s: %s" % (bash_shebang_regex.pattern, bashbin_path, bashbin_txt))
3062+
regexes_S['py'] = re.compile(r'^#!/usr/bin/env -S python\n# test$')
3063+
regexes_S['pl'] = re.compile(r'^#!/usr/bin/env -S perl\n# test$')
3064+
regexes_S['sh'] = re.compile(r'^#!/usr/bin/env -S bash\n# test$')
3065+
3066+
for ext in ['sh', 'pl', 'py']:
3067+
for script in scripts[ext]:
3068+
bin_path = os.path.join(toy_bindir, script)
3069+
bin_txt = read_file(bin_path)
3070+
# the scripts b1.py, b1.pl, b1.sh, b2.sh should keep their original shebang
3071+
if script.startswith('b'):
3072+
self.assertTrue(regexes[ext].match(bin_txt),
3073+
"Pattern '%s' found in %s: %s" % (regexes[ext].pattern, bin_path, bin_txt))
3074+
else:
3075+
self.assertTrue(regexes_S[ext].match(bin_txt),
3076+
"Pattern '%s' found in %s: %s" % (regexes_S[ext].pattern, bin_path, bin_txt))
30703077

30713078
def test_toy_system_toolchain_alias(self):
30723079
"""Test use of 'system' toolchain alias."""

0 commit comments

Comments
 (0)