summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2020-10-28 14:07:05 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2020-10-28 17:43:23 -0700
commitaebf20ebdc0f5d1ea03956681e0b16ffaffa9568 (patch)
tree154464aab993ed2aa40d8b675516f707113a6338
parent44bacefb27675aaed22d77c768fb18a627e678eb (diff)
downloadspack-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--COPYRIGHT12
-rwxr-xr-xbin/sbang110
-rw-r--r--lib/spack/spack/cmd/license.py1
-rw-r--r--lib/spack/spack/test/sbang.py65
4 files changed, 24 insertions, 164 deletions
diff --git a/COPYRIGHT b/COPYRIGHT
index ae21fe54bd..7bc67442d7 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -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
diff --git a/bin/sbang b/bin/sbang
index 983f778651..c8f1c7c39c 100755
--- a/bin/sbang
+++ b/bin/sbang
@@ -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()