Files
haskell.nix/lib/stack-cache-generator.nix
T
ismaelbouyaf 4729034750 Add "branch" information for builtins.fetchGit (#1019)
The builtins.fetchGit used by haskell.nix clones only the subset of a
repository corresponding to HEAD. So if we have a workflow that has a
branch "development" as HEAD, but the stack.yaml only targets commits
from "master", then it will be unable to fetch any commit.

Fixes #592
2021-02-03 13:16:02 +13:00

114 lines
4.2 KiB
Nix

# Generate cache entries for dependencies of package defined in `src`
{ pkgs, haskellLib }:
{ src
, stackYaml ? "stack.yaml"
, sha256map ? null
# An alternative to adding `# nix-sha256:` comments into the
# stack.yaml file:
# sha256map =
# { "https://github.com/jgm/pandoc-citeproc"."0.17"
# = "0dxx8cp2xndpw3jwiawch2dkrkp15mil7pyx7dvd810pwc22pm2q"; };
, lookupSha256 ?
if sha256map != null
then { location, tag, ...}: sha256map."${location}"."${tag}"
else _: null
, branchMap ? null
# A way to specify in which branch a git commit can
# be found
, lookupBranch ?
if branchMap != null
then { location, tag, ...}: branchMap."${location}"."${tag}" or null
else _: null
, resolverSha256 ? null
, nix-tools ? pkgs.haskell-nix.internal-nix-tools # When building stack projects we use the internal nix-tools (compiled with a fixed GHC version)
, ...
}:
let
# We only care about the stackYaml file. If src is a local directory
# we want to avoid recalculating the cache unless the stack.yaml file
# changes.
inherit (haskellLib.fetchResolver {
inherit src stackYaml resolverSha256;
}) resolver fetchedResolver;
# Filter just the stack yaml file and any resolver yaml file it points to.
maybeCleanedSource =
if haskellLib.canCleanSource src
then haskellLib.cleanSourceWith {
inherit src;
filter = path: type:
let
origSrc = if src ? _isLibCleanSourceWith then src.origSrc else src;
origSubDir = if src ? _isLibCleanSourceWithEx then src.origSubDir else "";
relPath = pkgs.lib.removePrefix (toString origSrc + origSubDir + "/") path;
# checks if path1 is a parent directory for path2
isParent = path1: path2: pkgs.lib.hasPrefix "${path1}/" path2;
in
(relPath == stackYaml)
|| (resolver != null && (relPath == resolver || isParent relPath resolver))
;
}
else src;
# All repos served via ssh or git protocols are usually private
private = url: pkgs.lib.substring 0 4 url != "http";
repos = builtins.fromJSON (builtins.readFile (pkgs.runCommand "stack-repos" {
buildInputs = [ nix-tools ];
} ''
TMP=$(mktemp -d)
cd $TMP
cp -r "${maybeCleanedSource}/." $TMP
chmod -R +w $TMP
substituteInPlace ${stackYaml} --replace "# nix-sha256:" "nix-sha256:"
${pkgs.lib.optionalString (fetchedResolver != null) ''
substituteInPlace ${stackYaml} --replace "${resolver}" "${fetchedResolver}"
''}
stack-repos --stack-yaml ${stackYaml}
cp repos.json $out
''));
cabalName = path: builtins.readFile (pkgs.runCommand "cabal-name" {
buildInputs = [ nix-tools ];
} ''
cabal-name ${path} > $out
'');
hashPath = path:
builtins.readFile (pkgs.runCommand "hash-path" { preferLocalBuild = true; }
"echo -n $(${pkgs.nix}/bin/nix-hash --type sha256 --base32 ${path}) > $out");
in with pkgs.lib;
concatMap (dep:
let
is-private = private dep.url;
sha256 = if dep.sha256 != null
then dep.sha256
else lookupSha256 {
location = dep.url;
tag = dep.rev;
};
branch = lookupBranch {
location = dep.url;
tag = dep.rev;
};
pkgsrc =
if !is-private && sha256 != null
then pkgs.fetchgit {
inherit (dep) url rev;
inherit sha256;
}
else builtins.fetchGit ({
inherit (dep) url rev;
} // pkgs.lib.optionalAttrs (branch != null) { ref = branch; });
in map (subdir: {
name = cabalName "${pkgsrc}/${subdir}";
inherit (dep) url rev;
inherit is-private;
sha256 = if !is-private then hashPath pkgsrc else null;
} // (optionalAttrs (subdir != "") { inherit subdir; }))
(dep.subdirs or [ "" ])) repos