Merge pull request #48 from haslersn/enhancement/modern-cli

nix-bundle.sh: Modernize CLI
This commit is contained in:
Matthew Bauer 2019-11-03 12:00:18 -05:00 committed by GitHub
commit 4300437ede
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,56 +1,178 @@
#!/usr/bin/env sh
if [ "$#" -lt 2 ]; then
cat <<EOF
fail() {
echo "Try '$0 --help'." >&2
exit 2
}
Usage: $0 TARGET EXECUTABLE
build() {
linkdir=$(mktemp -d)
nix build "$@" --out-link "$linkdir/result"
readlink "$linkdir/result"
}
Create a single-file bundle from the nixpkgs attribute "TARGET".
EXECUTABLE should be relative to the TARGET's output path.
For example:
$ $0 hello /bin/hello
$ ./hello
Hello, world!
EOF
exit 1
fi
check_arg() {
if [ $# -le 1 ]
then
echo "error: flag '$1' requires an argument" >&2
fail
fi
}
nix_file=`dirname $0`/default.nix
target="$1"
shift
# Read arguments
extraTargets=
if [ "$#" -gt 1 ]; then
while [ "$#" -gt 1 ]; do
extraTargets="$extraTargets $1"
shift
done
build_flags=()
unset bin
targets=()
while [ $# -ne 0 ]
do
case "$1" in
-f|--file|-I|--include)
check_arg "$@"
build_flags+=("$1")
shift
build_flags+=("$1")
shift
;;
--arg|--argstr)
if [ $# -le 2 ]
then
echo "error: flag '$1' requires two arguments" >&2
fail
fi
build_flags+=("$1")
shift
build_flags+=("$1")
shift
build_flags+=("$1")
shift
;;
--bin)
check_arg "$@"
shift
bin="$1"
shift
;;
-h|--help)
cat <<EOF >&2
Usage: $0 <FLAGS>... [<TARGET>] <targets>...
Summary: Similar to nix build, but creates a single-file bundle.
Flags:
--arg <NAME> <EXPR> argument to be passed to Nix functions
--argstr <NAME> <STRING> string-valued argument to be passed to Nix functions
-f, --file <FILE> evaluate FILE rather than the default
-I, --include <PATH> add a path to the list of locations used to look up <...> file names
--bin <BINARY> the binary to bundle, relative to TARGET's output path; defaults to
the lexicographically first file inside /bin
Examples:
To bundle GNU Hello from NixOS 19.03:
$ $0 -f channel:nixos-19.03 hello --bin /bin/hello
To bundle the executable from within a project that has a default.nix for build:
$ $0 --bin /bin/name-of-the-executable
EOF
exit 0
;;
--)
shift
break
;;
-*)
echo "error: unrecognized flag '$1'" >&2
fail
;;
*)
targets+=("$1")
shift
;;
esac
done
while [ $# -ne 0 ]
do
targets+=("$1")
shift
done
# Add application-specific extra targets
if [ "${targets[0]}" = "nix-bundle" ] || [ "${targets[0]}" = "nixStable" ] || [ "${targets[0]}" = "nixUnstable" ] || [ "${targets[0]}" = "nix" ]
then
targets+=("bash")
targets+=("bzip2")
targets+=("coreutils")
targets+=("gnutar")
targets+=("gzip")
targets+=("xz")
fi
exec="$1"
shift
# Create tmp directory for the links produced by `nix build`
linkdir=$(mktemp -d)
build_flags+=("--out-link")
build_flags+=("$linkdir/result")
# Build targets
target_path=
extra_target_paths=()
for target in "${targets[@]}"
do
nix build "${build_flags[@]}" "$target" || exit $?
out_link="$linkdir/$(ls "$linkdir")"
if [ -z "$target_path" ]
then
target_path="$(readlink "$out_link")"
else
extra_target_paths+=("\"$(readlink "$out_link")\"")
fi
rm "$out_link"
done
if [ -z "$target_path" ]
then
nix build "${build_flags[@]}" || exit $?
out_link="$(ls "$linkdir")"
target_path="$(readlink "$out_link")"
fi
# Apply default for --bin
if [ -z ${bin+x} ]
then
bin=$(ls "$target_path/bin" | head -1)
fi
# Determine bootstrap function -- This seems like a total hack!
bootstrap=nix-bootstrap
if [ "$target" = "nix-bundle" ] || [ "$target" = "nixStable" ] || [ "$target" = "nixUnstable" ] || [ "$target" = "nix" ]; then
bootstrap=nix-bootstrap-nix
elif ! [ -z "$extraTargets" ]; then
if ! [ -z "$extra_target_paths" ]; then
bootstrap=nix-bootstrap-path
fi
expr="with import <nixpkgs> {}; with import $nix_file {}; $bootstrap { target = $target; extraTargets = [ $extraTargets ]; run = \"$exec\"; }"
# Run bootstrap function
expr="(with import $nix_file {}; $bootstrap { target = \"$target_path\"; extraTargets = [ ${extra_target_paths[@]} ]; run = \"$bin\"; })"
echo $expr
out=$(nix-store --no-gc-warning -r $(nix-instantiate --no-gc-warning -E "$expr"))
# Copy the created bundle to the working directory
if [ -z "$out" ]; then
>&2 echo "$0 failed. Exiting."
exit 1
elif [ -t 1 ]; then
filename=$(basename $exec)
filename=$(basename $bin)
echo "Nix bundle created at $filename."
cp -f $out $filename
else