@@ -1,89 +1,127 @@
1# Use cleanSourceWith to filter just the files needed for a particular
1# Use cleanSourceWith to filter just the files needed for a particular
2# component of the package
2# component of the package
3−{ lib, cleanSourceWith }: package: component: src:
3+{ lib, cleanSourceWith, canCleanSource }: package: component: componentName: src:
5− srcStr' = src.origSrcSubDir or src.origSrc or null;
5+ srcStr' = src.origSrc or null;
6+ subDir = if src.origSubDir or "" == ""
8+ else lib.removePrefix "/" src.origSubDir + "/";
9+ # Remove a directory for each .. part of a path.
10+ removeDotDots = parts: lib.reverseList (
11+ builtins.foldl' (a: b:
14+ else builtins.concatLists [ [b] a ]) [] parts);
6 # Transform
15 # Transform
7− # "." -> ""
16+ # "." -> ""
21+ # "abc/../xyz" -> "xyz"
22+ # "abc/./xyz" -> "abc/xyz"
8− # "./." -> ""
23+ # "abc/./../xyz" -> "xyz"
9− # "./xyz" -> "xyz"
24+ # "abc/.././xyz" -> "xyz"
10− normalizeRelativePath = rel:
26+ normalizeRelativePath = path:
11− if rel == "." || rel == "./."
27+ let
28+ # Split the path into component parts and remove the empty ones and single dots.
29+ nonEmptyParts = lib.filter (x: x != "" && x != ".") (lib.splitString "/" path);
30+ in lib.concatStringsSep "/" (removeDotDots nonEmptyParts)
31+ # Keep the trailing slash if there was one.
32+ + (if lib.hasSuffix "/" path then "/" else "");
33+ isAbsolutePath = path: lib.hasPrefix "/" path;
34+ isRelativePath = path: !(isAbsolutePath path);
35+ normalizePath = path:
36+ (if isAbsolutePath path
13− else lib.strings.removePrefix "./" rel;
38+ else ""
39+ ) + normalizeRelativePath path;
40+ combinePaths = a: b: if isAbsolutePath b
42+ else normalizePath (a + "/" + b);
14− # Like normalizeRelativePath but with a trailing / when needed
43+ # Like normalizePath but with a trailing / when needed
15− normalizeRelativeDir = dir:
44+ normalizeDir = dir:
16− let p = normalizeRelativePath dir;
45+ let p = normalizePath dir;
17 in if p == "" || p == "/"
46 in if p == "" || p == "/"
19 else if lib.hasSuffix "/" p
48 else if lib.hasSuffix "/" p
21 else p + "/";
50 else p + "/";
23− if srcStr' == null || package.detailLevel != "FullDetails"
52+ if srcStr' == null || package.detailLevel != "FullDetails" || !canCleanSource src
27 srcStr = toString srcStr';
56 srcStr = toString srcStr';
28− dataDir = normalizeRelativeDir package.dataDir;
57+ dataDir = combinePaths subDir package.dataDir;
29− hsSourceDirs = builtins.map normalizeRelativeDir component.hsSourceDirs
58+ hsSourceDirs = builtins.map (d: combinePaths subDir d) component.hsSourceDirs
30− ++ (if component.hsSourceDirs == [] then [""] else []);
59+ ++ (if component.hsSourceDirs == [] then [subDir] else []);
31− includeDirs = builtins.map normalizeRelativeDir component.includeDirs;
60+ includeDirs = builtins.map (d: combinePaths subDir d) component.includeDirs;
61+ dirsNeeded = builtins.map (d: combinePaths subDir d) (
32− dirsNeeded = [dataDir]
62+ [dataDir]
33 ++ hsSourceDirs
63 ++ hsSourceDirs
34− ++ includeDirs;
64+ ++ includeDirs
65+ ++ package.licenseFiles
66+ ++ package.extraSrcFiles
67+ ++ component.extraSrcFiles
68+ ++ package.extraDocFiles
69+ ++ builtins.map (f: dataDir + f) package.dataFiles
70+ ++ otherSourceFiles);
35 fileMatch = dir: list:
71 fileMatch = dir: list:
37− prefixes = builtins.map (f: dir + f) (
73+ prefixes = builtins.map (f: combinePaths dir f) (
38 lib.lists.remove null (lib.lists.flatten (
74 lib.lists.remove null (lib.lists.flatten (
39 builtins.map (f: builtins.match "([^*]*)[*].*" f) list)));
75 builtins.map (f: builtins.match "([^*]*)[*].*" f) list)));
40− exactMatches = builtins.map (f: dataDir + f) (
76+ exactMatches = builtins.map (f: combinePaths dir f) (
41 lib.lists.remove null (lib.lists.flatten (
77 lib.lists.remove null (lib.lists.flatten (
42 builtins.map (f: builtins.match "([^*]*)" f) list)));
78 builtins.map (f: builtins.match "([^*]*)" f) list)));
43 in rPath: lib.any (d: lib.strings.hasPrefix d rPath) prefixes
79 in rPath: lib.any (d: lib.strings.hasPrefix d rPath) prefixes
44 || lib.any (d: d == rPath) exactMatches;
80 || lib.any (d: d == rPath) exactMatches;
45 dataFileMatch = fileMatch dataDir package.dataFiles;
81 dataFileMatch = fileMatch dataDir package.dataFiles;
46− licenseMatch = fileMatch "" package.licenseFiles;
82+ licenseMatch = fileMatch subDir package.licenseFiles;
47− extraSrcMatch = fileMatch "" (
83+ extraSrcMatch = fileMatch subDir (
48 package.extraSrcFiles
84 package.extraSrcFiles
49 ++ component.extraSrcFiles);
85 ++ component.extraSrcFiles);
50− extraDocMatch = fileMatch "" package.extraDocFiles;
86+ extraDocMatch = fileMatch subDir package.extraDocFiles;
51− otherSourceFiles =
87+ otherSourceFiles = builtins.map (f: combinePaths subDir f) (
52 component.asmSources
88 component.asmSources
53 ++ component.cmmSources
89 ++ component.cmmSources
54 ++ component.cSources
90 ++ component.cSources
55 ++ component.cxxSources
91 ++ component.cxxSources
56− ++ component.jsSources;
92+ ++ component.jsSources);
57 in cleanSourceWith {
93 in cleanSourceWith {
58− inherit src;
94+ name = src.name or "source" + "-${componentName}";
95+ subDir = lib.removePrefix "/" (src.origSubDir or "");
96+ includeSiblings = true;
97+ src = cleanSourceWith {
98+ src = src.origSrc or src;
59− filter = path: type:
99+ filter = path: type:
100+ (!(src ? filter) || src.filter path type) && (
60− assert (if !lib.strings.hasPrefix (srcStr + "/") (path + "/")
101+ assert (if !lib.strings.hasPrefix (srcStr + "/") (path + "/")
61− then throw ("Unexpected path " + path + " (expected something in " + srcStr + "/)")
102+ then throw ("Unexpected path " + path + " (expected something in " + srcStr + "/)")
62− else true);
103+ else true);
64− srcStrLen = lib.strings.stringLength srcStr;
105+ srcStrLen = lib.strings.stringLength srcStr;
65− rPath = lib.strings.substring (srcStrLen + 1) (lib.strings.stringLength path - srcStrLen - 1) path;
106+ 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
107+ # 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;
108+ # traceReason = reason: v: if v then builtins.trace (rPath + " : " + reason) true else false;
68− traceReason = reason: v: v;
109+ traceReason = reason: v: v;
70− traceReason "directory is needed" (
111+ traceReason "directory is needed" (
71− lib.any (d: lib.strings.hasPrefix (rPath + "/") d) (
112+ lib.any (d: lib.strings.hasPrefix (rPath + "/") d) dirsNeeded)
73− ++ package.licenseFiles
74− ++ package.extraSrcFiles
75− ++ component.extraSrcFiles
76− ++ package.extraDocFiles
77− ++ builtins.map (f: dataDir + f) package.dataFiles
78− ++ otherSourceFiles))
79− || traceReason "cabal package definition" (lib.strings.hasSuffix ".cabal" rPath)
113+ || traceReason "cabal package definition" (lib.strings.hasPrefix subDir rPath
114+ && lib.strings.hasSuffix ".cabal" rPath)
80− || traceReason "hpack package defintion" (rPath == "package.yaml")
115+ || traceReason "hpack package defintion" (lib.strings.hasPrefix subDir rPath
116+ && rPath == "package.yaml")
81− || traceReason "data file" (lib.strings.hasPrefix dataDir rPath
117+ || traceReason "data file" (lib.strings.hasPrefix dataDir rPath
82− && dataFileMatch rPath)
118+ && dataFileMatch rPath)
83− || traceReason "haskell source dir" (lib.any (d: lib.strings.hasPrefix d rPath) hsSourceDirs)
119+ || traceReason "haskell source dir" (lib.any (d: lib.strings.hasPrefix d rPath) hsSourceDirs)
84− || traceReason "include dir" (lib.any (d: lib.strings.hasPrefix d rPath) includeDirs)
120+ || traceReason "include dir" (lib.any (d: lib.strings.hasPrefix d rPath) includeDirs)
85− || traceReason "license file" (licenseMatch rPath)
121+ || traceReason "license file" (licenseMatch rPath)
86− || traceReason "extra source file" (extraSrcMatch rPath)
122+ || traceReason "extra source file" (extraSrcMatch rPath)
87− || traceReason "extra doc file" (extraDocMatch rPath)
123+ || traceReason "extra doc file" (extraDocMatch rPath)
88− || traceReason "other source file" (lib.any (f: f == rPath) otherSourceFiles);
124+ || traceReason "other source file" (lib.any (f: f == rPath) otherSourceFiles)