$ nix-env -i hello
installing 'hello-2.10'
these paths will be fetched (0.02 MiB download, 0.07 MiB unpacked):
/nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10
copying path '/nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10' from 'https://cache.nixos.org'...
building '/nix/store/lvmi85vn4kgp1f99rhqzc18jxnw4vffn-user-environment.drv'...
created 212 symlinks in user environment
$ which hello
/Users/huangyi/.nix-profile/bin/hello
$ nix-env -e hello
uninstalling 'hello-2.10'
$ which hello
hello not found
$ nix-env --rollback
switching from generation 30 to 29
$ which hello
/Users/huangyi/.nix-profile/bin/hello
Notice:
- hash in directory name
- binary package download
- what is the user-environment
- uninstalling software is extremely fast
$ readlink $HOME/.nix-profile/bin/hello
/nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10/bin/hello
$ otool -L $HOME/.nix-profile/bin/hello
/nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10/bin/hello:
/nix/store/c0cbqklqg1ahap52ixv3gwcnmxpwk9f7-Libsystem-osx-10.12.6/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
Notice:
- packages are immutable, and connected with absolute paths, thus reproducible.
- the version number is for informational purposes only, since different versions are already identified by different hashes.
- a set of packages forms a directed immutable hash graph
- Can there be cycles?
A forest of symbolic links:
-
git gc
->nix-collect-garbage
when the packages finally get uninstalled
-
git push
->nix-copy-closure
poor man's deployment tool
https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/all-packages.nix
- visualization: MAPPING A UNIVERSE OF OPEN SOURCE SOFTWARE
How do you maintain such a giant immutable graph?
- nix expression language
$ nix-store -q --references `which hello`
/nix/store/c0cbqklqg1ahap52ixv3gwcnmxpwk9f7-Libsystem-osx-10.12.6
/nix/store/4yfhzgb68xj7157b9qxxl8gr3v5q5nax-swift-corefoundation
$ nix-store -qR `which hello`
/nix/store/c0cbqklqg1ahap52ixv3gwcnmxpwk9f7-Libsystem-osx-10.12.6
/nix/store/0scgf1j9wdakk4jwplnyrhw8m05vldax-openssl-1.1.1h
/nix/store/84507pkw9i7j3hc2dnc6nrzf10szmbzr-libc++abi-7.1.0
/nix/store/acbsjshd9mpq3hn9i1mj1l03jmc41828-libc++-7.1.0
/nix/store/91c1njy0cx0f02kp4lb571vrwi1n9dgn-ICU-osx-10.10.5
/nix/store/nxffklb14g8yb61p2fv3fpl9sj1mqj1y-zlib-1.2.11
/nix/store/mr5g67r8cnvfrsvsnh22vb82mw9hjqw7-libxml2-2.9.10
/nix/store/7kzamk0abm530kkr5v106hnc3cfscwkc-bash-4.4-p23
/nix/store/7z3yawqmw7haixbkw2kq85k3qjsmrzp5-libkrb5-1.18
/nix/store/8nwp8kh7bzw2h9wmyin8hshibvsq8lwp-libssh2-1.9.0
/nix/store/dpnp2kjxr2hiac1vipvnwc1liwfg8w6x-nghttp2-1.41.0-lib
/nix/store/sk20l6znqrq7rm2mgpxkn0rpfypih70f-curl-7.73.0
/nix/store/4yfhzgb68xj7157b9qxxl8gr3v5q5nax-swift-corefoundation
/nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10
nix-copy-closure
basically sync the closure to a remote machine.- you can also use
nix-store --export
nix-store --import
together with closure.
Derivation is basically nix's terminology for package, it contains all the information needed to build the output of a package. The hash of output is calculated based on the derivation, so the output hash is decided before actual building.
$ nix-instantiate '<nixpkgs>' -A hello
/nix/store/fz4sqv90q68ys3i9sfm2jv8xdzc177wr-hello-2.10.drv
$ nix-build -Q /nix/store/fz4sqv90q68ys3i9sfm2jv8xdzc177wr-hello-2.10.drv
/nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10
$ nix show-derivation /nix/store/fz4sqv90q68ys3i9sfm2jv8xdzc177wr-hello-2.10.drv
...
-
Replace the output hash with empty string in the
hello.drv
file -
TMP=$(nix-hash --type sha256 --flat hello.drv) echo -n "output:out:sha256:$TMP:/nix/store:hello" > tmp nix-hash --type sha256 --truncate --base32 --flat tmp
$ nix show-derivation /nix/store/fz4sqv90q68ys3i9sfm2jv8xdzc177wr-hello-2.10.drv
{
"/nix/store/fz4sqv90q68ys3i9sfm2jv8xdzc177wr-hello-2.10.drv": {
"platform": "x86_64-darwin",
"builder": "/nix/store/7kzamk0abm530kkr5v106hnc3cfscwkc-bash-4.4-p23/bin/bash",
"args": [
"-e",
"/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"
],
"env": {
"src": "/nix/store/3x7dwzq014bblazs7kq20p9hyzz0qh8g-hello-2.10.tar.gz",
...
},
...
}
}
You use nix expression language to build a derivation, the language has:
-
JSON-like syntax and data structures
(primitives, record, array)
-
Functional programming
(higher order functions, closures)
captured environment in nix code get translated to dependencies of derivation
-
Pure and lazy
(recursive data structure, fixed point)
https://github.com/crypto-com/chain-main/blob/master/default.nix
https://github.com/crypto-com/chain-main/blob/master/docker.nix
https://github.com/yihuang/chain-main/blob/testnet/default.nix#L107
-
Write configuration file
tasks-ini = writeTextDir "etc/supervisord.conf" (lib.generators.toINI { } { "fcgi-program:webapi" = { socket = "tcp://0.0.0.0:8000"; command = "${pyenv}/bin/uvicorn --fd 0 app:app"; }; "program:redis" = { command = ''${redis}/bin/redis-server --port ${toString redisport} --appendonly yes''; }; ... };
-
Combine them into a env
buildEnv { name = "awesome-env"; pathsToLink = ["/bin" "/etc" "/share"]; paths = [ redis postgresql supervisord tasks-ini ]; }
$ nix-env -i ... $ supervisord -c ~/.nix-profile/etc/supervisord.conf