mirror of
https://github.com/simplex-chat/haskell.nix.git
synced 2026-06-03 09:17:32 +00:00
a385241331
In recent nix, builtins.path works in restricted eval mode. Therefore canCleanSource is not required anymore. follow up on #1403 * add comment on hydra overlay * throw error on outdated nix version
139 lines
5.8 KiB
Nix
139 lines
5.8 KiB
Nix
# Use cleanSourceWith to filter just the files needed for a particular
|
|
# component of the package
|
|
{ lib, cleanSourceWith }: package: component: componentName: src:
|
|
let
|
|
srcStr' = src.origSrc or null;
|
|
subDir = if src.origSubDir or "" == ""
|
|
then ""
|
|
else lib.removePrefix "/" src.origSubDir + "/";
|
|
# Remove a directory for each .. part of a path.
|
|
removeDotDots = parts: lib.reverseList (
|
|
builtins.foldl' (a: b:
|
|
if b == ".."
|
|
then builtins.tail a
|
|
else builtins.concatLists [ [b] a ]) [] parts);
|
|
# Transform
|
|
# "." -> ""
|
|
# "./." -> ""
|
|
# "./xyz" -> "xyz"
|
|
# "../abc" -> ERROR
|
|
# "abc/.." -> ""
|
|
# "abc/../xyz" -> "xyz"
|
|
# "abc/./xyz" -> "abc/xyz"
|
|
# "abc/./../xyz" -> "xyz"
|
|
# "abc/.././xyz" -> "xyz"
|
|
# "abc/" -> "abc/"
|
|
normalizeRelativePath = path:
|
|
let
|
|
# Split the path into component parts and remove the empty ones and single dots.
|
|
nonEmptyParts = lib.filter (x: x != "" && x != ".") (lib.splitString "/" path);
|
|
in lib.concatStringsSep "/" (removeDotDots nonEmptyParts)
|
|
# Keep the trailing slash if there was one.
|
|
+ (if lib.hasSuffix "/" path then "/" else "");
|
|
isAbsolutePath = path: lib.hasPrefix "/" path;
|
|
isRelativePath = path: !(isAbsolutePath path);
|
|
normalizePath = path:
|
|
(if isAbsolutePath path
|
|
then "/"
|
|
else ""
|
|
) + normalizeRelativePath path;
|
|
combinePaths = a: b:
|
|
if isAbsolutePath b
|
|
then b
|
|
else normalizePath (
|
|
if a == ""
|
|
then b
|
|
else if b == ""
|
|
then a
|
|
else a + "/" + b
|
|
);
|
|
# Like normalizePath but with a trailing / when needed
|
|
normalizeDir = dir:
|
|
let p = normalizePath dir;
|
|
in if p == "" || p == "/"
|
|
then ""
|
|
else if lib.hasSuffix "/" p
|
|
then p
|
|
else p + "/";
|
|
in
|
|
if srcStr' == null || package.detailLevel != "FullDetails"
|
|
then src
|
|
else
|
|
let
|
|
srcStr = toString srcStr';
|
|
dataDir = combinePaths subDir package.dataDir;
|
|
hsSourceDirs = builtins.map (d: combinePaths subDir d) component.hsSourceDirs
|
|
++ (if component.hsSourceDirs == [] then [subDir] else []);
|
|
includeDirs = builtins.map (d: combinePaths subDir d) component.includeDirs;
|
|
# paths that will be needed (used to check if a parent dir should be included)
|
|
dirsNeeded =
|
|
# These already include subDir
|
|
[dataDir]
|
|
++ hsSourceDirs
|
|
++ includeDirs
|
|
++ builtins.map (f: combinePaths dataDir f) package.dataFiles
|
|
++ otherSourceFiles
|
|
++ builtins.map (d: combinePaths subDir d) (
|
|
# These need the subDir added
|
|
package.licenseFiles
|
|
++ package.extraSrcFiles
|
|
++ component.extraSrcFiles
|
|
++ package.extraDocFiles);
|
|
fileMatch = dir: list:
|
|
let
|
|
prefixes = builtins.map (f: combinePaths dir f) (
|
|
lib.lists.remove null (lib.lists.flatten (
|
|
builtins.map (f: builtins.match "([^*]*)[*].*" f) list)));
|
|
exactMatches = builtins.map (f: combinePaths dir f) (
|
|
lib.lists.remove null (lib.lists.flatten (
|
|
builtins.map (f: builtins.match "([^*]*)" f) list)));
|
|
in rPath: lib.any (d: lib.strings.hasPrefix d rPath) prefixes
|
|
|| lib.any (d: d == rPath) exactMatches;
|
|
dataFileMatch = fileMatch dataDir package.dataFiles;
|
|
licenseMatch = fileMatch subDir package.licenseFiles;
|
|
extraSrcMatch = fileMatch subDir (
|
|
package.extraSrcFiles
|
|
++ component.extraSrcFiles);
|
|
extraDocMatch = fileMatch subDir package.extraDocFiles;
|
|
otherSourceFiles = builtins.map (f: combinePaths subDir f) (
|
|
component.asmSources
|
|
++ component.cmmSources
|
|
++ component.cSources
|
|
++ component.cxxSources
|
|
++ component.jsSources);
|
|
in cleanSourceWith {
|
|
name = src.name or "source" + "-${componentName}";
|
|
subDir = lib.removePrefix "/" (src.origSubDir or "");
|
|
includeSiblings = true;
|
|
src = cleanSourceWith {
|
|
src = src.origSrc or src;
|
|
filter = path: type:
|
|
(!(src ? filter) || src.filter path type) && (
|
|
assert (if !lib.strings.hasPrefix (srcStr + "/") (path + "/")
|
|
then throw ("Unexpected path " + path + " (expected something in " + srcStr + "/)")
|
|
else true);
|
|
let
|
|
srcStrLen = lib.strings.stringLength srcStr;
|
|
rPath = lib.strings.substring (srcStrLen + 1) (lib.strings.stringLength path - srcStrLen - 1) path;
|
|
# This is a handy way to find out why different files are included
|
|
# traceReason = reason: v: if v then builtins.trace (rPath + " : " + reason) true else false;
|
|
traceReason = reason: v: v;
|
|
in
|
|
traceReason "directory is needed" (
|
|
lib.any (d: lib.strings.hasPrefix (rPath + "/") d) dirsNeeded)
|
|
|| traceReason "cabal package definition" (lib.strings.hasPrefix subDir rPath
|
|
&& lib.strings.hasSuffix ".cabal" rPath)
|
|
|| traceReason "hpack package defintion" (lib.strings.hasPrefix subDir rPath
|
|
&& rPath == "package.yaml")
|
|
|| traceReason "data file" (lib.strings.hasPrefix dataDir rPath
|
|
&& dataFileMatch rPath)
|
|
|| traceReason "haskell source dir" (lib.any (d: lib.strings.hasPrefix d rPath) hsSourceDirs)
|
|
|| traceReason "include dir" (lib.any (d: lib.strings.hasPrefix d rPath) includeDirs)
|
|
|| traceReason "license file" (licenseMatch rPath)
|
|
|| traceReason "extra source file" (extraSrcMatch rPath)
|
|
|| traceReason "extra doc file" (extraDocMatch rPath)
|
|
|| traceReason "other source file" (lib.any (f: f == rPath) otherSourceFiles)
|
|
);
|
|
};
|
|
}
|