mirror of
https://github.com/ilyakooo0/haskell.nix.git
synced 2024-10-26 01:27:40 +03:00
Support githash package and cross package refs (#843)
* Adds support for cross package refs (with a project). Relative directory references between packages within a project should now work. * Adds `includeSiblings` to `cleanSourceWith`. When `true` it prevents the `subDir` arg from causing filtering of other directories. * Adds `keepGitDir` to `cleanGit` to allow `.git` directory to be kept (useful for components that use the `githash` package).
This commit is contained in:
parent
faaca67355
commit
64efc98852
@ -77,7 +77,27 @@ let self =
|
||||
let
|
||||
# TODO fix cabal wildcard support so hpack wildcards can be mapped to cabal wildcards
|
||||
canCleanSource = !(cabal-generator == "hpack" && !(package.cleanHpack or false));
|
||||
cleanSrc = if canCleanSource then haskellLib.cleanCabalComponent package component src else src;
|
||||
# In order to support relative references to other packages we need to use
|
||||
# the `origSrc` diretory as the root `src` for the derivation.
|
||||
# We use `rootAndSubDir` here to split the cleaned source into a `cleanSrc.root`
|
||||
# path (that respects the filtering) and a `cleanSrc.subDir` that
|
||||
# is the sub directory in that root path that contains the package.
|
||||
# `cleanSrc.subDir` is used in `prePatch` and `lib/cover.nix`.
|
||||
cleanSrc = haskellLib.rootAndSubDir (if canCleanSource
|
||||
then haskellLib.cleanCabalComponent package component "${componentId.ctype}-${componentId.cname}" src
|
||||
else
|
||||
# We can clean out the siblings though to at least avoid changes to other packages
|
||||
# from triggering a rebuild of this one.
|
||||
# Passing `subDir` but not `includeSiblings = true;` will exclude anything not
|
||||
# in the `subDir`.
|
||||
if src ? origSrc && src ? filter && src.origSubDir or "" != ""
|
||||
then haskellLib.cleanSourceWith {
|
||||
name = src.name or "source";
|
||||
src = src.origSrc;
|
||||
subDir = lib.removePrefix "/" src.origSubDir;
|
||||
inherit (src) filter;
|
||||
}
|
||||
else src);
|
||||
|
||||
nameOnly = "${package.identifier.name}-${componentId.ctype}-${componentId.cname}";
|
||||
|
||||
@ -189,7 +209,7 @@ let
|
||||
|
||||
# Attributes that are common to both the build and haddock derivations
|
||||
commonAttrs = {
|
||||
src = cleanSrc;
|
||||
src = cleanSrc.root;
|
||||
|
||||
LANG = "en_US.UTF-8"; # GHC needs the locale configured during the Haddock phase.
|
||||
LC_ALL = "en_US.UTF-8";
|
||||
@ -198,14 +218,27 @@ let
|
||||
|
||||
SETUP_HS = setup + /bin/Setup;
|
||||
|
||||
prePatch = if (cabalFile != null)
|
||||
then ''cat ${cabalFile} > ${package.identifier.name}.cabal''
|
||||
else
|
||||
# When building hpack package we use the internal nix-tools
|
||||
# (compiled with a fixed GHC version)
|
||||
lib.optionalString (cabal-generator == "hpack") ''
|
||||
${buildPackages.haskell-nix.internal-nix-tools}/bin/hpack
|
||||
'';
|
||||
prePatch =
|
||||
# If the package is in a sub directory `cd` there first.
|
||||
# In some cases the `cleanSrc.subDir` will be empty and the `.cabal`
|
||||
# file will be in the root of `src` (`cleanSrc.root`). This
|
||||
# will happen when:
|
||||
# * the .cabal file is in the projects `src.origSrc or src`
|
||||
# * the package src was overridden with a value that does not
|
||||
# include an `origSubDir`
|
||||
(lib.optionalString (cleanSrc.subDir != "") ''
|
||||
cd ${lib.removePrefix "/" cleanSrc.subDir}
|
||||
''
|
||||
) +
|
||||
(if cabalFile != null
|
||||
then ''cat ${cabalFile} > ${package.identifier.name}.cabal''
|
||||
else
|
||||
# When building hpack package we use the internal nix-tools
|
||||
# (compiled with a fixed GHC version)
|
||||
lib.optionalString (cabal-generator == "hpack") ''
|
||||
${buildPackages.haskell-nix.internal-nix-tools}/bin/hpack
|
||||
''
|
||||
);
|
||||
}
|
||||
# patches can (if they like) depend on the version and revision of the package.
|
||||
// lib.optionalAttrs (patches != []) {
|
||||
@ -244,7 +277,9 @@ let
|
||||
passthru = {
|
||||
inherit (package) identifier;
|
||||
config = component;
|
||||
inherit configFiles executableToolDepends cleanSrc exeName;
|
||||
srcSubDir = cleanSrc.subDir;
|
||||
srcSubDirPath = cleanSrc.root + cleanSrc.subDir;
|
||||
inherit configFiles executableToolDepends exeName;
|
||||
exePath = drv + "/bin/${exeName}";
|
||||
env = shellWrappers;
|
||||
profiled = self (drvArgs // { enableLibraryProfiling = true; });
|
||||
|
@ -118,7 +118,7 @@ in rec {
|
||||
checks = pkgs.recurseIntoAttrs (builtins.mapAttrs
|
||||
(_: d: haskellLib.check d)
|
||||
(lib.filterAttrs (_: d: d.config.doCheck) components.tests));
|
||||
inherit (package) identifier detailLevel isLocal;
|
||||
inherit (package) identifier detailLevel isLocal isProject;
|
||||
inherit setup cabalFile;
|
||||
isHaskell = true;
|
||||
inherit src;
|
||||
|
@ -5,10 +5,12 @@
|
||||
, prePatch ? null, postPatch ? null
|
||||
, preBuild ? component.preBuild , postBuild ? component.postBuild
|
||||
, preInstall ? component.preInstall , postInstall ? component.postInstall
|
||||
, cleanSrc ? haskellLib.cleanCabalComponent package component src
|
||||
, cleanSrc ? haskellLib.cleanCabalComponent package component "setup" src
|
||||
}:
|
||||
|
||||
let
|
||||
cleanSrc' = haskellLib.rootAndSubDir cleanSrc;
|
||||
|
||||
fullName = "${name}-setup";
|
||||
|
||||
includeGhcPackage = lib.any (p: p.identifier.name == "ghc") component.depends;
|
||||
@ -35,7 +37,7 @@ let
|
||||
drv =
|
||||
stdenv.mkDerivation ({
|
||||
name = "${ghc.targetPrefix}${fullName}";
|
||||
src = cleanSrc;
|
||||
src = cleanSrc'.root;
|
||||
buildInputs = component.libs
|
||||
++ component.frameworks
|
||||
++ builtins.concatLists component.pkgconfig;
|
||||
@ -44,7 +46,10 @@ let
|
||||
passthru = {
|
||||
inherit (package) identifier;
|
||||
config = component;
|
||||
inherit configFiles cleanSrc;
|
||||
srcSubDir = cleanSrc'.subDir;
|
||||
srcSubDirPath = cleanSrc'.root + cleanSrc'.subDir;
|
||||
cleanSrc = cleanSrc';
|
||||
inherit configFiles;
|
||||
};
|
||||
|
||||
meta = {
|
||||
@ -83,6 +88,13 @@ let
|
||||
runHook postInstall
|
||||
'';
|
||||
}
|
||||
// (lib.optionalAttrs (cleanSrc'.subDir != "") {
|
||||
prePatch =
|
||||
# If the package is in a sub directory `cd` there first
|
||||
''
|
||||
cd ${lib.removePrefix "/" cleanSrc'.subDir}
|
||||
'';
|
||||
})
|
||||
// (lib.optionalAttrs (patches != []) { patches = map (p: if builtins.isFunction p then p { inherit (package.identifier) version; inherit revision; } else p) patches; })
|
||||
// hooks
|
||||
);
|
||||
|
@ -1,6 +1,15 @@
|
||||
This file contains a summary of changes to Haskell.nix and `nix-tools`
|
||||
that will impact users.
|
||||
|
||||
## Jan 14, 2021
|
||||
* Added support for cross package refs (with a project). Relative
|
||||
directory references between packages within a project should now
|
||||
work.
|
||||
* Added `includeSiblings` to `cleanSourceWith`. When `true` it
|
||||
prevents the `subDir` arg from causing filtering of other directories.
|
||||
* Added `keepGitDir` to `cleanGit` to allow `.git` directory to be kept
|
||||
(useful for components that use the `githash` package).
|
||||
|
||||
## Nov 26, 2020
|
||||
* Renamed `otherShells` arg for `shellFor` to `inputsFrom
|
||||
|
||||
|
@ -1,89 +1,127 @@
|
||||
# Use cleanSourceWith to filter just the files needed for a particular
|
||||
# component of the package
|
||||
{ lib, cleanSourceWith }: package: component: src:
|
||||
{ lib, cleanSourceWith, canCleanSource }: package: component: componentName: src:
|
||||
let
|
||||
srcStr' = src.origSrcSubDir or src.origSrc or null;
|
||||
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"
|
||||
normalizeRelativePath = rel:
|
||||
if rel == "." || rel == "./."
|
||||
then ""
|
||||
else lib.strings.removePrefix "./" rel;
|
||||
# Like normalizeRelativePath but with a trailing / when needed
|
||||
normalizeRelativeDir = dir:
|
||||
let p = normalizeRelativePath dir;
|
||||
# "." -> ""
|
||||
# "./." -> ""
|
||||
# "./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 (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"
|
||||
if srcStr' == null || package.detailLevel != "FullDetails" || !canCleanSource src
|
||||
then src
|
||||
else
|
||||
let
|
||||
srcStr = toString srcStr';
|
||||
dataDir = normalizeRelativeDir package.dataDir;
|
||||
hsSourceDirs = builtins.map normalizeRelativeDir component.hsSourceDirs
|
||||
++ (if component.hsSourceDirs == [] then [""] else []);
|
||||
includeDirs = builtins.map normalizeRelativeDir component.includeDirs;
|
||||
dirsNeeded = [dataDir]
|
||||
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;
|
||||
dirsNeeded = builtins.map (d: combinePaths subDir d) (
|
||||
[dataDir]
|
||||
++ hsSourceDirs
|
||||
++ includeDirs;
|
||||
++ includeDirs
|
||||
++ package.licenseFiles
|
||||
++ package.extraSrcFiles
|
||||
++ component.extraSrcFiles
|
||||
++ package.extraDocFiles
|
||||
++ builtins.map (f: dataDir + f) package.dataFiles
|
||||
++ otherSourceFiles);
|
||||
fileMatch = dir: list:
|
||||
let
|
||||
prefixes = builtins.map (f: dir + f) (
|
||||
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: dataDir + f) (
|
||||
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 "" package.licenseFiles;
|
||||
extraSrcMatch = fileMatch "" (
|
||||
licenseMatch = fileMatch subDir package.licenseFiles;
|
||||
extraSrcMatch = fileMatch subDir (
|
||||
package.extraSrcFiles
|
||||
++ component.extraSrcFiles);
|
||||
extraDocMatch = fileMatch "" package.extraDocFiles;
|
||||
otherSourceFiles =
|
||||
extraDocMatch = fileMatch subDir package.extraDocFiles;
|
||||
otherSourceFiles = builtins.map (f: combinePaths subDir f) (
|
||||
component.asmSources
|
||||
++ component.cmmSources
|
||||
++ component.cSources
|
||||
++ component.cxxSources
|
||||
++ component.jsSources;
|
||||
++ component.jsSources);
|
||||
in cleanSourceWith {
|
||||
inherit 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
|
||||
++ package.licenseFiles
|
||||
++ package.extraSrcFiles
|
||||
++ component.extraSrcFiles
|
||||
++ package.extraDocFiles
|
||||
++ builtins.map (f: dataDir + f) package.dataFiles
|
||||
++ otherSourceFiles))
|
||||
|| traceReason "cabal package definition" (lib.strings.hasSuffix ".cabal" rPath)
|
||||
|| traceReason "hpack package defintion" (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);
|
||||
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)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# From https://github.com/NixOS/nix/issues/2944
|
||||
{ lib, runCommand, git, cleanSourceWith }:
|
||||
{ name ? null, src, subDir ? "" }:
|
||||
{ name ? null, src, subDir ? "", includeSiblings ? false, keepGitDir ? false }:
|
||||
|
||||
# The function call
|
||||
#
|
||||
@ -24,26 +24,6 @@ with builtins;
|
||||
# is shared among multiple invocations of gitSource:
|
||||
|
||||
let
|
||||
filter_from_list = root: files:
|
||||
let
|
||||
all_paren_dirs = p:
|
||||
if p == "." || p == "/"
|
||||
then []
|
||||
else [ p ] ++ all_paren_dirs (dirOf p);
|
||||
|
||||
whitelist_set = listToAttrs (
|
||||
concatMap (p:
|
||||
# Using `origSrcSubDir` (if present) makes it possible to cleanGit src that
|
||||
# has already been cleaned with cleanSrcWith.
|
||||
let full_path = root.origSrcSubDir or (toString root) + "/${p}"; in
|
||||
map (p': { name = p'; value = true; }) (all_paren_dirs full_path)
|
||||
) files
|
||||
);
|
||||
in
|
||||
p: t: hasAttr (toString p) whitelist_set;
|
||||
|
||||
has_prefix = prefix: s:
|
||||
prefix == builtins.substring 0 (builtins.stringLength prefix) s;
|
||||
remove_prefix = prefix: s:
|
||||
builtins.substring
|
||||
(builtins.stringLength prefix)
|
||||
@ -84,7 +64,7 @@ then
|
||||
git_content = lines (readFile (origSrcSubDir + "/.git"));
|
||||
first_line = head git_content;
|
||||
prefix = "gitdir: ";
|
||||
ok = length git_content == 1 && has_prefix prefix first_line;
|
||||
ok = length git_content == 1 && lib.hasPrefix prefix first_line;
|
||||
in
|
||||
if ok
|
||||
then /. + remove_prefix prefix first_line
|
||||
@ -148,17 +128,39 @@ then
|
||||
|
||||
whitelist = lines (readFile (whitelist_file.out));
|
||||
|
||||
filter = filter_from_list src whitelist;
|
||||
all_paren_dirs = p:
|
||||
if p == "." || p == "/"
|
||||
then []
|
||||
else [ p ] ++ all_paren_dirs (dirOf p);
|
||||
|
||||
# All the paths that we need to keep as a set (including parent dirs)
|
||||
whitelist_set = listToAttrs (
|
||||
concatMap (p:
|
||||
# Using `origSrcSubDir` (if present) makes it possible to cleanGit src that
|
||||
# has already been cleaned with cleanSrcWith.
|
||||
let full_path = src.origSrcSubDir or (toString src) + "/${p}"; in
|
||||
map (p': { name = p'; value = true; }) (all_paren_dirs full_path)
|
||||
) whitelist
|
||||
);
|
||||
|
||||
# Identify files in the `.git` dir
|
||||
isGitDirPath = path:
|
||||
path == origSrcSubDir + "/.git"
|
||||
|| lib.hasPrefix (origSrcSubDir + "/.git/") path;
|
||||
|
||||
filter = path: type:
|
||||
hasAttr (toString path) whitelist_set
|
||||
|| (keepGitDir && isGitDirPath path);
|
||||
in
|
||||
cleanSourceWith {
|
||||
caller = "cleanGit";
|
||||
inherit name src subDir filter;
|
||||
inherit name src subDir includeSiblings filter;
|
||||
}
|
||||
|
||||
else
|
||||
trace "gitSource.nix: ${origSrcSubDir} does not seem to be a git repository,\nassuming it is a clean checkout." (
|
||||
trace "haskell-nix.haskellLib.cleanGit: ${origSrcSubDir} does not seem to be a git repository,\nassuming it is a clean checkout." (
|
||||
cleanSourceWith {
|
||||
caller = "cleanGit";
|
||||
inherit name src subDir;
|
||||
inherit name src subDir includeSiblings;
|
||||
}
|
||||
)
|
||||
|
@ -54,7 +54,7 @@ let
|
||||
(l: "${l}/share/hpc/vanilla/mix/${l.identifier.name}-${l.identifier.version}")
|
||||
libs;
|
||||
|
||||
srcDirs = map (l: l.src.outPath) libs;
|
||||
srcDirs = map (l: l.srcSubDirPath) libs;
|
||||
|
||||
in pkgs.runCommand "project-coverage-report"
|
||||
({ nativeBuildInputs = [ (ghc.buildGHC or ghc) pkgs.buildPackages.zip ];
|
||||
|
@ -21,7 +21,7 @@ let
|
||||
mixDir = l: "${l}/share/hpc/vanilla/mix/${l.identifier.name}-${l.identifier.version}";
|
||||
mixDirs = map mixDir mixLibraries;
|
||||
|
||||
srcDirs = map (l: l.src.outPath) mixLibraries;
|
||||
srcDirs = map (l: l.srcSubDirPath) mixLibraries;
|
||||
|
||||
in pkgs.runCommand (name + "-coverage-report")
|
||||
({nativeBuildInputs = [ (ghc.buildGHC or ghc) pkgs.buildPackages.zip ];
|
||||
|
@ -94,7 +94,7 @@ in {
|
||||
|
||||
# if it's a project package it has a src attribute set with an origSubDir attribute.
|
||||
# project packages are a subset of localPackages
|
||||
isProjectPackage = p: p ? src && p.src ? origSubDir;
|
||||
isProjectPackage = p: p.isProject or false;
|
||||
selectProjectPackages = ps: lib.filterAttrs (n: p: p != null && isLocalPackage p && isProjectPackage p) ps;
|
||||
|
||||
# Format a componentId as it should appear as a target on the
|
||||
@ -193,7 +193,7 @@ in {
|
||||
|
||||
# Use cleanSourceWith to filter just the files needed for a particular
|
||||
# component of a package
|
||||
cleanCabalComponent = import ./clean-cabal-component.nix { inherit lib cleanSourceWith; };
|
||||
cleanCabalComponent = import ./clean-cabal-component.nix { inherit lib cleanSourceWith canCleanSource; };
|
||||
|
||||
# Clean git directory based on `git ls-files --recurse-submodules`
|
||||
cleanGit = import ./clean-git.nix {
|
||||
@ -273,4 +273,52 @@ in {
|
||||
inherit (import ./cabal-project-parser.nix {
|
||||
inherit pkgs;
|
||||
}) parseIndexState parseBlock;
|
||||
|
||||
# This function is like
|
||||
# `src + (if subDir == "" then "" else "/" + subDir)`
|
||||
# however when `includeSiblings` is set it maintains
|
||||
# `src.origSrc` if there is one and instead adds to
|
||||
# `src.origSubDir`. It uses `cleanSourceWith` when possible
|
||||
# to keep `cleanSourceWith` support in the result.
|
||||
appendSubDir = { src, subDir, includeSiblings ? false }:
|
||||
if subDir == ""
|
||||
then src
|
||||
else
|
||||
if haskellLib.canCleanSource src
|
||||
then haskellLib.cleanSourceWith {
|
||||
inherit src subDir includeSiblings;
|
||||
}
|
||||
else let name = src.name or "source" + "-" + __replaceStrings ["/"] ["-"] subDir;
|
||||
in if includeSiblings
|
||||
then rec {
|
||||
# Keep `src.origSrc` so it can be used to allow references
|
||||
# to other parts of that root.
|
||||
inherit name;
|
||||
origSrc = src.origSrc or src;
|
||||
origSubDir = src.origSubDir or "" + "/" + subDir;
|
||||
outPath = origSrc + origSubDir;
|
||||
}
|
||||
else {
|
||||
# We are not going to need other parts of `origSrc` if there
|
||||
# was one and we can ignore it
|
||||
inherit name;
|
||||
outPath = src + "/" + subDir;
|
||||
};
|
||||
|
||||
# Givin a `src` split it into a `root` path (based on `src.origSrc` if
|
||||
# present) and `subDir` (based on `src.origSubDir). The
|
||||
# `root` will still use the `filter` of `src` if there was one.
|
||||
rootAndSubDir = src: rec {
|
||||
subDir = src.origSubDir or "";
|
||||
root =
|
||||
# Use `cleanSourceWith` to make sure the `filter` is still used
|
||||
if src ? origSrc && src ? filter && subDir != ""
|
||||
then haskellLib.cleanSourceWith {
|
||||
name = src.name or "source" + "-root";
|
||||
src = src.origSrc;
|
||||
# Not passing src.origSubDir so that the result points `origSrc`
|
||||
inherit (src) filter;
|
||||
}
|
||||
else src.origSrc or src;
|
||||
};
|
||||
}
|
||||
|
@ -37,11 +37,18 @@ in project // {
|
||||
then
|
||||
pkgs.lib.lists.elemAt sourceRepos (
|
||||
pkgs.lib.strings.toInt (pkgs.lib.strings.removePrefix srcRepoPrefix subDir))
|
||||
else if haskellLib.canCleanSource srcRoot
|
||||
then haskellLib.cleanSourceWith { src = srcRoot; inherit subDir; }
|
||||
else srcRoot + (if subDir == "" then "" else "/" + subDir);
|
||||
else haskellLib.appendSubDir {
|
||||
src = srcRoot;
|
||||
inherit subDir;
|
||||
includeSiblings = true; # Filtering sibling dirs of the package dir is done in the
|
||||
# component builder so that relative paths can be used to
|
||||
# reference project directories not in the package subDir.
|
||||
};
|
||||
in oldPkg // {
|
||||
src = (pkgs.lib).mkDefault packageSrc;
|
||||
package = oldPkg.package // {
|
||||
isProject = (pkgs.lib).mkDefault true;
|
||||
};
|
||||
}) old;
|
||||
};
|
||||
}
|
||||
|
@ -132,6 +132,11 @@ in {
|
||||
default = false;
|
||||
};
|
||||
|
||||
isProject = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
ghcOptions = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
|
@ -1,4 +1,19 @@
|
||||
final: prev: {
|
||||
# gitMinimal still ships with perl (breaks for windows cross compilation)
|
||||
gitReallyMinimal = (
|
||||
final.git.override {
|
||||
perlSupport = false;
|
||||
pythonSupport = false;
|
||||
withManual = false;
|
||||
withpcre2 = false;
|
||||
}
|
||||
).overrideAttrs (
|
||||
_: {
|
||||
# installCheck is broken when perl is disabled
|
||||
doInstallCheck = false;
|
||||
}
|
||||
);
|
||||
|
||||
# This can reduce closure size of nix-tools:
|
||||
# * Eliminates dependency on python3 (70MB)
|
||||
# * Allows sharing with `fetchgit` as it also uses `gitMinimal` (50MB)
|
||||
|
@ -136,6 +136,12 @@ let
|
||||
|
||||
testSrcRoot = haskell-nix.haskellLib.cleanGit { src = ../.; subDir = "test"; };
|
||||
testSrc = subDir: haskell-nix.haskellLib.cleanSourceWith { src = testSrcRoot; inherit subDir; };
|
||||
# Use the following reproduce issues that may arise on hydra as a
|
||||
# result of building a snapshot not a git repo.
|
||||
# testSrcRoot = pkgs.copyPathToStore ./.;
|
||||
# testSrc = subDir: testSrcRoot + "/${subDir}";
|
||||
testSrcRootWithGitDir = haskell-nix.haskellLib.cleanGit { src = ../.; subDir = "test"; includeSiblings = true; keepGitDir = true; };
|
||||
testSrcWithGitDir = subDir: haskell-nix.haskellLib.cleanSourceWith { src = testSrcRootWithGitDir; inherit subDir; includeSiblings = true; };
|
||||
callTest = x: args: haskell-nix.callPackage x (args // { inherit testSrc; });
|
||||
|
||||
# Run unit tests with: nix-instantiate --eval --strict -A unit.tests
|
||||
@ -203,6 +209,9 @@ let
|
||||
} // lib.optionalAttrs (!pkgs.haskell-nix.haskellLib.isCrossHost) {
|
||||
# Haddock is not included with cross compilers currently
|
||||
sublib-docs = callTest ./sublib-docs { inherit util compiler-nix-name; };
|
||||
# githash runs git from TH code and this needs a cross compiled git exe
|
||||
# to work correctly. Cross compiling git is currently brocken.
|
||||
githash = haskell-nix.callPackage ./githash { inherit compiler-nix-name; testSrc = testSrcWithGitDir; };
|
||||
};
|
||||
|
||||
# This is the same as allTests, but filter out all the key/vaules from the
|
||||
|
67
test/githash/default.nix
Normal file
67
test/githash/default.nix
Normal file
@ -0,0 +1,67 @@
|
||||
{ stdenv, haskell-nix, recurseIntoAttrs, testSrc, compiler-nix-name, runCommand, gitMinimal, buildPackages }:
|
||||
|
||||
with stdenv.lib;
|
||||
|
||||
let
|
||||
src = testSrc "githash";
|
||||
git =
|
||||
# Using the cross compiled version here, but currently git does not
|
||||
# seem to cross compile (so this test is disabled for cross compilation in
|
||||
# the test/default.nix file).
|
||||
# Using buildPackages here is not right, but at least gets musl64 test to pass.
|
||||
if stdenv.hostPlatform != stdenv.buildPlatform
|
||||
then buildPackages.buildPackages.gitReallyMinimal
|
||||
else gitMinimal;
|
||||
project = haskell-nix.cabalProject' {
|
||||
inherit src;
|
||||
# When haskell.nix has come from the store (e.g. on hydra) we need to provide
|
||||
# a suitable mock of the cleaned source with a .git dir.
|
||||
modules = (optional (!(src ? origSrc && __pathExists (src.origSrc + "/.git"))) {
|
||||
packages.githash-test.src =
|
||||
rec {
|
||||
origSrc = runCommand "githash-test-src" { nativeBuildInputs = [ git ]; } ''
|
||||
mkdir -p $out/test/githash
|
||||
cd $out
|
||||
git init
|
||||
cp -r ${src}/* test/githash
|
||||
git add test/githash
|
||||
git -c "user.name=unknown" -c "user.email=unknown" commit -m 'Initial Commit'
|
||||
'';
|
||||
origSubDir = "/test/githash";
|
||||
origSrcSubDir = origSrc + origSubDir;
|
||||
outPath = origSrcSubDir;
|
||||
};
|
||||
}) ++ [{
|
||||
packages.githash-test.components.exes.githash-test.build-tools = mkForce [ git ];
|
||||
}];
|
||||
inherit compiler-nix-name;
|
||||
};
|
||||
|
||||
packages = project.hsPkgs;
|
||||
githash-test =
|
||||
packages.githash-test.components.exes.githash-test;
|
||||
|
||||
in recurseIntoAttrs {
|
||||
ifdInputs = {
|
||||
inherit (project) plan-nix;
|
||||
};
|
||||
|
||||
run = stdenv.mkDerivation {
|
||||
name = "run-githash-test";
|
||||
|
||||
buildCommand = ''
|
||||
exe="${githash-test}/bin/githash-test${stdenv.hostPlatform.extensions.executable}"
|
||||
echo Checking that the error message is generated and that it came from the right place:
|
||||
(${toString githash-test.config.testWrapper} $exe || true) 2>&1 \
|
||||
| grep "error, called at src/Main.hs:5:13 in main:Main"
|
||||
touch $out
|
||||
'';
|
||||
|
||||
meta.platforms = platforms.all;
|
||||
|
||||
passthru = {
|
||||
# Used for debugging with nix repl
|
||||
inherit project packages;
|
||||
};
|
||||
};
|
||||
}
|
16
test/githash/githash-test.cabal
Normal file
16
test/githash/githash-test.cabal
Normal file
@ -0,0 +1,16 @@
|
||||
cabal-version: 2.4
|
||||
name: githash-test
|
||||
version: 0.1.0.0
|
||||
license: MIT
|
||||
author: Hamish Mackenzie
|
||||
build-type: Simple
|
||||
extra-source-files: ../../.git/**/*
|
||||
|
||||
executable githash-test
|
||||
hs-source-dirs: src
|
||||
main-is: Main.hs
|
||||
build-depends: base >=4.12 && <5,
|
||||
githash
|
||||
default-language: Haskell2010
|
||||
build-tools: git
|
||||
|
15
test/githash/src/Main.hs
Normal file
15
test/githash/src/Main.hs
Normal file
@ -0,0 +1,15 @@
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
import GitHash
|
||||
|
||||
panic :: String -> a
|
||||
panic msg = error panicMsg
|
||||
where panicMsg =
|
||||
concat [ "[panic ", giBranch gi, "@", giHash gi
|
||||
, " (", giCommitDate gi, ")"
|
||||
, " (", show (giCommitCount gi), " commits in HEAD)"
|
||||
, dirty, "] ", msg ]
|
||||
dirty | giDirty gi = " (uncommitted files present)"
|
||||
| otherwise = ""
|
||||
gi = $$tGitInfoCwd
|
||||
|
||||
main = panic "oh no!"
|
Loading…
Reference in New Issue
Block a user