{ description = "Proot-based bundler"; inputs = { nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, flake-utils, ... }: flake-utils.lib.eachSystem flake-utils.lib.allSystems ( system: let pkgs = import nixpkgs { inherit system; }; prootPatched = (pkgs.proot.override { enablePython = false; }).overrideAttrs (prev: { postFixup = (prev.postFixup or "") + '' exe=$out/bin/proot if interp="$(${pkgs.patchelf}/bin/patchelf --print-interpreter "$exe" 2>/dev/null)"; then ${pkgs.patchelf}/bin/patchelf --set-interpreter ."$interp" "$exe" fi if rpath="$(${pkgs.patchelf}/bin/patchelf --print-rpath "$exe" 2>/dev/null)"; then ${pkgs.patchelf}/bin/patchelf \ --set-rpath "$(printf %s "$rpath" | sed 's|/nix/store/|./nix/store/|g')" "$exe" fi ''; }); in { bundlers = rec { proot-bundler = drv: let ci = pkgs.closureInfo { rootPaths = [ drv prootPatched ]; }; mainProgram = drv.meta.mainProgram or (throw "${drv.name} has no meta.mainProgram set"); prootStoreBase = builtins.baseNameOf prootPatched; PROOT_REL = "/nix/store/${prootStoreBase}/bin/proot"; in pkgs.stdenvNoCC.mkDerivation { name = "${mainProgram}-bdl"; nativeBuildInputs = with pkgs; [ coreutils findutils gnutar gzip ]; dontFixup = true; buildCommand = '' set -euo pipefail PAY="$PWD/payload" mkdir -p "$PAY/nix/store" while IFS= read -r p; do cp -a --no-preserve=ownership "$p" "$PAY/nix/store/" done < ${ci}/store-paths APP_BIN="${drv}/bin/${mainProgram}" if [ ! -x "$APP_BIN" ]; then echo "mainProgram ${mainProgram} not found in ${drv}/bin" >&2 exit 1 fi APP_REL="$APP_BIN" _TMP="$(mktemp -d)" ( cd "$PAY" && tar \ --owner=0 --group=0 \ --mode=u+rw,uga+r \ --hard-dereference \ --format=gnu \ --sort=name \ -czf "$_TMP/payload.tar.gz" . ) cat > "$out" <<'SH' #!/bin/sh set -euf umask 077 unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT LD_DEBUG LD_PROFILE LD_USE_LOAD_BIAS LD_ORIGIN_PATH LD_ASSUME_KERNEL : "''${TMPDIR:=/tmp}" EXTRACT_DIR="$(mktemp -d "''${TMPDIR%/}/nxbdl.XXXXXX")" cleanup() { [ -n "''${KEEP_BUNDLE:-}" ] || rm -rf "$EXTRACT_DIR"; } trap cleanup EXIT INT TERM ARCHIVE_LINE=$(awk '/^__ARCHIVE_BELOW__/ {print NR+1; exit 0}' "$0") sed -n "''${ARCHIVE_LINE},\$p" "$0" | tar -xzf - -C "$EXTRACT_DIR" BUNDLE_PWD="''${BUNDLE_PWD:-$PWD}" cd "$EXTRACT_DIR" APP_REL='__APP_REL__' PROOT_REL='__PROOT_REL__' if [ -n "''${BUNDLE_PROOT:-}" ] && command -v "''${BUNDLE_PROOT}" >/dev/null 2>&1; then PROOT_BIN="''${BUNDLE_PROOT}" elif command -v proot >/dev/null 2>&1; then PROOT_BIN="$(command -v proot)" else PROOT_BIN="$EXTRACT_DIR${PROOT_REL}" fi [ "''${BUNDLE_FORCE_BUNDLED_PROOT:-0}" = 1 ] && PROOT_BIN="$EXTRACT_DIR${PROOT_REL}" [ -x "$PROOT_BIN" ] || { echo "proot not found/executable: $PROOT_BIN" >&2; exit 127; } [ -x "$EXTRACT_DIR''${APP_REL}" ] || { echo "app not found/executable: $EXTRACT_DIR''${APP_REL}" >&2; exit 127; } mkdir -p "$EXTRACT_DIR/etc" cat > "$EXTRACT_DIR/etc/resolv.conf" <<'EOF' nameserver 9.9.9.9 nameserver 8.8.8.8 nameserver 1.1.1.1 nameserver 1.0.0.1 EOF "''${PROOT_BIN}" \ -R / \ -b "$EXTRACT_DIR/nix:/nix" \ -b "$EXTRACT_DIR/etc/resolv.conf:/etc/resolv.conf" \ -b /dev -b /proc -b /sys \ -w "$BUNDLE_PWD" \ "$EXTRACT_DIR''${APP_REL}" "$@" exit $? __ARCHIVE_BELOW__ SH sed -i \ -e "s|__APP_REL__|$APP_REL|g" \ -e "s|__PROOT_REL__|${PROOT_REL}|g" \ "$out" cat "$_TMP/payload.tar.gz" >> "$out" chmod +x "$out" ''; }; default = proot-bundler; }; } ); }