On CI I often need to execute tasks from inside flake’s devShell – unfortunately not everything is nixifiable like some node monorepos or some cargo subcommands which require compilation of crate with some compile-time dependencies. I’ve not found any obvious way to populate binary cache for devShell dependencies. Even if I replace mkShell
by stdenv.mkDerivation
, the derivation does not contain it’s buildInputs
so nix copy
doesn’t copy them and the next time CI runs on preemptible instance it wastes tens of minutes on building buildInputs
again.
But I’ve found hacky way to guarantee that nix copy --to 'http://some-nix-store' .#devShell.x86_64-linux
copies all devShell dependencies. I’m sharing it here hoping that there is a less hacky way. If not, I hope it hepls someone who also use spot/preemptible instances which run flake devShell with slow-to-build dependencies.
{
inputs = {
# your inputs
};
outputs = { utils, ... }: utils.lib.eachDefaultSystem (system:
{
packages = {
# packages
};
devShell = pkgs.stdenv.mkDerivation rec {
name = "dev-shell";
src = ./.;
phases = "installPhase";
installPhase =
let keep =
writeScript "__keep" ''
echo ${stdenv.lib.makeBinPath buildInputs}
''; in
''
mkdir -p $out/bin
cd $out/bin
cp ${keep} __keep
'';
# usual devShell setup goes here..
};
};
);
}
I replace mkShell by mkDerivation to make nix copy
think that devShell is buildable and create __keep
script which holds references to all buildInputs
to convince nix that buildInputs
are needed by __keep
scripts. Such way commands like nix copy --print-build-logs --to 'file:///tmp/cache' .#devShell.x86_64-darwin
copy all devShell dependencies.