commit 1978aee9c4fcca8dd9579895ede21530b80f2cd5 Author: Slendi Date: Tue Sep 16 14:05:17 2025 +0300 yes Signed-off-by: Slendi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a88ab8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.direnv + diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..b4231c3 --- /dev/null +++ b/flake.nix @@ -0,0 +1,122 @@ +{ + description = "My flake"; + + 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.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { inherit system; }; + in + { + bundlers = rec { + proot-bundler = + drv: + pkgs.stdenvNoCC.mkDerivation { + name = "myApp.run"; + nativeBuildInputs = [ + pkgs.nix + pkgs.coreutils + pkgs.findutils + pkgs.gnutar + pkgs.gzip + pkgs.patchelf + ]; + # patch proot as you described + prootPatched = pkgs.proot.overrideAttrs (_: { + postFixup = '' + exe=$out/bin/proot + ${pkgs.patchelf}/bin/patchelf \ + --set-interpreter ."$(${pkgs.patchelf}/bin/patchelf --print-interpreter $exe)" \ + --set-rpath "$(${pkgs.patchelf}/bin/patchelf --print-rpath $exe | sed 's|/nix/store/|./nix/store/|g')" \ + $exe + ''; + }); + + buildCommand = '' + set -euo pipefail + # 1) Make payload dir that mirrors the bundle runtime layout + PAY="$PWD/payload" + mkdir -p "$PAY/nix/store" + + # include app + patched proot in the payload closure + app=${drv} + proot=${ + self.bundlers.${system}.selfExtracting.prootPatched or "" + } # not callable; we want the attr above + proot=${ + pkgs.proot.overrideAttrs (_: { + postFixup = "${pkgs.patchelf}/bin/patchelf --set-interpreter .\"$(${pkgs.patchelf}/bin/patchelf --print-interpreter $out/bin/proot)\" --set-rpath \"$( ${pkgs.patchelf}/bin/patchelf --print-rpath $out/bin/proot | sed 's|/nix/store/|./nix/store/|g')\" $out/bin/proot"; + }) + } + + # copy closure of app + proot into ./nix/store + paths=$( ${pkgs.nix}/bin/nix-store --query --requisites "$app" "$proot" ) + for p in $paths; do + cp -a --no-preserve=ownership "$p" "$PAY/nix/store/" + done + + # discover targets for the launcher + APP_BIN=$(find "$app/bin" -maxdepth 1 -type f -perm -111 | head -n1) + APP_REL="/nix/store/$(basename "$(dirname "$APP_BIN")")/$(basename "$APP_BIN")" + PROOT_REL="/nix/store/$(basename "$proot")/bin/proot" + + # 2) Tar.gz the payload + ( cd "$PAY" && tar -czf "$PWD/payload.tar.gz" . ) + + # 3) Assemble a self-extracting script at $out + cat > $out <<'SH' + #!/bin/sh + set -euf + # extract to temp dir + : "''${TMPDIR:=/tmp}" + EXTRACT_DIR="$(mktemp -d "''${TMPDIR%/}/nxbdl.XXXXXX")" + cleanup() { [ -n "''${KEEP_BUNDLE:-}" ] || rm -rf "$EXTRACT_DIR"; } + trap cleanup EXIT INT TERM + + # locate embedded archive (line after marker) + ARCHIVE_LINE=$(awk '/^__ARCHIVE_BELOW__/ {print NR+1; exit 0}' "$0") + tail -n +$ARCHIVE_LINE "$0" | tar -xzf - -C "$EXTRACT_DIR" + + cd "$EXTRACT_DIR" + # vars substituted by bundler at build time: + APP_REL='__APP_REL__' + PROOT_REL='__PROOT_REL__' + + # run via proot + BUNDLE_PWD="''${BUNDLE_PWD:-$PWD}" + exec ".$PROOT_REL" \ + -b ./nix:nix \ + -R / \ + -w "$BUNDLE_PWD" \ + ".$APP_REL" "$@" + + __ARCHIVE_BELOW__ + SH + + # substitute the program + proot paths into the stub + sed -i \ + -e "s|__APP_REL__|$APP_REL|g" \ + -e "s|__PROOT_REL__|$PROOT_REL|g" \ + $out + chmod +x $out + + # 4) Append the payload bytes after the marker + cat payload.tar.gz >> $out + ''; + }; + + default = proot-bundler; + }; + } + ); +}