diff options
author | Todd Gamblin <tgamblin@llnl.gov> | 2020-10-28 14:07:05 -0700 |
---|---|---|
committer | Todd Gamblin <tgamblin@llnl.gov> | 2020-10-28 17:43:23 -0700 |
commit | aebf20ebdc0f5d1ea03956681e0b16ffaffa9568 (patch) | |
tree | 154464aab993ed2aa40d8b675516f707113a6338 | |
parent | 44bacefb27675aaed22d77c768fb18a627e678eb (diff) | |
download | spack-aebf20ebdc0f5d1ea03956681e0b16ffaffa9568.tar.gz spack-aebf20ebdc0f5d1ea03956681e0b16ffaffa9568.tar.bz2 spack-aebf20ebdc0f5d1ea03956681e0b16ffaffa9568.tar.xz spack-aebf20ebdc0f5d1ea03956681e0b16ffaffa9568.zip |
sbang: vendor sbang
`sbang` now lives at https://github.com/spack/sbang, and it has its own
test suite that's more extensive than what's in Spack. We'll leave sbang
tests to sbang from now on, and just vendor `bin/sbang` directly.
Remaining `sbang` tests have to do with patching files, not with
`sbang`'s functionality.
This update also fixes a bug with `sbang` and multiple command line
arguments that was introduced in #19529. See:
* https://github.com/spack/sbang/pull/1
* https://github.com/spack/sbang/pull/2
- [x] include latest `sbang` from https://github.com/spack/sbang
- [x] remove old `sbang` tests from Spack
- [x] update `COPYRIGHT` and `cmd/license.py`
-rw-r--r-- | COPYRIGHT | 12 | ||||
-rwxr-xr-x | bin/sbang | 110 | ||||
-rw-r--r-- | lib/spack/spack/cmd/license.py | 1 | ||||
-rw-r--r-- | lib/spack/spack/test/sbang.py | 65 |
4 files changed, 24 insertions, 164 deletions
@@ -28,9 +28,11 @@ text in the license header: External Packages ------------------- -Spack bundles its external dependencies in lib/spack/external. These -packages are covered by various permissive licenses. A summary listing -follows. See the license included with each package for full details. + +Spack bundles most external dependencies in lib/spack/external. It also +includes the sbang tool directly in bin/sbang. These packages are covered +by various permissive licenses. A summary listing follows. See the +license included with each package for full details. PackageName: argparse PackageHomePage: https://pypi.python.org/pypi/argparse @@ -76,6 +78,10 @@ PackageName: ruamel.yaml PackageHomePage: https://yaml.readthedocs.io/ PackageLicenseDeclared: MIT +PackageName: sbang +PackageHomePage: https://github.com/spack/sbang +PackageLicenseDeclared: Apache-2.0 OR MIT + PackageName: six PackageHomePage: https://pypi.python.org/pypi/six PackageLicenseDeclared: MIT @@ -1,7 +1,7 @@ #!/bin/sh # # Copyright 2013-2020 Lawrence Livermore National Security, LLC and other -# Spack Project Developers. See the top-level COPYRIGHT file for details. +# sbang project developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) @@ -12,85 +12,16 @@ # arguments in shebang lines, making it hard to use interpreters that are # deep in the directory hierarchy or require special arguments. # -# `sbang` can run such scripts, either as a shebang interpreter, or -# directly on the command line. +# To use, put the long shebang on the second line of your script, and +# make sbang the interpreter, like this: # -# Usage -# ----- -# Suppose you have a script, long-shebang.sh, like this: +# #!/bin/sh /path/to/sbang +# #!/long/path/to/real/interpreter with arguments # -# 1 #!/very/long/path/to/some/interp -# 2 -# 3 echo "success!" +# `sbang` will run the real interpreter with the script as its argument. # -# Invoking this script will result in an error on some OS's. On -# Linux, you get this: +# See https://github.com/spack/sbang for more details. # -# $ ./longshebang.sh -# -bash: ./longshebang.sh: /very/long/path/to/some/interp: bad interpreter: -# No such file or directory -# -# On macOS, the system simply assumes the interpreter is the shell and -# tries to run with it, which is not likely what you want. -# -# -# `sbang` on the command line -# --------------------------- -# You can use `sbang` in two ways. The first is to use it directly, -# from the command line, like this: -# -# $ sbang ./long-shebang.sh -# success! -# -# -# `sbang` as the interpreter -# -------------------------- -# You can also use `sbang` *as* the interpreter for your script. Put -# `#!/bin/sh /path/to/sbang` on line 1, and move the original -# shebang to line 2 of the script: -# -# 1 #!/bin/sh /path/to/sbang -# 2 #!/long/path/to/real/interpreter with arguments -# 3 -# 4 echo "success!" -# -# $ ./long-shebang.sh -# success! -# -# On Linux, you could shorten line 1 to `#!/path/to/sbang`, but other -# operating systems like Mac OS X require the interpreter to be a binary, -# so it's best to use `sbang` as an argument to `/bin/sh`. Obviously, for -# this to work, `sbang` needs to have a short enough path that *it* will -# run without hitting OS limits. -# -# For Lua, node, and php scripts, the second line can't start with #!, as -# # is not the comment character in these languages (though they all -# ignore #! on the *first* line of a script). So, instrument such scripts -# like this, using --, //, or <?php ... ?> instead of # on the second -# line, e.g.: -# -# 1 #!/bin/sh /path/to/sbang -# 2 --!/long/path/to/lua with arguments -# 3 print "success!" -# -# 1 #!/bin/sh /path/to/sbang -# 2 //!/long/path/to/node with arguments -# 3 print "success!" -# -# 1 #!/bin/sh /path/to/sbang -# 2 <?php #/long/path/to/php with arguments ?> -# 3 <?php echo "success!\n"; ?> -# -# How it works -# ------------ -# `sbang` is a very simple posix shell script. It looks at the first two -# lines of a script argument and runs the last line starting with `#!`, -# with the script as an argument. It also forwards arguments. -# - -# We disable two shellcheck errors below: -# SC2124: when saving arguments, we intentionally assign as an array -# SC2086: when splitting $shebang_line and exec args, we want to expand args # Generic error handling die() { @@ -130,27 +61,16 @@ while read -r line && [ $lines -ne 2 ]; do lines=$((lines+1)) done < "$script" -# shellcheck disable=SC2124 -# this saves arguments for later and intentionally assigns as an array -args="$@" - -# handle scripts with sbang parameters, e.g.: -# -# #!/<spack-long-path>/perl -w -# -# put the shebang line with all the parameters in the $@ array and get -# the first element. -# shellcheck disable=SC2086 -set $shebang_line -set -- "$@" -interpreter="$1" -arg1="$2" - # error if we did not find any interpreter -if [ -z "$interpreter" ]; then +if [ -z "$shebang_line" ]; then die "error: sbang found no interpreter in $script" fi +# parse out the interpreter and first argument +IFS=' ' read -r interpreter arg1 rest <<EOF +$shebang_line +EOF + # Determine if the interpreter is a particular program, accounting for the # '#!/usr/bin/env PROGRAM' convention. So: # @@ -176,8 +96,8 @@ fi # if interpreter_is perl || interpreter_is ruby; then # shellcheck disable=SC2086 - $exec $shebang_line -x "$args" + $exec $shebang_line -x "$@" else # shellcheck disable=SC2086 - $exec $shebang_line "$args" + $exec $shebang_line "$@" fi diff --git a/lib/spack/spack/cmd/license.py b/lib/spack/spack/cmd/license.py index 5fd57c39c9..84a4a02282 100644 --- a/lib/spack/spack/cmd/license.py +++ b/lib/spack/spack/cmd/license.py @@ -32,7 +32,6 @@ licensed_files = [ # spack scripts r'^bin/spack$', r'^bin/spack-python$', - r'^bin/sbang$', # all of spack core r'^lib/spack/spack/.*\.py$', diff --git a/lib/spack/spack/test/sbang.py b/lib/spack/spack/test/sbang.py index bdab7a8cfc..18bbe9f345 100644 --- a/lib/spack/spack/test/sbang.py +++ b/lib/spack/spack/test/sbang.py @@ -217,68 +217,3 @@ def test_install_sbang(install_mockery): # install again and make sure sbang is still fine sbang.install_sbang() check_sbang_installation() - - -def test_sbang_fails_without_argument(): - sbang = which(spack.paths.sbang_script) - sbang(fail_on_error=False) - assert sbang.returncode == 1 - - -@pytest.mark.parametrize("shebang,returncode,expected", [ - # perl, with and without /usr/bin/env - ("#!/path/to/perl", 0, "/path/to/perl -x"), - ("#!/usr/bin/env perl", 0, "/usr/bin/env perl -x"), - - # perl -w, with and without /usr/bin/env - ("#!/path/to/perl -w", 0, "/path/to/perl -w -x"), - ("#!/usr/bin/env perl -w", 0, "/usr/bin/env perl -w -x"), - - # ruby, with and without /usr/bin/env - ("#!/path/to/ruby", 0, "/path/to/ruby -x"), - ("#!/usr/bin/env ruby", 0, "/usr/bin/env ruby -x"), - - # python, with and without /usr/bin/env - ("#!/path/to/python", 0, "/path/to/python"), - ("#!/usr/bin/env python", 0, "/usr/bin/env python"), - - # php with one-line php comment - ("<?php #!/usr/bin/php ?>", 0, "/usr/bin/php"), - - # simple shell scripts - ("#!/bin/sh", 0, "/bin/sh"), - ("#!/bin/bash", 0, "/bin/bash"), - - # error case: sbang as infinite loop - ("#!/path/to/sbang", 1, None), - ("#!/usr/bin/env sbang", 1, None), - - # lua - ("--!/path/to/lua", 0, "/path/to/lua"), - - # node - ("//!/path/to/node", 0, "/path/to/node"), -]) -def test_sbang_with_specific_shebang( - tmpdir, shebang, returncode, expected): - - script = str(tmpdir.join("script")) - - # write a script out with <shebang> on second line - with open(script, "w") as f: - f.write("#!/bin/sh {sbang}\n{shebang}\n".format( - sbang=spack.paths.sbang_script, - shebang=shebang - )) - fs.set_executable(script) - - # test running the script in debug, which prints what would be executed - exe = which(script) - out = exe(output=str, fail_on_error=False, env={"SBANG_DEBUG": "1"}) - - # check error status and output vs. expected - assert exe.returncode == returncode - - if expected is not None: - expected += " " + script - assert expected == out.strip() |