summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2016-03-05 04:18:48 -0800
committerTodd Gamblin <tgamblin@llnl.gov>2016-03-05 04:18:48 -0800
commitfc6aa7374a243928af38fd1e583c6c67146951cd (patch)
tree22bb8eba191bd22d62a59cf4960def42ffe545bf /lib
parent8d2538f205ba9d9d9f0cafd678f500de04a6f144 (diff)
downloadspack-fc6aa7374a243928af38fd1e583c6c67146951cd.tar.gz
spack-fc6aa7374a243928af38fd1e583c6c67146951cd.tar.bz2
spack-fc6aa7374a243928af38fd1e583c6c67146951cd.tar.xz
spack-fc6aa7374a243928af38fd1e583c6c67146951cd.zip
Fix #104, #54: issues with overlong shebang in deep directories.
This does several things: - Add `sbang`: a script to run scripts with long shebang lines. - Documentation for `sbang` is in `bin/sbang`. - Add an `sbang` hook that filters the `bin` directory after install and modifies any scripts wtih shebangs that are too long to use `sbang` instead. - `sbang` is at the top level, so it should be runnable (not much we can do if spack itself is too deep for shebang) - `sbang`, when used as the interpreter, runs the *second* shebang line it finds in a script. - shoud fix issues with too long shebang paths.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/llnl/util/filesystem.py11
-rw-r--r--lib/spack/spack/hooks/sbang.py74
2 files changed, 84 insertions, 1 deletions
diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py
index da3cf96050..10d25bdce8 100644
--- a/lib/spack/llnl/util/filesystem.py
+++ b/lib/spack/llnl/util/filesystem.py
@@ -25,7 +25,8 @@
__all__ = ['set_install_permissions', 'install', 'install_tree', 'traverse_tree',
'expand_user', 'working_dir', 'touch', 'touchp', 'mkdirp',
'force_remove', 'join_path', 'ancestor', 'can_access', 'filter_file',
- 'FileFilter', 'change_sed_delimiter', 'is_exe', 'force_symlink']
+ 'FileFilter', 'change_sed_delimiter', 'is_exe', 'force_symlink',
+ 'copy_mode', 'unset_executable_mode']
import os
import sys
@@ -158,6 +159,14 @@ def copy_mode(src, dest):
os.chmod(dest, dest_mode)
+def unset_executable_mode(path):
+ mode = os.stat(path).st_mode
+ mode &= ~stat.S_IXUSR
+ mode &= ~stat.S_IXGRP
+ mode &= ~stat.S_IXOTH
+ os.chmod(path, mode)
+
+
def install(src, dest):
"""Manually install a file to a particular location."""
tty.debug("Installing %s to %s" % (src, dest))
diff --git a/lib/spack/spack/hooks/sbang.py b/lib/spack/spack/hooks/sbang.py
new file mode 100644
index 0000000000..6117c4809d
--- /dev/null
+++ b/lib/spack/spack/hooks/sbang.py
@@ -0,0 +1,74 @@
+##############################################################################
+# Copyright (c) 2013-2015, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://github.com/llnl/spack
+# Please also see the LICENSE file for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (as published by
+# the Free Software Foundation) version 2.1 dated February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+import os
+
+from llnl.util.filesystem import *
+import llnl.util.tty as tty
+
+import spack
+import spack.modules
+
+# Character limit for shebang line. Using Linux's 127 characters
+# here, as it is the shortest I could find on a modern OS.
+shebang_limit = 127
+
+def shebang_too_long(path):
+ """Detects whether an file has a shebang line that is too long."""
+ with open(path, 'r') as script:
+ bytes = script.read(2)
+ if bytes != '#!':
+ return False
+
+ line = bytes + script.readline()
+ return len(line) > shebang_limit
+
+
+def filter_shebang(path):
+ """Adds a second shebang line, using sbang, at the beginning of a file."""
+ backup = path + ".shebang.bak"
+ os.rename(path, backup)
+
+ with open(backup, 'r') as bak_file:
+ original = bak_file.read()
+
+ with open(path, 'w') as new_file:
+ new_file.write('#!/bin/bash %s/bin/sbang\n' % spack.spack_root)
+ new_file.write(original)
+
+ copy_mode(backup, path)
+ unset_executable_mode(backup)
+
+ tty.warn("Patched overly long shebang in %s" % path)
+
+
+def post_install(pkg):
+ """This hook edits scripts so that they call /bin/bash
+ $spack_prefix/bin/sbang instead of something longer than the
+ shebang limit."""
+ for file in os.listdir(pkg.prefix.bin):
+ path = os.path.join(pkg.prefix.bin, file)
+ if shebang_too_long(path):
+ filter_shebang(path)
+