sbang: add support for php (#18299)
PHP supports an initial shebang, but its comment syntax can't handle our 2-line shebangs. So, we need to embed the 2nd-line shebang comment to look like a PHP comment: <?php #!/path/to/php ?> This adds patching support to the sbang hook and support for instrumenting php shebangs. This also patches `phar`, which is a tool used to create php packages. `phar` itself has to add sbangs to those packages (as phar archives apparently contain UTF-8, as well as binary blobs), and `phar` sets a checksum based on the contents of the package. Co-authored-by: Todd Gamblin <tgamblin@llnl.gov>
This commit is contained in:
parent
cb07d9ddb1
commit
bb00b1a7c9
5 changed files with 105 additions and 7 deletions
25
bin/sbang
25
bin/sbang
|
@ -61,15 +61,23 @@
|
||||||
# Obviously, for this to work, `sbang` needs to have a short enough
|
# Obviously, for this to work, `sbang` needs to have a short enough
|
||||||
# path that *it* will run without hitting OS limits.
|
# path that *it* will run without hitting OS limits.
|
||||||
#
|
#
|
||||||
# For Lua, scripts the second line can't start with #!, as # is not
|
# For Lua, node, and php scripts, the second line can't start with #!, as
|
||||||
# the comment character in lua (even though lua ignores #! on the
|
# # is not the comment character in these languages (though they all
|
||||||
# *first* line of a script). So, instrument a lua script like this,
|
# ignore #! on the *first* line of a script). So, instrument such scripts
|
||||||
# using -- instead of # on the second line:
|
# like this, using --, //, or <?php ... ?> instead of # on the second
|
||||||
|
# line, e.g.:
|
||||||
#
|
#
|
||||||
# 1 #!/bin/bash /path/to/sbang
|
# 1 #!/bin/bash /path/to/sbang
|
||||||
# 2 --!/long/path/to/lua with arguments
|
# 2 --!/long/path/to/lua with arguments
|
||||||
# 3
|
# 3 print "success!"
|
||||||
# 4 print "success!"
|
#
|
||||||
|
# 1 #!/bin/bash /path/to/sbang
|
||||||
|
# 2 //!/long/path/to/node with arguments
|
||||||
|
# 3 print "success!"
|
||||||
|
#
|
||||||
|
# 1 #!/bin/bash /path/to/sbang
|
||||||
|
# 2 <?php #/long/path/to/php with arguments ?>
|
||||||
|
# 3 <?php echo "success!\n"; ?>
|
||||||
#
|
#
|
||||||
# How it works
|
# How it works
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
|
@ -90,6 +98,9 @@ while read line && ((lines < 2)) ; do
|
||||||
interpreter="${line#//!}"
|
interpreter="${line#//!}"
|
||||||
elif [[ "$line" = '--!'*lua* ]]; then
|
elif [[ "$line" = '--!'*lua* ]]; then
|
||||||
interpreter="${line#--!}"
|
interpreter="${line#--!}"
|
||||||
|
elif [[ "$line" = '<?php #!'*php* ]]; then
|
||||||
|
interpreter="${line#<?php\ \#!}"
|
||||||
|
interpreter="${interpreter%\ ?>}"
|
||||||
fi
|
fi
|
||||||
lines=$((lines+1))
|
lines=$((lines+1))
|
||||||
done < "$script"
|
done < "$script"
|
||||||
|
@ -98,7 +109,7 @@ done < "$script"
|
||||||
# #!/<spack-long-path>/perl -w
|
# #!/<spack-long-path>/perl -w
|
||||||
# this is the interpreter line with all the parameters as a vector
|
# this is the interpreter line with all the parameters as a vector
|
||||||
interpreter_v=(${interpreter})
|
interpreter_v=(${interpreter})
|
||||||
# this is the single interpreter path
|
# this is the single interpreter path
|
||||||
interpreter_f="${interpreter_v[0]}"
|
interpreter_f="${interpreter_v[0]}"
|
||||||
|
|
||||||
# Invoke any interpreter found, or raise an error if none was found.
|
# Invoke any interpreter found, or raise an error if none was found.
|
||||||
|
|
|
@ -64,6 +64,10 @@ def filter_shebang(path):
|
||||||
if re.search(r'^#!(/[^/\n]*)*lua\b', original):
|
if re.search(r'^#!(/[^/\n]*)*lua\b', original):
|
||||||
original = re.sub(r'^#', '--', original)
|
original = re.sub(r'^#', '--', original)
|
||||||
|
|
||||||
|
# Use <?php #! instead of #! on second line for php.
|
||||||
|
if re.search(r'^#!(/[^/\n]*)*php\b', original):
|
||||||
|
original = re.sub(r'^#', '<?php #', original) + ' ?>'
|
||||||
|
|
||||||
# Use //! instead of #! on second line for node.js.
|
# Use //! instead of #! on second line for node.js.
|
||||||
if re.search(r'^#!(/[^/\n]*)*node\b', original):
|
if re.search(r'^#!(/[^/\n]*)*node\b', original):
|
||||||
original = re.sub(r'^#', '//', original)
|
original = re.sub(r'^#', '//', original)
|
||||||
|
|
|
@ -30,6 +30,11 @@
|
||||||
node_in_text = ("line\n") * 100 + "lua\n" + ("line\n" * 100)
|
node_in_text = ("line\n") * 100 + "lua\n" + ("line\n" * 100)
|
||||||
node_line_patched = "//!/this/" + ('x' * 200) + "/is/node\n"
|
node_line_patched = "//!/this/" + ('x' * 200) + "/is/node\n"
|
||||||
sbang_line = '#!/bin/bash %s/bin/sbang\n' % spack.store.layout.root
|
sbang_line = '#!/bin/bash %s/bin/sbang\n' % spack.store.layout.root
|
||||||
|
php_line = "#!/this/" + ('x' * 200) + "/is/php\n"
|
||||||
|
php_in_text = ("line\n") * 100 + "php\n" + ("line\n" * 100)
|
||||||
|
php_line_patched = "<?php #!/this/" + ('x' * 200) + "/is/php\n"
|
||||||
|
php_line_patched2 = "?>\n"
|
||||||
|
sbang_line = '#!/bin/bash %s/bin/sbang\n' % spack.store.layout.root
|
||||||
last_line = "last!\n"
|
last_line = "last!\n"
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,6 +84,19 @@ def __init__(self):
|
||||||
f.write(node_in_text)
|
f.write(node_in_text)
|
||||||
f.write(last_line)
|
f.write(last_line)
|
||||||
|
|
||||||
|
# php script with long shebang
|
||||||
|
self.php_shebang = os.path.join(self.tempdir, 'php')
|
||||||
|
with open(self.php_shebang, 'w') as f:
|
||||||
|
f.write(php_line)
|
||||||
|
f.write(last_line)
|
||||||
|
|
||||||
|
# php script with long shebang
|
||||||
|
self.php_textbang = os.path.join(self.tempdir, 'php_in_text')
|
||||||
|
with open(self.php_textbang, 'w') as f:
|
||||||
|
f.write(short_line)
|
||||||
|
f.write(php_in_text)
|
||||||
|
f.write(last_line)
|
||||||
|
|
||||||
# Script already using sbang.
|
# Script already using sbang.
|
||||||
self.has_sbang = os.path.join(self.tempdir, 'shebang')
|
self.has_sbang = os.path.join(self.tempdir, 'shebang')
|
||||||
with open(self.has_sbang, 'w') as f:
|
with open(self.has_sbang, 'w') as f:
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
import spack.hooks.sbang as sbang
|
||||||
|
|
||||||
|
|
||||||
class Php(AutotoolsPackage):
|
class Php(AutotoolsPackage):
|
||||||
"""
|
"""
|
||||||
|
@ -36,6 +38,27 @@ class Php(AutotoolsPackage):
|
||||||
depends_on('libxml2')
|
depends_on('libxml2')
|
||||||
depends_on('sqlite')
|
depends_on('sqlite')
|
||||||
|
|
||||||
|
patch('sbang.patch')
|
||||||
|
|
||||||
|
def patch(self):
|
||||||
|
"""
|
||||||
|
phar sbang is added before build phase.
|
||||||
|
Because phar is php script with binary data
|
||||||
|
(Not UTF-8 text file) And phar is embeded own sha1 checksum.
|
||||||
|
"""
|
||||||
|
shebang_limit = 127
|
||||||
|
|
||||||
|
if len(self.prefix.bin.php) + 2 <= shebang_limit:
|
||||||
|
return
|
||||||
|
|
||||||
|
new_sbang_line = '#!/bin/bash %s' % sbang.sbang_install_path()
|
||||||
|
original_bang = '-b "$(PHP_PHARCMD_BANG)"'
|
||||||
|
makefile = join_path('ext', 'phar', 'Makefile.frag')
|
||||||
|
filter_file(
|
||||||
|
original_bang,
|
||||||
|
original_bang + ' -z "{0}"'.format(new_sbang_line),
|
||||||
|
makefile, string=True)
|
||||||
|
|
||||||
def autoreconf(self, spec, prefix):
|
def autoreconf(self, spec, prefix):
|
||||||
bash = which('bash')
|
bash = which('bash')
|
||||||
bash('./buildconf', '--force')
|
bash('./buildconf', '--force')
|
||||||
|
|
42
var/spack/repos/builtin/packages/php/sbang.patch
Executable file
42
var/spack/repos/builtin/packages/php/sbang.patch
Executable file
|
@ -0,0 +1,42 @@
|
||||||
|
--- spack-src/ext/phar/phar/pharcommand.inc.org 2019-12-18 01:35:53.000000000 +0900
|
||||||
|
+++ spack-src/ext/phar/phar/pharcommand.inc 2020-08-20 12:26:16.207347572 +0900
|
||||||
|
@@ -68,6 +68,12 @@
|
||||||
|
'inf' => '<bang> Hash-bang line to start the archive (e.g. #!/usr/bin/php). The hash '
|
||||||
|
.' mark itself \'#!\' and the newline character are optional.'
|
||||||
|
),
|
||||||
|
+ 'z' => array(
|
||||||
|
+ 'typ' => 'any',
|
||||||
|
+ 'val' => NULL,
|
||||||
|
+ 'inf' => '<bang> Hash-bang line to start the archive for spack. The hash '
|
||||||
|
+ .' mark itself \'#!\' and the newline character are optional.'
|
||||||
|
+ ),
|
||||||
|
'c' => array(
|
||||||
|
'typ' => 'compalg',
|
||||||
|
'val' => NULL,
|
||||||
|
@@ -455,7 +461,7 @@
|
||||||
|
*/
|
||||||
|
static function cli_cmd_arg_pack()
|
||||||
|
{
|
||||||
|
- $args = self::phar_args('abcFhilpsxy', 'pharnew');
|
||||||
|
+ $args = self::phar_args('azbcFhilpsxy', 'pharnew');
|
||||||
|
|
||||||
|
$args[''] = array(
|
||||||
|
'typ' => 'any',
|
||||||
|
@@ -560,6 +566,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
$alias = $this->args['a']['val'];
|
||||||
|
+ $spack_hb = $this->args['z']['val'];
|
||||||
|
$hashbang = $this->args['b']['val'];
|
||||||
|
$archive = $this->args['f']['val'];
|
||||||
|
$hash = $this->args['h']['val'];
|
||||||
|
@@ -571,6 +578,9 @@
|
||||||
|
$invregex = $this->args['x']['val'];
|
||||||
|
$input = $this->args['']['val'];
|
||||||
|
|
||||||
|
+ if (isset($spack_hb)) {
|
||||||
|
+ $hashbang = "$spack_hb\n<?php #!$hashbang ?>";
|
||||||
|
+ }
|
||||||
|
$hash = self::phar_check_hash($hash, $privkey);
|
||||||
|
|
||||||
|
$phar = new Phar($archive, 0, $alias);
|
Loading…
Reference in a new issue