@@ -1,56 +1,178 @@
1#!/usr/bin/env sh
1#!/usr/bin/env sh
3−if [ "$#" -lt 2 ]; then
3+fail() {
4− cat <<EOF
4+ echo "Try '$0 --help'." >&2
6−Usage: $0 TARGET EXECUTABLE
8+build() {
10+ nix build "$@" --out-link "$linkdir/result"
11+ readlink "$linkdir/result"
8−Create a single-file bundle from the nixpkgs attribute "TARGET".
14+check_arg() {
9−EXECUTABLE should be relative to the TARGET's output path.
15+ if [ $# -le 1 ]
17+ echo "error: flag '$1' requires an argument" >&2
11−For example:
22+nix_file=`dirname $0`/default.nix
33+ -f|--file|-I|--include)
43+ echo "error: flag '$1' requires two arguments" >&2
61+Usage: $0 <FLAGS>... [<TARGET>] <targets>...
63+Summary: Similar to nix build, but creates a single-file bundle.
13−$ $0 hello /bin/hello
65+Flags:
14−$ ./hello
66+ --arg <NAME> <EXPR> argument to be passed to Nix functions
15−Hello, world!
67+ --argstr <NAME> <STRING> string-valued argument to be passed to Nix functions
68+ -f, --file <FILE> evaluate FILE rather than the default
69+ -I, --include <PATH> add a path to the list of locations used to look up <...> file names
70+ --bin <BINARY> the binary to bundle, relative to TARGET's output path; defaults to
71+ the lexicographically first file inside /bin
75+ To bundle GNU Hello from NixOS 19.03:
76+ $ $0 -f channel:nixos-19.03 hello --bin /bin/hello
78+ To bundle the executable from within a project that has a default.nix for build:
79+ $ $0 --bin /bin/name-of-the-executable
88+ echo "error: unrecognized flag '$1'" >&2
19− exit 1
104+# Add application-specific extra targets
106+if [ "${targets[0]}" = "nix-bundle" ] || [ "${targets[0]}" = "nixStable" ] || [ "${targets[0]}" = "nixUnstable" ] || [ "${targets[0]}" = "nix" ]
110+ targets+=("coreutils")
22−nix_file=`dirname $0`/default.nix
116+# Create tmp directory for the links produced by `nix build`
24−target="$1"
118+linkdir=$(mktemp -d)
25−shift
119+build_flags+=("--out-link")
120+build_flags+=("$linkdir/result")
27−extraTargets=
122+# Build targets
28−if [ "$#" -gt 1 ]; then
123+
29− while [ "$#" -gt 1 ]; do
124+target_path=
30− extraTargets="$extraTargets $1"
125+extra_target_paths=()
127+for target in "${targets[@]}"
129+ nix build "${build_flags[@]}" "$target" || exit $?
130+ out_link="$linkdir/$(ls "$linkdir")"
131+ if [ -z "$target_path" ]
133+ target_path="$(readlink "$out_link")"
135+ extra_target_paths+=("\"$(readlink "$out_link")\"")
140+if [ -z "$target_path" ]
142+ nix build "${build_flags[@]}" || exit $?
143+ out_link="$(ls "$linkdir")"
144+ target_path="$(readlink "$out_link")"
35−exec="$1"
147+# Apply default for --bin
151+ bin=$(ls "$target_path/bin" | head -1)
154+# Determine bootstrap function -- This seems like a total hack!
38bootstrap=nix-bootstrap
156bootstrap=nix-bootstrap
39−if [ "$target" = "nix-bundle" ] || [ "$target" = "nixStable" ] || [ "$target" = "nixUnstable" ] || [ "$target" = "nix" ]; then
157+if ! [ -z "$extra_target_paths" ]; then
40− bootstrap=nix-bootstrap-nix
41−elif ! [ -z "$extraTargets" ]; then
42 bootstrap=nix-bootstrap-path
158 bootstrap=nix-bootstrap-path
161+# Run bootstrap function
45−expr="with import <nixpkgs> {}; with import $nix_file {}; $bootstrap { target = $target; extraTargets = [ $extraTargets ]; run = \"$exec\"; }"
163+expr="(with import $nix_file {}; $bootstrap { target = \"$target_path\"; extraTargets = [ ${extra_target_paths[@]} ]; run = \"$bin\"; })"
47out=$(nix-store --no-gc-warning -r $(nix-instantiate --no-gc-warning -E "$expr"))
167out=$(nix-store --no-gc-warning -r $(nix-instantiate --no-gc-warning -E "$expr"))
169+# Copy the created bundle to the working directory
49if [ -z "$out" ]; then
171if [ -z "$out" ]; then
50 >&2 echo "$0 failed. Exiting."
172 >&2 echo "$0 failed. Exiting."
52elif [ -t 1 ]; then
174elif [ -t 1 ]; then
53− filename=$(basename $exec)
175+ filename=$(basename $bin)
54 echo "Nix bundle created at $filename."
176 echo "Nix bundle created at $filename."
55 cp -f $out $filename
177 cp -f $out $filename