Comment by lloeki
2 years ago
> Part of the reason that it’s painful to use is because while it’s marketed as “declarative”, in actuality it’s functional
You're correct, with a twist: NixOS is declarative, nix is not - it's indeed functional machinery.
This exposes a declarative interface:
https://github.com/NixOS/nixpkgs/tree/master/nixos/modules
https://github.com/NixOS/nixos-hardware
https://github.com/LnL7/nix-darwin/tree/master/modules
This does not:
https://github.com/NixOS/nixpkgs/tree/master/pkgs
but being functional makes it easier for the declarative bits to exist, e.g the next step in this case (PR pending on my side to contribute just that upstream) is:
- creating systemd.services."nqptp" with enabled = false as a default
- transforming services.shairport-sync to reference systemd.services."nqptp".enabled = true when enableAirplay2 = true
https://github.com/NixOS/nixpkgs/issues/258643
It also makes pinning/rollback to a specific version without touching the remainder of the system a spectacular non-event:
https://github.com/NixOS/nixpkgs/issues/245769
Even when `.package` is not made available it's only slightly harder to use another module with disabledModules + import.
> Another evening I sat down to make a minor feature to a Python library and decided to use a nix environment. In theory, this should have been better than a virtualenv. In practice, there’s no in-tree support for specifying specific versions of Python libraries, and mach-nix had trouble with the dependencies
Maybe you tried too hard to "nixify" everything, including managing the whole of python stuff. That's what I use:
# shell.nix
{
pkgs ? import <nixpkgs> {},
}:
let
# get these python packages from nix
python_packages = python-packages: [
python-packages.pip
];
# use this pyton version, and include the above packages
python = pkgs.python39.withPackages python_packages;
in pkgs.mkShell {
buildInputs = [
python
];
shellHook = ''
# get python version
export PYTHON_VERSION="$(python -c 'import platform; import re; print(re.sub(r"\.\d+$", "", platform.python_version()))')"
# replicate virtualenv behaviour
export PIP_PREFIX="$PWD/vendor/python/$PYTHON_VERSION/packages"
export PYTHONPATH="$PIP_PREFIX/lib/python$PYTHON_VERSION/site-packages:$PYTHONPATH"
unset SOURCE_DATE_EPOCH
export PATH="$PIP_PREFIX/bin:$PATH"
'';
}
And then just `pip -r requirements` or whatever poetry you fancy.
On a specific project I needed a bit more control, and some fix because of a braindead build system. Fix once and be done with it.
# shell.nix
{
pinned ? import(fetchTarball("https://github.com/NixOS/nixpkgs/archive/88f63d51109.tar.gz")) {},
}:
let
# get these python packages from nix
python_packages = python-packages: [
python-packages.pip
];
# use this pyton version, and include the above packages
python = pinned.python39.withPackages python_packages;
# control llvm/clang version (e.g for packages built from source)
llvm = pinned.llvmPackages_12;
in llvm.stdenv.mkDerivation {
# unique project name for this environment derivation
name = "whatevs.shell";
buildInputs = [
# version to use + default packages are declared above
python
# linters
pinned.shellcheck
# for scripts
pinned.bash
pinned.fswatch
pinned.rsync
# for c++ dependencies such as grpcio-tools
llvm.libcxx.dev
];
shellHook = ''
# get python version
export PYTHON_VERSION="$(python -c 'import platform; import re; print(re.sub(r"\.\d+$", "", platform.python_version()))')"
# replicate virtualenv behaviour
export PIP_PREFIX="$PWD/vendor/python/$PYTHON_VERSION/packages"
export PYTHONPATH="$PIP_PREFIX/lib/python$PYTHON_VERSION/site-packages:$PYTHONPATH"
unset SOURCE_DATE_EPOCH
export PATH="$PIP_PREFIX/bin:$PATH"
# for grpcio-tools, which is building from source but doesn't pick up the proper include
export CFLAGS="-I${llvm.libcxx.dev}/include/c++/v1"
'';
}
Sure that's not pure nix or flakesy or whatever, but simply delegating python things to python-land is a very pragmatic move, idealistic purity and reproducibility of everything be damned, it is instantly better than homebrew or docker because that setup gets you a consistent tooling environment on any Darwin (Intel or ARM, at whatever version) or Linux (whether it's NixOS or just nixpkgs).
Also it's super amenable to collaborators who don't know the first thing about nix: they can blindly type `nix-shell` and be all the merrier, handling their python stuff as usual, and completely removing a whole class of "it works/breaks on my machine".
No comments yet
Contribute on Hacker News ↗