on stack-cache-native help sign in
haskell.nix/lib/clean-source-with.nix
86 lines 3.7 kB history raw
1# This is a replacement for the cleanSourceWith function in nixpkgs
2# https://github.com/NixOS/nixpkgs/blob/1d9d31a0eb8e8358830528538a391df52f6a075a/lib/sources.nix#L41
3# It adds a subDir argument in a way that allows descending into a subdirectory
4# to compose with cleaning the source with a filter.
5{ lib }: rec {
7 # Like `builtins.filterSource`, except it will compose with itself,
8 # allowing you to chain multiple calls together without any
9 # intermediate copies being put in the nix store.
10 #
11 # lib.cleanSourceWith {
12 # filter = f;
13 # src = lib.cleanSourceWith {
14 # filter = g;
15 # src = ./.;
16 # };
17 # }
18 # # Succeeds!
19 #
20 # builtins.filterSource f (builtins.filterSource g ./.)
21 # # Fails!
22 #
23 # Parameters:
24 #
25 # src: A path or cleanSourceWith result to filter and/or rename.
26 #
27 # filter: A function (path -> type -> bool)
28 # Optional with default value: constant true (include everything)
29 # The function will be combined with the && operator such
30 # that src.filter is called lazily.
31 # For implementing a filter, see
32 # https://nixos.org/nix/manual/#builtin-filterSource
33 #
34 # subDir: Descend into a subdirectory in a way that will compose.
35 # It will be ase if `src = src + "/${subDir}` and filters
36 # already applied to `src` will be respected.
37 #
38 # name: Optional name to use as part of the store path.
39 # This defaults `src.name` or otherwise `baseNameOf src`.
40 # We recommend setting `name` whenever `src` is syntactically `./.`.
41 # Otherwise, you depend on `./.`'s name in the parent directory,
42 # which can cause inconsistent names, defeating caching.
43 #
44 cleanSourceWith = { filter ? _path: _type: true, src, subDir ? "", name ? null }:
45 let
46 subDir' = if subDir == "" then "" else "/" + subDir;
47 # In case this is mixed with older versions of cleanSourceWith
48 isFiltered = src ? _isLibCleanSourceWith;
49 isFilteredEx = src ? _isLibCleanSourceWithEx;
50 origSrc = if isFiltered || isFilteredEx then src.origSrc else src;
51 origSubDir = if isFilteredEx then src.origSubDir + subDir' else subDir';
52 origSrcSubDir = toString origSrc + origSubDir;
53 parentFilter = if isFiltered || isFilteredEx
54 then path: type: src.filter path type
55 else path: type: true;
56 filter' = path: type:
57 # Include parent paths based on the parent filter
58 (lib.strings.hasPrefix (path + "/") (origSrcSubDir + "/")
59 && parentFilter path type)
60 # Children only if both filters return true
61 || (lib.strings.hasPrefix (origSrcSubDir + "/") path
62 && (filter path type && parentFilter path type));
63 name' = if name != null
64 then name
65 else (if isFiltered && src ? name
66 then src.name
67 else baseNameOf src)
68 + (lib.optionalString (origSubDir != "") ("--" + baseNameOf origSubDir));
69 in {
70 inherit origSrc origSubDir origSrcSubDir;
71 filter = filter';
72 outPath = (builtins.path { filter = filter'; path = origSrc; name = name'; }) + origSubDir;
73 _isLibCleanSourceWithEx = true;
74 # It is only safe for older cleanSourceWith to filter this one
75 # if the we are still looking at the root of origSrc
76 _isLibCleanSourceWith = origSubDir == "";
77 name = name';
78 };
80 pathHasContext = builtins.hasContext or (lib.hasPrefix builtins.storeDir);
82 canCleanSource = src:
83 src ? _isLibCleanSourceWithEx
84 || src ? _isLibCleanSourceWith
85 || !(pathHasContext (toString src));