on stack-cache-native help sign in
haskell.nix/lib/clean-cabal-component.nix
88 lines 4.0 kB history raw
1# Use cleanSourceWith to filter just the files needed for a particular
2# component of the package
3{ lib, cleanSourceWith }: package: component: src:
4let
5 srcStr' = src.origSrcSubDir or src.origSrc or null;
6 # Transform
7 # "." -> ""
8 # "./." -> ""
9 # "./xyz" -> "xyz"
10 normalizeRelativePath = rel:
11 if rel == "." || rel == "./."
12 then ""
13 else lib.strings.removePrefix "./" rel;
14 # Like normalizeRelativePath but with a trailing / when needed
15 normalizeRelativeDir = dir:
16 let p = normalizeRelativePath dir;
17 in if p == "" || p == "/"
18 then ""
19 else if lib.hasSuffix "/" p
20 then p
21 else p + "/";
22in
23 if srcStr' == null || package.detailLevel != "FullDetails"
24 then src
25 else
26 let
27 srcStr = toString srcStr';
28 dataDir = normalizeRelativeDir package.dataDir;
29 hsSourceDirs = builtins.map normalizeRelativeDir component.hsSourceDirs
30 ++ (if component.hsSourceDirs == [] then [""] else []);
31 includeDirs = builtins.map normalizeRelativeDir component.includeDirs;
32 dirsNeeded = [dataDir]
33 ++ hsSourceDirs
34 ++ includeDirs;
35 fileMatch = dir: list:
36 let
37 prefixes = builtins.map (f: dir + f) (
38 lib.lists.remove null (lib.lists.flatten (
39 builtins.map (f: builtins.match "([^*]*)[*].*" f) list)));
40 exactMatches = builtins.map (f: dataDir + f) (
41 lib.lists.remove null (lib.lists.flatten (
42 builtins.map (f: builtins.match "([^*]*)" f) list)));
43 in rPath: lib.any (d: lib.strings.hasPrefix d rPath) prefixes
44 || lib.any (d: d == rPath) exactMatches;
45 dataFileMatch = fileMatch dataDir package.dataFiles;
46 licenseMatch = fileMatch "" package.licenseFiles;
47 extraSrcMatch = fileMatch "" (
48 package.extraSrcFiles
49 ++ component.extraSrcFiles);
50 extraDocMatch = fileMatch "" package.extraDocFiles;
51 otherSourceFiles =
52 component.asmSources
53 ++ component.cmmSources
54 ++ component.cSources
55 ++ component.cxxSources
56 ++ component.jsSources;
57 in cleanSourceWith {
58 inherit src;
59 filter = path: type:
60 assert (if !lib.strings.hasPrefix (srcStr + "/") (path + "/")
61 then throw ("Unexpected path " + path + " (expected something in " + srcStr + "/)")
62 else true);
63 let
64 srcStrLen = lib.strings.stringLength srcStr;
65 rPath = lib.strings.substring (srcStrLen + 1) (lib.strings.stringLength path - srcStrLen - 1) path;
66 # This is a handy way to find out why different files are included
67 # traceReason = reason: v: if v then builtins.trace (rPath + " : " + reason) true else false;
68 traceReason = reason: v: v;
69 in
70 traceReason "directory is needed" (
71 lib.any (d: lib.strings.hasPrefix (rPath + "/") d) (
72 dirsNeeded
73 ++ package.extraSrcFiles
74 ++ component.extraSrcFiles
75 ++ package.extraDocFiles
76 ++ builtins.map (f: dataDir + f) package.dataFiles
77 ++ otherSourceFiles))
78 || traceReason "cabal package definition" (lib.strings.hasSuffix ".cabal" rPath)
79 || traceReason "hpack package defintion" (rPath == "package.yaml")
80 || traceReason "data file" (lib.strings.hasPrefix dataDir rPath
81 && dataFileMatch rPath)
82 || traceReason "haskell source dir" (lib.any (d: lib.strings.hasPrefix d rPath) hsSourceDirs)
83 || traceReason "include dir" (lib.any (d: lib.strings.hasPrefix d rPath) includeDirs)
84 || traceReason "license file" (licenseMatch rPath)
85 || traceReason "extra source file" (extraSrcMatch rPath)
86 || traceReason "extra doc file" (extraDocMatch rPath)
87 || traceReason "other source file" (lib.any (f: f == rPath) otherSourceFiles);
88 }