download stack resolver if a sha256 is provided (#748)

This change allows a resolverSha256 to be passed to stackProject.
When provided the resolver found in the stack.yaml is fetched
using this sha256 and the uri string is replaced with the
path to the fetched version.
This commit is contained in:
Hamish Mackenzie 2020-07-04 14:35:52 +12:00 committed by GitHub
parent 393678f384
commit c7736060cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 111 additions and 24 deletions

View File

@ -5,21 +5,26 @@
*
* see also `call-cabal-project-to-nix`!
*/
{ runCommand, nix-tools, pkgs, mkCacheFile, materialize }:
{ runCommand, nix-tools, pkgs, mkCacheFile, materialize, haskellLib }:
{ name ? src.name or null # optional name for better error messages
, src
, stackYaml ? null
, stackYaml ? "stack.yaml"
, ignorePackageYaml ? false
, cache ? null
, stack-sha256 ? null
, resolverSha256 ? null
, materialized ? null # Location of a materialized copy of the nix files
, checkMaterialization ? null # If true the nix files will be generated used to check plan-sha256 and material
, ... }:
let
inherit (haskellLib.fetchResolver {
inherit src stackYaml resolverSha256;
}) resolver fetchedResolver;
subDir' = src.origSubDir or "";
stackToNixArgs = builtins.concatStringsSep " " [
"--full"
"--stack-yaml=${src}/${if stackYaml == null then "stack.yaml" else stackYaml}"
"--stack-yaml=$SRC/${stackYaml}"
(if ignorePackageYaml then "--ignore-package-yaml" else "")
"-o ."
];
@ -31,7 +36,7 @@ let
} // pkgs.lib.optionalAttrs (checkMaterialization != null) {
inherit checkMaterialization;
}) (runCommand (if name == null then "stack-to-nix-pkgs" else name + "-stack-to-nix-pkgs") {
nativeBuildInputs = [ nix-tools pkgs.nix-prefetch-git pkgs.cacert ];
nativeBuildInputs = [ nix-tools pkgs.nix-prefetch-git pkgs.cacert pkgs.xorg.lndir ];
# Needed or stack-to-nix will die on unicode inputs
LOCALE_ARCHIVE = pkgs.lib.optionalString (pkgs.stdenv.hostPlatform.libc == "glibc") "${pkgs.glibcLocales}/lib/locale/locale-archive";
LANG = "en_US.UTF-8";
@ -39,15 +44,32 @@ let
preferLocalBuild = false;
} (''
mkdir -p $out${subDir'}
'' + pkgs.lib.optionalString (cache != null) ''
cp ${mkCacheFile cache}/.stack-to-nix.cache* $out${subDir'}
'' + ''
${
# If no resolver was fetched use the original stack.yaml
if fetchedResolver == null
then ''
SRC=${src}
''
else
# Replace the resolver path in the stack.yaml with the fetched version
''
SRC=$(mktemp -d)
cd $SRC
lndir -silent "${src}/." $SRC
rm ${stackYaml}
cp ${src}/${stackYaml} .
chmod +w ${stackYaml}
substituteInPlace ${stackYaml} --replace "${resolver}" "${fetchedResolver}"
''}
${pkgs.lib.optionalString (cache != null) ''
cp ${mkCacheFile cache}/.stack-to-nix.cache* $out${subDir'}
''}
(cd $out${subDir'} && stack-to-nix ${stackToNixArgs})
# We need to strip out any references to $src, as those won't
# be accessable in restricted mode.
for nixf in $(find $out -name "*.nix" -type f); do
substituteInPlace $nixf --replace "${src}" "."
substituteInPlace $nixf --replace "$SRC" "."
done
# move pkgs.nix to default.nix ensure we can just nix `import` the result.

View File

@ -261,4 +261,9 @@ in {
if lib.isAttrs versionOrArgs
then versionOrArgs
else { version = versionOrArgs; };
# Find the resolver in the stack.yaml file and fetch it if a sha256 value is provided
fetchResolver = import ./fetch-resolver.nix {
inherit (pkgs.evalPackages) pkgs;
};
}

33
lib/fetch-resolver.nix Normal file
View File

@ -0,0 +1,33 @@
# Find the resolver in the stack.yaml file and fetch it if a sha256 value is provided
{ pkgs }:
{ src
, stackYaml ? "stack.yaml"
, resolverSha256 ? null
}:
let
# Using origSrcSubDir bypasses any cleanSourceWith so that it will work when
# access to the store is restricted. If origSrc was already in the store
# you can pass the project in as a string.
rawStackYaml = builtins.readFile ((src.origSrcSubDir or src) + ("/" + stackYaml));
# Determine the resolver as it may point to another file we need
# to look at.
resolver =
let
rs = pkgs.lib.lists.concatLists (
pkgs.lib.lists.filter (l: l != null)
(builtins.map (l: builtins.match "^resolver: *(.*)" l)
(pkgs.lib.splitString "\n" rawStackYaml)));
in
pkgs.lib.lists.head (rs ++ [ null ]);
# If we found a resolver andwe have a resolverSha256 then we should download it.
fetchedResolver =
if resolver != null && resolverSha256 != null
then pkgs.fetchurl {
url = resolver;
sha256 = resolverSha256;
}
else null;
in { inherit resolver fetchedResolver; }

View File

@ -13,6 +13,7 @@
if sha256map != null
then { location, tag, ...}: sha256map."${location}"."${tag}"
else _: null
, resolverSha256 ? null
, ...
}:
let
@ -20,21 +21,9 @@ let
# we want to avoid recalculating the cache unless the stack.yaml file
# changes.
# Using origSrcSubDir bypasses any cleanSourceWith so that it will work when
# access to the store is restricted. If origSrc was already in the store
# you can pass the project in as a string.
rawStackYaml = builtins.readFile ((src.origSrcSubDir or src) + ("/" + stackYaml));
# Determine the resolver as it may point to another file we need
# to look at.
resolver =
let
rs = pkgs.lib.lists.concatLists (
pkgs.lib.lists.filter (l: l != null)
(builtins.map (l: builtins.match "^resolver: *(.*)" l)
(pkgs.lib.splitString "\n" rawStackYaml)));
in
pkgs.lib.lists.head (rs ++ [ null ]);
inherit (haskellLib.fetchResolver {
inherit src stackYaml resolverSha256;
}) resolver fetchedResolver;
# Filter just the stack yaml file and any reolver yaml file it points to.
maybeCleanedSource =
@ -58,6 +47,9 @@ let
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
''));

View File

@ -260,7 +260,7 @@ final: prev: {
callStackToNix = import ../lib/call-stack-to-nix.nix {
pkgs = final.evalPackages.pkgs;
inherit (final.evalPackages.pkgs) runCommand;
inherit (final.evalPackages.haskell-nix) nix-tools mkCacheFile materialize;
inherit (final.evalPackages.haskell-nix) nix-tools mkCacheFile materialize haskellLib;
};
# given a source location call `cabal-to-nix` (from nix-tools) on it

View File

@ -159,6 +159,7 @@ let
builder-haddock = callTest ./builder-haddock {};
stack-simple = callTest ./stack-simple {};
stack-local-resolver = callTest ./stack-local-resolver {};
stack-remote-resolver = callTest ./stack-remote-resolver {};
snapshots = callTest ./snapshots {};
shell-for = callTest ./shell-for {};
shell-for-setup-deps = callTest ./shell-for-setup-deps {};

2
test/stack-remote-resolver/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/.stack-work/
/*.cabal

View File

@ -0,0 +1,15 @@
{ project', recurseIntoAttrs, testSrc }:
let
project = project' {
src = testSrc "stack-remote-resolver";
resolverSha256 = "1rldkqqsxd8zxybrkqhc25bcxinhz212kz45jcz8jinfihc91jl7";
};
packages = project.hsPkgs;
in recurseIntoAttrs {
ifdInputs = {
inherit (project) stack-nix;
};
inherit (packages.stack-remote-resolver.components) library;
}

View File

@ -0,0 +1,7 @@
name: stack-remote-resolver
dependencies:
- base
library:
source-dirs: src

View File

@ -0,0 +1,6 @@
module Lib
( someFunc
) where
someFunc :: IO ()
someFunc = putStrLn "someFunc"

View File

@ -0,0 +1,4 @@
resolver: https://raw.githubusercontent.com/input-output-hk/haskell.nix/master/test/stack-local-resolver/snapshot.yaml
packages:
- .