This is a random thing I started playing with after a conversation with @samueldr on IRC. Started with @matthewbauer’s nix-bundle which uses arx to bundle an executable and chroot into an env. And some inspiration from static-nix. Then added some opinionated defaults and a few hacks. Ended up with a self-installing script with minimal host machine dependencies.
As a user on a Linux machine without nix you can
- run ./myScript.sh which self-extracts the /nix/store to a tmp directory
- chroot’s into the environment
- It trims away the binary and wrapper and runs itself
- the nix-shell shebang will download/update dependencies
- your script runs.
- the store persists in /tmp and subsequent runs are faster
- edit the script directly, no recompilation needed
- single file contains everything
- no nix install needed
- easy cleanup, remove /tmp/tmpx-* and the file itself
- no root needed (actually, fails with root)
- super ugly hack
- only Linux due to nix-user-chroot
- Appimage approach doesn’t work due to the FUSE not writable by nix. Creating yet another store in another location led down a horrible rabbit hole.
- need to preload the correct /nix/store
- needs tricks to embed other languages into shell (see below)
- Too big
- Use static-nix?
- Appimage with non-standard remote store.
- nix run vs nix-shell: there are some benefits to the shebang approach, but nix run might be cleaner
The top of myScript.sh looks like:
#!/bin/sh if [ ! -z "$IN_NIX_USER_CHROOT"]; then #! /nix/env nix-shell #! nix-shell --pure -I nixpkgs=channel://nixpkgs-unstable -p hello -i sh echo Modify this script for a self-installing nix-shell in a chroot. echo "The store will persist in TMPDIR due to nix-bundle's arx approach." echo "This hard-codes a channel, feel free to modify." echo echo "Perhaps try '-i python' for a run-anywhere-with-nix python script" echo "Cons:" echo " Linux only due to nix-user-chroot" echo " nix-shell is slow to start" echo "Arguments:" shift echo "$@" ### Don't remove this exit, or weird things happen ### exit #ENDSENTINEL fi <ARX script> <BINARY>
Python support requires a bit of commenting polyglot goodness.
#!/bin/sh if [ ! -z "$IN_NIX_USER_CHROOT"]; then #! /nix/env nix-shell #! nix-shell --pure -I nixpkgs=channel://nixpkgs-unstable -p python bash -i python """": ' """ print("hi") quit() """ : ' """" # " #ENDSENTINEL fi <ARX script> <BINARY>
To build, grab https://github.com/tomberek/nix-bundle (c2ec9977325392e483dd090c8f7af2f909023076) and run
./nix-bundle.sh nix /bin/nix-shell to build a
nix-shell script, which can be manually edited.