Skip to content

Instantly share code, notes, and snippets.

@Profpatsch
Last active January 9, 2017 11:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Profpatsch/7598a40c13440a0d1c7ad7ae97244de8 to your computer and use it in GitHub Desktop.
Save Profpatsch/7598a40c13440a0d1c7ad7ae97244de8 to your computer and use it in GitHub Desktop.
autoupdate nix expressions.
/* usage:
* echo '"stub"' > version.nix
* eval $(nix-build -A updater) ./.
* nix-build
*/
with import <nixpkgs> {};
let
/* The updater. This is what the maintainer/CI tool executes
* when it wants to update a package.
* It takes as first argument the root path of the packageset
* and as second attribute the package to update (simple version).
* The package to update has a meta attribute `update`, where
* `file` points to the (absolute!) path of the file that will
* be modified and `script` is the update script. More on the
* update script below.
* Note: This will live in a library function,
* just defined here for shortness.
*/
updater = writeScript "updater" ''
#!/usr/bin/env bash
ROOT="$1"
PRE=
if [ -n "$2" ]; then
# the attribute path of the package to update (if left out root)
PRE="''${2}."
fi
# We build the update script from `meta.update.script`
SCRIPT=$(nix-build "$ROOT" -A "''${PRE}meta.update.script")
# This extracts the file to write to from `meta.update.file`
OUT=$(nix-instantiate --eval "$ROOT" -A "''${PRE}meta.update.file")
# and finally write it
eval "$SCRIPT" > "$OUT"
'';
in
let
# the name of the file to write to
# note that these update files will always be overwritten
# and should *never* contain manual changes
ver = ./version.nix;
in stdenv.mkDerivation rec {
name = "foo-${version}";
# import the update file
# It only contains a version in this example
version = import ver;
src = ./.;
dontBuild = true;
installPhase = "echo bar; touch $out";
meta = {
# this is the magic part
update = {
# By nature of nix this is the absolute path of the current
# source file as a string (not the contents)
file = ver;
/* Here, the update script for this derivation is defined.
* Since it lives in `meta`, changes will not incfluence
* the actual derivation’s build hash.
*
* Build scripts should *never* write anything in the file
* system, particularly not write to `file`.
* Their interface is: they return the contents that will be
* put in the file on stdout. The builder should restrict them
* from being able to do anything except (probably) access
* the network.
*/
script = writeScript "${name}-updater" ''
#!/usr/bin/env bash
echo "\"$(date +%Hh%Mm%Ss)\""
'';
};
};
# just used to be able to access the updater for this example
passthru = {
inherit updater;
};
}
/*
* IDEAS
- the updaters should probably return JSON and have a kind of standardized
interface? This way the builder can find out what the build did.
- `meta.update` could have another attribute `resources` that tells
the builder what resources the update script needs to access to find out
about updates. This could go down to individual domains. By default everything
else should be as restricted as possible.
* BUGS
- the update file needs to exist with valid contents before running
the updater for the first time. This is because `mkDerivation` is still too
strict for its own good.
*/
@garbas
Copy link

garbas commented Dec 29, 2016

think is exactly how updateScript already works, except you are calling it updater in your example.

apart from this there is an ./maintainers/scripts/update.nix script which looks which package defines updateScript and executes in order. you can execute it also directly via nix-build as you are doing it here. but i found it very useful to be able to just type nix-shell ./maintainers/scripts/update.nix --argstr maintainer garbas which would update all packages i am maintaining.

i think what your example assumes is that updater will only package one package in nix expression. with python packages (and others *2nix tools) you want be able to generate multiple nix expressions/packages. and it would be nice to have this possibility.

of course i might misinterpret some of your code, but i think you already showed that ideas are quite similar if not even identical at its core.

@timbertson
Copy link

If I'm reading this properly, I'm not sure that generating nix files from scripts is a good idea. And in particular having everyone write their own ad-hoc scripts to generate a .nix file is going to lead to some heavy duplication and/or fragile scripts.

(I guess you could use this to generate JSON just as well, but generating JSON from a shell script is almost as hard as generating .nix)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment