However, if source-dir is a Subversion working copy, then all those annoying .svn subdirectories will also be copied to the store. Worse, the contents of those directories may change a lot, causing lots of spurious rebuilds. With filterSource you can filter out the .svn directories
That gives me the impression I can use builtins.filterSource to prevent files from being copied into the nix store and therefore prevent unnecessary rebuilds, but I am unable to make it work.
I created a simple flakes project using the filterSource example from the docs.
flake.nix
{
description = "A very basic flake";
outputs = { self, nixpkgs }:
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
in
{
defaultPackage.x86_64-linux = pkgs.stdenv.mkDerivation {
pname = "test";
version = "dev";
src = builtins.filterSource (path: type: type != "directory" || baseNameOf path != "data") ./.;
buildPhase = ''
find . > $out
'';
installPhase = "true";
};
};
}
data/exclude_me
Lorem ipsum
When I run nix build .#, the filter works as expected in the sense that $out contains
.
./flake.nix
./flake.lock
but if I make a change to the excluded file date >> date/exclude_me and re-run nix build .# the build is reexecuted despite the real src being the same (judging from $out contents).
Do I misinterpret the docs and this has never been possible, is it impossible with nix flakes, or am I just doing something wrong? Thanks in advance
Yeah, that is the issue. filterSource is called on a different store path each time so it will result in another different set of store paths, even though their content will be the same.
More generally, builtins.path is preferred over builtins.filterSource because the name argument is fixed instead of being derived from the folder name, which can vary if a user checked out the repo under a different name. But that’s not the issue here.
To better understand the core of the issue, the best thing to do is to inspect the diff of both srcs. Outside of flakes it’s possible to use nix-instanciate --eval . -A mypackage.src or nix repl . and then select mypackage.src to find out the store path. Take note, and then repeat until you have both store paths. With flakes, use nix show-derivation .#mypackage (for example) to find the inputSrcs argument. Same logic as before.
Your issue is the same as How to make `src = ./.` in a flake.nix not change a lot?, the name of the directory created by filterSource depends on the name of the initial directory, which is an impurity. builtins.path allows specifying a name that doesn’t depend on the source directory.
@Kha uses “src” as the namein here so that’s why path is working for them. You probably didn’t specified the name explicitly and it behaves similar to filterSource in that case.