From 421e2c5e7968da23cd0fcfe22f76f032b6d700ae Mon Sep 17 00:00:00 2001 From: jtimberman Date: Mon, 22 Feb 2016 18:03:51 -0700 Subject: [PATCH] [bldr-build] Add fix_shebang, pkg_interpreter_for This commit introduces the fix_shebang and pkg_interpreter_for functions. * fix_shebang is used to modify hardcoded shebang lines in interpreted scripts to use the paths in the INTERPRETERS metadata * pkg_interpreter_for finds the specified interpreter in the INTERPRETERS metadata for the given package * We now support adding pkg_interpreters in plan.sh to specify binaries of interpreters provided by the package * The interpreters are added to the new INTERPRETERS metadata Expose the interpreters using the subdirectory of their binary, for example bin/bash, because some packages may have directories besides bin where their interpreters are such as sbin or libexec. --- plans/bash/plan.sh | 1 + plans/bldr-build | 87 ++++++++++++++++++++++++++++++++++++ plans/bootstrap-toolchain.sh | 2 +- plans/busybox/plan.sh | 1 + plans/coreutils/plan.sh | 1 + plans/gawk/plan.sh | 1 + plans/perl/plan.sh | 1 + plans/ruby/plan.sh | 2 + 8 files changed, 95 insertions(+), 1 deletion(-) diff --git a/plans/bash/plan.sh b/plans/bash/plan.sh index 3b73d85310..86ed5b01e6 100644 --- a/plans/bash/plan.sh +++ b/plans/bash/plan.sh @@ -13,6 +13,7 @@ pkg_deps=(chef/glibc chef/ncurses chef/readline) pkg_build_deps=(chef/coreutils chef/diffutils chef/patch chef/make chef/gcc) pkg_binary_path=(bin) pkg_gpg_key=3853DA6B +pkg_interpreters=(bin/bash bin/sh) do_begin() { # The maintainer of Bash only releases these patches to fix serious issues, diff --git a/plans/bldr-build b/plans/bldr-build index 42926e9bf0..76c76ed1a3 100755 --- a/plans/bldr-build +++ b/plans/bldr-build @@ -158,6 +158,17 @@ # pkg_derivation=bldr # ``` # +# ### pkg_interpreters +# An array of interpreters used in shebang lines for scripts. Specify +# the subdirectory where the binary is relative to the package, e.g., +# `bin/bash` or `libexec/neverland`, since binaries can be located in +# directories besides `bin`. This list of interpreters will be written +# to the metadata INTERPRETERS file with their fully-qualified path. +# Then these can be used with the `fix_interpreter` function in this script. +# ``` +# pkg_interpreters=(bin/bash bin/sh) +# ``` +# # ## Plan variables # # `bldr-build` sets a few useful variables for you, in addition to the ones you @@ -1034,6 +1045,76 @@ unpack_file() { return 0 } +# Edit the `#!` shebang of the target file in-place. Useful for +# changing hardcoded `/usr/bin/env` to our coreutils, for example. Be +# sure to depend on the required package that provides the expected +# path for the shebang in `pkg_deps`. This does a greedy match against +# the specified interpreter in the target file(s). +# +# To use this function in your plan.sh, specify the following +# arguments: +# +# 1. The target file or files +# 2. The name of the package that contains the interpreter +# 3. The relative directory and binary path to the interpreter +# +# For example, to replace all the files in `node_modules/.bin` that +# have `#!/usr/bin/env` with the `coreutils` path +# to `bin/env` (which resolves to +# /opt/bldr/pkgs/chef/coreutils/8.24/20160219013458/bin/env): +# +# fix_interpreter node_modules/.bin/* chef/coreutils bin/env +# +# For a single target: +# +# fix_interpreter node_modules/.bin/concurrent chef/coreutils bin/env +# +# To get the interpreters exposed by a package, look in that package's +# INTERPRETERS metadata file, e.g., +# `/opt/bldr/pkgs/chef/coreutils/8.24/20160219013458/INTERPRETERS` + +fix_interpreter() { + local targets=$1 + local pkg=$2 + local int=$3 + local interpreter_old=".*${int}" + local interpreter_new="$(pkg_interpreter_for ${pkg} ${int})" + + for t in ${targets}; do + build_line "Replacing '${interpreter_old} with ${interpreter_new} in ${t}" + sed -e "s#\#\!${interpreter_old}#\#\!${interpreter_new}#" -i $t + done +} + +# Returns the path for the given package and interpreter by reading it +# from the INTERPRETERS metadata in the package. The directory of the +# interpreter needs to be specified, as an interpeter binary might +# live in `bin`, `sbin`, or `libexec`, depending on the software. +# +# ``` +# pkg_interpreter_for chef/coreutils bin/env +# ``` +# +# Will return 0 if the specified package and interpreter were found, +# and 1 if the package could not be found or the interpreter is not +# specified for that package. +pkg_interpreter_for() { + local pkg=$1 + local int=$2 + local path=$(pkg_path_for $pkg) + if [[ -z $path || $? -ne 0 ]]; then + warn "Could not resolve the path for ${pkg}, is it specified in 'pkg_deps'?" + return 1 + fi + + local int_path=$(grep -x ".*${int}" ${path}/INTERPRETERS) + if [[ ! -z "$int_path" ]]; then + echo $int_path + return 0 + fi + warn "Could not find interpreter ${int} in package ${pkg}" + return 1 +} # ## Build Phases # @@ -1509,6 +1590,11 @@ _build_metadata() { echo $port_part > $pkg_path/EXPOSES fi + local interpreters="$(printf "${pkg_path}/%s\n" ${pkg_interpreters[@]})" + if [[ -n $interpreters ]]; then + echo "$interpreters" > $pkg_path/INTERPRETERS + fi + local cutn="$(($(echo $BLDR_PKG_ROOT | grep -o '/' | wc -l)+2))" local deps @@ -1638,6 +1724,7 @@ SHA: $pkg_shasum Path: $pkg_path Build Dependencies: $(printf "%s " ${pkg_build_deps[@]}) Dependencies: $(printf "%s " ${pkg_deps[@]}) +Interpreters $(printf "%s " ${pkg_interpreters[@]}) Plan ======== diff --git a/plans/bootstrap-toolchain.sh b/plans/bootstrap-toolchain.sh index bcaf3c7ac0..3fe839fc1d 100755 --- a/plans/bootstrap-toolchain.sh +++ b/plans/bootstrap-toolchain.sh @@ -1,4 +1,4 @@ -#1/bin/sh +#!/bin/sh set -eu if [ -n "${DEBUG:-}" ]; then set -x; fi diff --git a/plans/busybox/plan.sh b/plans/busybox/plan.sh index a26416c3e7..3b29498d78 100644 --- a/plans/busybox/plan.sh +++ b/plans/busybox/plan.sh @@ -10,6 +10,7 @@ pkg_deps=(chef/glibc) pkg_build_deps=(chef/gcc chef/coreutils chef/sed chef/bison chef/flex chef/grep chef/bash chef/gawk chef/libtool chef/diffutils chef/findutils chef/xz chef/gettext chef/gzip chef/make chef/patch chef/texinfo chef/util-linux chef/wget) pkg_binary_path=(bin sbin) pkg_gpg_key=3853DA6B +pkg_interpreters=(bin/ash bin/awk bin/env bin/sh) do_build() { make -j$(nproc) diff --git a/plans/coreutils/plan.sh b/plans/coreutils/plan.sh index 1e8292acda..e33f92bf15 100644 --- a/plans/coreutils/plan.sh +++ b/plans/coreutils/plan.sh @@ -10,6 +10,7 @@ pkg_deps=(chef/glibc chef/acl chef/attr chef/gmp chef/libcap) pkg_build_deps=(chef/coreutils chef/diffutils chef/patch chef/make chef/gcc chef/m4 chef/perl) pkg_binary_path=(bin) pkg_gpg_key=3853DA6B +pkg_interpreters=(bin/env) do_build() { # The `FORCE_` variable allows the software to compile with the root user, diff --git a/plans/gawk/plan.sh b/plans/gawk/plan.sh index 8cd08afeb2..b0a2e42ad8 100644 --- a/plans/gawk/plan.sh +++ b/plans/gawk/plan.sh @@ -9,6 +9,7 @@ pkg_deps=(chef/glibc chef/mpfr) pkg_build_deps=(chef/coreutils chef/diffutils chef/patch chef/make chef/gcc chef/sed) pkg_binary_path=(bin) pkg_gpg_key=3853DA6B +pkg_interpreters=(bin/awk bin/gawk) do_check() { make check diff --git a/plans/perl/plan.sh b/plans/perl/plan.sh index f1c0718575..ddc3d98a2e 100644 --- a/plans/perl/plan.sh +++ b/plans/perl/plan.sh @@ -10,6 +10,7 @@ pkg_build_deps=(chef/coreutils chef/diffutils chef/patch chef/make chef/gcc chef pkg_binary_path=(bin) pkg_lib_dirs=(lib) pkg_gpg_key=3853DA6B +pkg_interpreters=(bin/perl) do_prepare() { do_default_prepare diff --git a/plans/ruby/plan.sh b/plans/ruby/plan.sh index caf24b23ac..476da93fe3 100644 --- a/plans/ruby/plan.sh +++ b/plans/ruby/plan.sh @@ -11,6 +11,8 @@ pkg_deps=(chef/glibc chef/ncurses chef/zlib chef/libedit chef/openssl chef/libyaml chef/libiconv chef/libffi) pkg_lib_dirs=(lib) pkg_include_dirs=(include) +pkg_binary_path=(bin) +pkg_interpreters=(bin/ruby) do_build() { CFLAGS="${CFLAGS} -O3 -g -pipe"