Improve support for external Hackage repositories (#1370)

* Improve support for external Hackage repositories

This change builds #535. `repository` blocks in `cabal.project` parsed and `cabal` is used to automatically downloaded them.  Then `hackage-to-nix` is used to produce the nix required.

To make it work with restricted eval (on hydra for instance) we need to include a sha256 like this:

```
repository ghcjs-overlay
  url: https://input-output-hk.github.io/hackage-overlay-ghcjs
  secure: True
  root-keys:
  key-threshold: 0
  --sha256: sha256-EPlLYPmIGtxeahlOspRzwJv+60N5mqrNC2BY4jZKceE=
```

To find the correct `sha256` put in an invalid one and attempt a build.
This commit is contained in:
Hamish Mackenzie 2022-02-18 00:42:11 +13:00 committed by GitHub
parent 6b891ba383
commit 2576a948b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 406 additions and 94 deletions

View File

@ -1,6 +1,13 @@
This file contains a summary of changes to Haskell.nix and `nix-tools`
that will impact users.
## Feb 16, 2022
* Removed lookupSha256 argument from project functions.
Pass a `sha256map` instead.
* Added better support for `repository` in `cabal.project`. These
blocks should now work without the need for passing `extra-hackages` and
`extra-hackage-tarballs`.
## Aug 6, 2021
* Included dependencies of haskell.nix that were tracked in `nix/sources.json`
as flake inputs (`flake.lock` replaces `nix/sources.json`).

View File

@ -74,17 +74,21 @@ let
# --shar256: 003lm3pm0000hbfmii7xcdd9v20000flxf7gdl2pyxia7p014i8z
# will be trated like a field and returned here
# (used in call-cabal-project-to-nix.nix to create a fixed-output derivation)
extractRepoData = cabalProjectFileName: lookupSha256: repo: {
extractSourceRepoPackageData = cabalProjectFileName: sha256map: repo: {
url = repo.location;
ref = repo.tag;
sha256 = repo."--sha256" or (lookupSha256 repo);
sha256 = repo."--sha256" or (
if sha256map != null
then sha256map."${repo.location}"."${repo.tag}"
else null);
subdirs = if repo ? subdir
then pkgs.lib.filter (x: x != "") (pkgs.lib.splitString " " repo.subdir)
else ["."];
};
# Parse a source-repository-package and return data of `type: git` repositories
parseBlock = cabalProjectFileName: lookupSha256: block:
# See tests/unit.nix for examples of input and output.
parseSourceRepositoryPackageBlock = cabalProjectFileName: sha256map: block:
let
x = span (pkgs.lib.strings.hasPrefix " ") (pkgs.lib.splitString "\n" block);
attrs = parseBlockLines x.fst;
@ -95,10 +99,106 @@ let
otherText = "\nsource-repository-package\n" + block;
}
else {
sourceRepo = extractRepoData cabalProjectFileName lookupSha256 attrs;
sourceRepo = extractSourceRepoPackageData cabalProjectFileName sha256map attrs;
otherText = pkgs.lib.strings.concatStringsSep "\n" x.snd;
};
parseSourceRepositoryPackages = cabalProjectFileName: sha256map: source-repo-override: projectFile:
let
blocks = pkgs.lib.splitString "\nsource-repository-package\n" ("\n" + projectFile);
initialText = pkgs.lib.lists.take 1 blocks;
repoBlocks = builtins.map (parseSourceRepositoryPackageBlock cabalProjectFileName sha256map) (pkgs.lib.lists.drop 1 blocks);
overrideSourceRepo = sourceRepo: (source-repo-override.${sourceRepo.url} or (pkgs.lib.id)) sourceRepo;
in {
sourceRepos = pkgs.lib.lists.map (block: overrideSourceRepo block.sourceRepo) repoBlocks;
otherText = pkgs.lib.strings.concatStringsSep "\n" (
initialText
++ (builtins.map (x: x.otherText) repoBlocks));
};
# Parse and replace repository
# This works in a similar way to the `source-repository-package` but we are
# able to simply replace the `repository` blocks with local `file:/nix/store` ones.
# This works because `cabal configure` does not include any of the `/nix/sore/`
# paths in the `plan.json` (so materialized plan-nix will still work as expeced).
# See tests/unit.nix for examples of input and output.
parseRepositoryBlock = cabalProjectFileName: sha256map: cabal-install: nix-tools: block:
let
lines = pkgs.lib.splitString "\n" block;
# The first line will contain the repository name.
x = span (pkgs.lib.strings.hasPrefix " ") (__tail lines);
attrs = parseBlockLines x.fst;
sha256 = attrs."--sha256" or (
if sha256map != null
then sha256map."${attrs.url}"
else null);
in rec {
# This is `some-name` from the `repository some-name` line in the `cabal.project` file.
name = __head lines;
# The $HOME dir with `.cabal` sub directory after running `cabal new-update` to download the repository
home =
pkgs.evalPackages.runCommandLocal name ({
nativeBuildInputs = [ cabal-install pkgs.evalPackages.curl nix-tools ];
LOCALE_ARCHIVE = pkgs.lib.optionalString (pkgs.evalPackages.stdenv.buildPlatform.libc == "glibc") "${pkgs.evalPackages.glibcLocales}/lib/locale/locale-archive";
LANG = "en_US.UTF-8";
} // pkgs.lib.optionalAttrs (sha256 != null) {
outputHashMode = "recursive";
outputHashAlgo = "sha256";
outputHash = sha256;
}) ''
mkdir -p $out/.cabal
cat <<EOF > $out/.cabal/config
repository ${name}
url: ${attrs.url}
${pkgs.lib.optionalString (attrs ? secure) "secure: ${attrs.secure}"}
${pkgs.lib.optionalString (attrs ? root-keys) "root-keys: ${attrs.root-keys}"}
${pkgs.lib.optionalString (attrs ? key-threshold) "key-threshold: ${attrs.key-threshold}"}
EOF
export SSL_CERT_FILE=${pkgs.evalPackages.cacert}/etc/ssl/certs/ca-bundle.crt
mkdir -p $out/.cabal/packages/${name}
HOME=$out cabal new-update ${name}
'';
# Output of hackage-to-nix
hackage = import (
pkgs.evalPackages.runCommandLocal ("hackage-to-nix-" + name) {
nativeBuildInputs = [ cabal-install pkgs.evalPackages.curl nix-tools ];
LOCALE_ARCHIVE = pkgs.lib.optionalString (pkgs.evalPackages.stdenv.buildPlatform.libc == "glibc") "${pkgs.evalPackages.glibcLocales}/lib/locale/locale-archive";
LANG = "en_US.UTF-8";
} ''
mkdir -p $out
hackage-to-nix $out ${home}/.cabal/packages/${name}/01-index.tar ${attrs.url}
'');
# Tarball info in the same format as `extra-hackage-tarballs` passed in to cabalProject
tarball = {
${name} = home + "/.cabal/packages/${name}/01-index.tar.gz";
};
# Replacement `repository` block using `file:` uri and the remaining text (text that was not part of the attribute block).
updatedText = ''
repository ${name}
url: file:${home + "/.cabal/packages/${name}"}
secure: True
root-keys:
key-threshold: 0
'' + pkgs.lib.strings.concatStringsSep "\n" x.snd;
};
parseRepositories = cabalProjectFileName: sha256map: cabal-install: nix-tools: projectFile:
let
# This will leave the name of repository in the first line of each block
blocks = pkgs.lib.splitString "\nrepository " ("\n" + projectFile);
initialText = pkgs.lib.lists.take 1 blocks;
repoBlocks = builtins.map (parseRepositoryBlock cabalProjectFileName sha256map cabal-install nix-tools) (pkgs.lib.lists.drop 1 blocks);
in {
extra-hackages = pkgs.lib.lists.map (block: block.hackage) repoBlocks;
tarballs = pkgs.lib.lists.foldl' (x: block: x // block.tarball) {} repoBlocks;
updatedText = pkgs.lib.strings.concatStringsSep "\n" (
initialText
++ (builtins.map (x: x.updatedText) repoBlocks));
};
in {
inherit parseIndexState parseBlockLines parseBlock;
inherit parseIndexState parseSourceRepositoryPackages parseRepositories
# These are only exposed for tests
parseSourceRepositoryPackageBlock parseRepositoryBlock;
}

View File

@ -30,13 +30,14 @@ in
# An alternative to adding `--sha256` comments into the
# cabal.project file:
# sha256map =
# { "https://github.com/jgm/pandoc-citeproc"."0.17"
# = "0dxx8cp2xndpw3jwiawch2dkrkp15mil7pyx7dvd810pwc22pm2q"; };
, lookupSha256 ?
if sha256map != null
then { location, tag, ...}: sha256map."${location}"."${tag}"
else _: null
, extra-hackage-tarballs ? []
# { # For a `source-repository-package` use the `location` and `tag` as the key
# "https://github.com/jgm/pandoc-citeproc"."0.17"
# = "0dxx8cp2xndpw3jwiawch2dkrkp15mil7pyx7dvd810pwc22pm2q";
# # For a `repository` use the `url` as the key
# "https://raw.githubusercontent.com/input-output-hk/hackage-overlay-ghcjs/bfc363b9f879c360e0a0460ec0c18ec87222ec32"
# = "sha256-g9xGgJqYmiczjxjQ5JOiK5KUUps+9+nlNGI/0SpSOpg=";
# };
, extra-hackage-tarballs ? {}
, source-repo-override ? {} # Cabal seems to behave incoherently when
# two source-repository-package entries
# provide the same packages, making it
@ -192,7 +193,7 @@ let
replaceSourceRepos = projectFile:
let
fetchRepo = fetchgit: repoData:
fetchPackageRepo = fetchgit: repoData:
let
fetched =
if repoData.sha256 != null
@ -200,7 +201,7 @@ let
else
let drv = builtins.fetchGit { inherit (repoData) url ref; };
in __trace "WARNING: No sha256 found for source-repository-package ${repoData.url} ${repoData.ref} download may fail in restricted mode (hydra)"
(__trace "Consider adding `--sha256: ${hashPath drv}` to the ${cabalProjectFileName} file or passing in a lookupSha256 argument"
(__trace "Consider adding `--sha256: ${hashPath drv}` to the ${cabalProjectFileName} file or passing in a sha256map argument"
drv);
in {
# Download the source-repository-package commit and add it to a minimal git
@ -221,14 +222,13 @@ let
tag = "minimal";
};
blocks = pkgs.lib.splitString "\nsource-repository-package\n" ("\n" + projectFile);
initialText = pkgs.lib.lists.take 1 blocks;
repoBlocks = builtins.map (pkgs.haskell-nix.haskellLib.parseBlock cabalProjectFileName lookupSha256) (pkgs.lib.lists.drop 1 blocks);
overrideSourceRepo = sourceRepo: (source-repo-override.${sourceRepo.url} or (pkgs.lib.id)) sourceRepo;
sourceRepoData = pkgs.lib.lists.map (x: overrideSourceRepo x.sourceRepo) repoBlocks;
otherText = pkgs.evalPackages.writeText "cabal.project" (pkgs.lib.strings.concatStringsSep "\n" (
initialText
++ (builtins.map (x: x.otherText) repoBlocks)));
# Parse the `source-repository-package` blocks
sourceRepoPackageResult = pkgs.haskell-nix.haskellLib.parseSourceRepositoryPackages
cabalProjectFileName sha256map source-repo-override projectFile;
# Parse the `repository` blocks
repoResult = pkgs.haskell-nix.haskellLib.parseRepositories
cabalProjectFileName sha256map cabal-install nix-tools sourceRepoPackageResult.otherText;
# we need the repository content twice:
# * at eval time (below to build the fixed project file)
@ -239,12 +239,13 @@ let
# on the target system would use, so that the derivation is unaffected
# and, say, a linux release build job can identify the derivation
# as built by a darwin builder, and fetch it from a cache
sourceReposEval = builtins.map (fetchRepo pkgs.evalPackages.fetchgit) sourceRepoData;
sourceReposBuild = builtins.map (x: (fetchRepo pkgs.fetchgit x).fetched) sourceRepoData;
sourceReposEval = builtins.map (fetchPackageRepo pkgs.evalPackages.fetchgit) sourceRepoPackageResult.sourceRepos;
sourceReposBuild = builtins.map (x: (fetchPackageRepo pkgs.fetchgit x).fetched) sourceRepoPackageResult.sourceRepos;
in {
sourceRepos = sourceReposBuild;
inherit (repoResult) tarballs extra-hackages;
makeFixedProjectFile = ''
cp -f ${otherText} ./cabal.project
cp -f ${pkgs.evalPackages.writeText "cabal.project" repoResult.updatedText} ./cabal.project
'' +
pkgs.lib.optionalString (builtins.length sourceReposEval != 0) (''
chmod +w -R ./cabal.project
@ -279,7 +280,7 @@ let
fixedProject =
if rawCabalProject == null
then { sourceRepos = []; makeFixedProjectFile = ""; replaceLocations = ""; }
then { sourceRepos = []; tarballs = {}; extra-hackages = []; makeFixedProjectFile = ""; replaceLocations = ""; }
else replaceSourceRepos rawCabalProject;
# The use of the actual GHC can cause significant problems:
@ -524,7 +525,8 @@ let
# some packages that will be excluded by `index-state-found`
# which is used by cabal (cached-index-state >= index-state-found).
dotCabal {
inherit cabal-install nix-tools extra-hackage-tarballs;
inherit cabal-install nix-tools;
extra-hackage-tarballs = fixedProject.tarballs // extra-hackage-tarballs;
index-state = cached-index-state;
sha256 = index-sha256-found;
}
@ -610,5 +612,5 @@ in {
projectNix = plan-nix;
index-state = index-state-found;
inherit src;
inherit (fixedProject) sourceRepos;
inherit (fixedProject) sourceRepos extra-hackages;
}

View File

@ -275,7 +275,7 @@ in {
inherit (import ./cabal-project-parser.nix {
inherit pkgs;
}) parseIndexState parseBlock;
}) parseIndexState parseSourceRepositoryPackages parseRepositories parseSourceRepositoryPackageBlock parseRepositoryBlock;
cabalToNixpkgsLicense = import ./spdx/cabal.nix pkgs;

View File

@ -9,10 +9,6 @@
# 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
@ -85,12 +81,10 @@ 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;
};
sha256 =
if dep.sha256 != null then dep.sha256
else if sha256map != null then { location, tag, ...}: sha256map."${dep.url}"."${dep.rev}"
else null;
branch = lookupBranch {
location = dep.url;
tag = dep.rev;

View File

@ -17,13 +17,13 @@
pkgs:
{ name, index }:
pkgs.evalPackages.runCommandLocal "hackage-repo-${name}" { nativeBuildInputs = [ pkgs.evalPackages.nix ]; } ''
pkgs.evalPackages.runCommandLocal "hackage-repo-${name}" {} ''
mkdir -p $out
export expires="4000-01-01T00:00:00Z"
ln -sf ${index} $out/01-index.tar.gz
export index_md5=$(nix-hash --flat --type md5 ${index})
export index_sha256=$(nix-hash --flat --type sha256 ${index})
export index_md5=$(md5sum ${index} | awk '{ print $1 }')
export index_sha256=$(sha256sum ${index} | awk '{ print $1 }')
${
# When possible check the hash we calculate here against the `outputHash`
# of the index derivation (when the `extra-hackages` feature is used the index
@ -37,18 +37,18 @@ ${
export index_length=$(stat --printf="%s" ${index})
substituteAll ${./root.json} $out/root.json
export root_md5=$(nix-hash --flat --type md5 $out/root.json)
export root_sha256=$(nix-hash --flat --type sha256 $out/root.json)
export root_md5=$(md5sum $out/root.json | awk '{ print $1 }')
export root_sha256=$(sha256sum $out/root.json | awk '{ print $1 }')
export root_length=$(stat --printf="%s" $out/root.json)
substituteAll ${./mirrors.json} $out/mirrors.json
export mirrors_md5=$(nix-hash --flat --type md5 $out/mirrors.json)
export mirrors_sha256=$(nix-hash --flat --type sha256 $out/mirrors.json)
export mirrors_md5=$(md5sum $out/mirrors.json | awk '{ print $1 }')
export mirrors_sha256=$(sha256sum $out/mirrors.json | awk '{ print $1 }')
export mirrors_length=$(stat --printf="%s" $out/mirrors.json)
substituteAll ${./snapshot.json} $out/snapshot.json
export snapshot_md5=$(nix-hash --flat --type md5 $out/snapshot.json)
export snapshot_sha256=$(nix-hash --flat --type sha256 $out/snapshot.json)
export snapshot_md5=$(md5sum $out/snapshot.json | awk '{ print $1 }')
export snapshot_sha256=$(sha256sum $out/snapshot.json | awk '{ print $1 }')
export snapshot_length=$(stat --printf="%s" $out/snapshot.json)
substituteAll ${./timestamp.json} $out/timestamp.json

View File

@ -105,15 +105,9 @@ in {
= "0dxx8cp2xndpw3jwiawch2dkrkp15mil7pyx7dvd810pwc22pm2q"; };
'';
};
lookupSha256 = mkOption {
type = nullOr unspecified;
default = if config.sha256map != null
then { location, tag, ...}: config.sha256map.${location}.${tag}
else _: null;
};
extra-hackage-tarballs = mkOption {
type = nullOr (listOf unspecified);
default = [];
type = nullOr attrs;
default = {};
};
source-repo-override = mkOption {
type = attrsOf (functionTo attrs);

View File

@ -72,12 +72,6 @@ with types;
= "0dxx8cp2xndpw3jwiawch2dkrkp15mil7pyx7dvd810pwc22pm2q"; };
'';
};
lookupSha256 = mkOption {
type = nullOr unspecified;
default = if config.sha256map != null
then { location, tag, ...}: config.sha256map.${location}.${tag}
else _: null;
};
branchMap = mkOption {
type = nullOr unspecified;
default = null;

View File

@ -43,10 +43,9 @@ in { haskell-nix = prev.haskell-nix // {
pandoc = {
# Function that returns a sha256 string by looking up the location
# and tag in a nested attrset
lookupSha256 = { location, tag, ... }:
sha256map =
{ "https://github.com/jgm/pandoc-citeproc"."0.17"
= "0dxx8cp2xndpw3jwiawch2dkrkp15mil7pyx7dvd810pwc22pm2q"; }
."${location}"."${tag}";
= "0dxx8cp2xndpw3jwiawch2dkrkp15mil7pyx7dvd810pwc22pm2q"; };
};
# See https://github.com/input-output-hk/haskell.nix/issues/948

View File

@ -189,8 +189,7 @@ final: prev: {
hackageTarball = { index-state, sha256, nix-tools ? final.haskell-nix.nix-tools, ... }:
assert sha256 != null;
let at = builtins.replaceStrings [":"] [""] index-state; in
{ name = "hackage.haskell.org-at-${at}";
index = final.evalPackages.fetchurl {
{ "hackage.haskell.org-at-${at}" = final.evalPackages.fetchurl {
name = "01-index.tar.gz-at-${at}";
url = "https://hackage.haskell.org/01-index.tar.gz";
downloadToTemp = true;
@ -204,10 +203,10 @@ final: prev: {
# Creates Cabal local repository from { name, index } set.
mkLocalHackageRepo = import ../mk-local-hackage-repo final;
dotCabal = { index-state, sha256, cabal-install, extra-hackage-tarballs ? [], ... }@args:
dotCabal = { index-state, sha256, cabal-install, extra-hackage-tarballs ? {}, ... }@args:
let
allTarballs = [ (hackageTarball args) ] ++ extra-hackage-tarballs;
allNames = final.lib.concatMapStringsSep "-" (tarball: tarball.name) allTarballs;
allTarballs = hackageTarball args // extra-hackage-tarballs;
allNames = final.lib.concatStringsSep "-" (builtins.attrNames allTarballs);
# Main Hackage index-state is embedded in its name and thus will propagate to
# dotCabalName anyway.
dotCabalName = "dot-cabal-" + allNames;
@ -217,10 +216,10 @@ final: prev: {
mkdir -p $out/.cabal
cat <<EOF > $out/.cabal/config
${final.lib.concatStrings (
map (tarball:
final.lib.mapAttrsToList (name: index:
''
repository ${tarball.name}
url: file:${mkLocalHackageRepo tarball}
repository ${name}
url: file:${mkLocalHackageRepo { inherit name index; }}
secure: True
root-keys:
key-threshold: 0
@ -231,13 +230,13 @@ final: prev: {
# All repositories must be mkdir'ed before calling new-update on any repo,
# otherwise it fails.
${final.lib.concatStrings (map ({ name, ... }: ''
${final.lib.concatStrings (map (name: ''
mkdir -p $out/.cabal/packages/${name}
'') allTarballs)}
'') (builtins.attrNames allTarballs))}
${final.lib.concatStrings (map ({ name, ... }: ''
${final.lib.concatStrings (map (name: ''
HOME=$out cabal new-update ${name}
'') allTarballs)}
'') (builtins.attrNames allTarballs))}
'';
# Some of features of haskell.nix rely on using a hackage index
@ -515,7 +514,7 @@ final: prev: {
++ final.lib.optional (args.ghcOverride != null || args.ghc != null)
{ ghc.package = if args.ghcOverride != null then args.ghcOverride else args.ghc; }
++ [ { compiler.nix-name = final.lib.mkForce args.compiler-nix-name; } ];
extra-hackages = args.extra-hackages or [];
extra-hackages = args.extra-hackages or [] ++ callProjectResults.extra-hackages;
};
project = addProjectAndPackageAttrs rec {

View File

@ -152,7 +152,7 @@ let
# An empty list means success.
unitTests =
let
tests = haskell-nix.callPackage ./unit.nix {};
tests = haskell-nix.callPackage ./unit.nix { inherit compiler-nix-name; };
testsFailedEcho = lib.concatMapStringsSep "\n" (t: "echo ${t.name} failed") tests;
testsFinalLine = if builtins.length tests == 0 then "\ntouch $out" else "\nexit 1";
testsScript = testsFailedEcho + testsFinalLine;
@ -186,11 +186,12 @@ let
stack-source-repo = callTest ./stack-source-repo { inherit compiler-nix-name; };
cabal-doctests = callTest ./cabal-doctests { inherit util compiler-nix-name; };
extra-hackage = callTest ./extra-hackage { inherit compiler-nix-name; };
ghcjs-overlay = callTest ./ghcjs-overlay { inherit compiler-nix-name; };
hls-cabal = callTest ./haskell-language-server/cabal.nix { inherit compiler-nix-name; };
hls-stack = callTest ./haskell-language-server/stack.nix { inherit compiler-nix-name; };
cabal-hpack = callTest ./cabal-hpack { inherit util compiler-nix-name; };
index-state = callTest ./index-state { inherit compiler-nix-name; };
lookup-sha256 = callTest ./lookup-sha256 { inherit compiler-nix-name; };
sha256map = callTest ./sha256map { inherit compiler-nix-name; };
# fully-static = callTest ./fully-static { inherit (pkgs) buildPackages; };
shell-for = callTest ./shell-for { inherit compiler-nix-name; };
cabal-22 = callTest ./cabal-22 { inherit util compiler-nix-name; };

View File

@ -6,9 +6,8 @@ let
hackage = import ./hackage;
tarball = {
name = "extra-hackage-demo";
index = ./01-index.tar.gz;
tarballs = {
extra-hackage-demo = ./01-index.tar.gz;
};
demo-src = ./external-package-demo-0.1.0.0.tar.gz;
@ -18,7 +17,7 @@ let
src = testSrc "extra-hackage/external-package-user";
extra-hackages = [ hackage ];
extra-hackage-tarballs = [ tarball ];
extra-hackage-tarballs = tarballs;
modules = [
# To prevent nix-build from trying to download it from the

View File

@ -1,4 +1,8 @@
packages: *.cabal
repository local
url: http://127.0.0.1:7777
-- Including `repository` here now actually causes haskell.nix to try
-- to download the repository. Luckily this test still works with this
-- commented out.
-- See the ghcjs-overlays test for an example of how to use `repository` blocks.
-- repository local
-- url: http://127.0.0.1:7777

View File

@ -0,0 +1,5 @@
# Revision history for external-package-user
## 0.1.0.0 -- YYYY-mm-dd
* First version. Released on an unsuspecting world.

View File

@ -0,0 +1,8 @@
module Main where
import qualified MyLib (someFunc)
main :: IO ()
main = do
putStrLn "Hello, Haskell!"
MyLib.someFunc

View File

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

View File

@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain

View File

@ -0,0 +1,9 @@
packages: *.cabal
repository ghcjs-overlay
url: https://raw.githubusercontent.com/input-output-hk/hackage-overlay-ghcjs/bfc363b9f879c360e0a0460ec0c18ec87222ec32
secure: True
root-keys:
key-threshold: 0
--sha256: sha256-g9xGgJqYmiczjxjQ5JOiK5KUUps+9+nlNGI/0SpSOpg=

View File

@ -0,0 +1,52 @@
{ stdenv, lib, cabalProject', haskellLib, recurseIntoAttrs, testSrc, compiler-nix-name }:
with lib;
let
project = cabalProject' {
src = testSrc "ghcjs-overlay";
inherit compiler-nix-name;
# Alternative to the --sha256 comment in cabal.project
# sha256map = {
# "https://raw.githubusercontent.com/input-output-hk/hackage-overlay-ghcjs/bfc363b9f879c360e0a0460ec0c18ec87222ec32" =
# "sha256-g9xGgJqYmiczjxjQ5JOiK5KUUps+9+nlNGI/0SpSOpg=";
# };
};
packages = project.hsPkgs;
in recurseIntoAttrs {
ifdInputs = {
inherit (project) plan-nix;
};
run = stdenv.mkDerivation {
name = "ghcjs-overlay-test";
buildCommand = ''
exe="${packages.ghcjs-overlay-test.components.exes.ghcjs-overlay-test.exePath}"
size=$(command stat --format '%s' "$exe")
printf "size of executable $exe is $size. \n" >& 2
# fixme: run on target platform when cross-compiled
printf "checking whether executable runs... " >& 2
cat ${haskellLib.check packages.ghcjs-overlay-test.components.exes.ghcjs-overlay-test}/test-stdout
'' + (if stdenv.hostPlatform.isMusl
then ''
printf "checking that executable is statically linked... " >& 2
(ldd $exe 2>&1 || true) | grep -i "not a"
''
else
# Skip this on aarch as we do not have an `ldd` tool
optionalString (!stdenv.hostPlatform.isAarch32 && !stdenv.hostPlatform.isAarch64) (''
printf "checking that executable is dynamically linked to system libraries... " >& 2
'' + optionalString stdenv.isLinux ''
ldd $exe | grep libpthread
'' + optionalString stdenv.isDarwin ''
otool -L $exe |grep .dylib
'')) + ''
touch $out
'';
meta.platforms = platforms.all;
passthru = {
inherit project;
};
};
}

View File

@ -0,0 +1,21 @@
cabal-version: 2.4
name: ghcjs-overlay-test
version: 0.1.0.0
synopsis: User package
description: Uses ghcjs-overlay to get patched double-conversion
license: BSD-3-Clause
author: Hamish Mackenzie
maintainer: Hamish.K.Mackenzie@gmail.com
extra-source-files: CHANGELOG.md
library
exposed-modules: MyLib
build-depends: base < 5,
double-conversion ==2.0.2.0
default-language: Haskell2010
executable ghcjs-overlay-test
main-is: Main.hs
other-modules: MyLib
build-depends: base, ghcjs-overlay-test
default-language: Haskell2010

View File

@ -11,10 +11,9 @@
version = "2.9.2.1";
# Function that returns a sha256 string by looking up the location
# and tag in a nested attrset
lookupSha256 = { location, tag, ... }:
sha256map =
{ "https://github.com/jgm/pandoc-citeproc"."0.17"
= "0dxx8cp2xndpw3jwiawch2dkrkp15mil7pyx7dvd810pwc22pm2q"; }
."${location}"."${tag}";
= "0dxx8cp2xndpw3jwiawch2dkrkp15mil7pyx7dvd810pwc22pm2q"; };
cabalProjectLocal = ''
allow-newer: *:base
'';

View File

@ -1,4 +1,4 @@
{ pkgs, lib, haskellLib }:
{ pkgs, lib, haskellLib, compiler-nix-name }:
let
emptyConfig = {
@ -58,7 +58,7 @@ lib.runTests {
};
testParseBlock1 = {
expr = __toJSON (haskellLib.parseBlock "cabal.project" (_: null) ''
expr = __toJSON (haskellLib.parseSourceRepositoryPackageBlock "cabal.project" {} ''
type: git
location: https://github.com/input-output-hk/haskell.nix.git
tag: 487eea1c249537d34c27f6143dff2b9d5586c657
@ -72,7 +72,7 @@ lib.runTests {
};
testParseBlock2 = {
expr = __toJSON (haskellLib.parseBlock "cabal.project" (_: null) ''
expr = __toJSON (haskellLib.parseSourceRepositoryPackageBlock "cabal.project" {} ''
type: git
location: https://github.com/input-output-hk/haskell.nix.git
tag: 487eea1c249537d34c27f6143dff2b9d5586c657
@ -87,7 +87,7 @@ lib.runTests {
};
testParseBlock3 = {
expr = __toJSON (haskellLib.parseBlock "cabal.project" (_: null) ''
expr = __toJSON (haskellLib.parseSourceRepositoryPackageBlock "cabal.project" {} ''
type: git
location: https://github.com/input-output-hk/haskell.nix.git
tag: 487eea1c249537d34c27f6143dff2b9d5586c657
@ -102,7 +102,7 @@ lib.runTests {
};
testParseBlock4 = {
expr = __toJSON (haskellLib.parseBlock "cabal.project" (_: null) ''
expr = __toJSON (haskellLib.parseSourceRepositoryPackageBlock "cabal.project" {} ''
type: git
location: https://github.com/input-output-hk/haskell.nix.git
tag: 487eea1c249537d34c27f6143dff2b9d5586c657
@ -117,4 +117,123 @@ lib.runTests {
sourceRepo = testRepoData // { subdirs = ["dir1" "dir2"]; };
};
};
testParseRepositoryBlock = {
expr = __toJSON (haskellLib.parseRepositoryBlock "cabal.project" {}
pkgs.evalPackages.haskell-nix.cabal-install.${compiler-nix-name}
pkgs.evalPackages.haskell-nix.nix-tools.${compiler-nix-name} ''
ghcjs-overlay
url: https://raw.githubusercontent.com/input-output-hk/hackage-overlay-ghcjs/bfc363b9f879c360e0a0460ec0c18ec87222ec32
secure: True
root-keys:
key-threshold: 0
--sha256: sha256-g9xGgJqYmiczjxjQ5JOiK5KUUps+9+nlNGI/0SpSOpg=
-- end of block
'');
expected = __toJSON {
name = "ghcjs-overlay";
updatedText = ''
repository ghcjs-overlay
url: file:/nix/store/0lx8536b53bqssqzzbyzi22j117a7q2g-ghcjs-overlay/.cabal/packages/ghcjs-overlay
secure: True
root-keys:
key-threshold: 0
-- end of block
'';
home = "/nix/store/0lx8536b53bqssqzzbyzi22j117a7q2g-ghcjs-overlay";
tarball = {
ghcjs-overlay = "/nix/store/0lx8536b53bqssqzzbyzi22j117a7q2g-ghcjs-overlay/.cabal/packages/ghcjs-overlay/01-index.tar.gz";
};
hackage = {
Cabal = {
"3.2.1.0" = {
revisions = {
default = "/nix/store/3ndxx3k43gmjkfl1qn1x39g15hz5amad-Cabal-3.2.1.0-r0-2b5309e942658e3b16e6938115867538e70a647d98e3dc967f2be20d6b886e61.nix";
r0 = "/nix/store/3ndxx3k43gmjkfl1qn1x39g15hz5amad-Cabal-3.2.1.0-r0-2b5309e942658e3b16e6938115867538e70a647d98e3dc967f2be20d6b886e61.nix";
};
sha256 = "826970f742b63d751f6fe3be7f862b7b1e419ddfafef3014c01de54f12874a4a";
};
};
basement = {
"0.0.12"= {
revisions = {
default = "/nix/store/3h1xwcij240kj243f23siw3p30hdbnrj-basement-0.0.12-r0-600669787199915545f99754496f13f955203b94dbb31de50093362c03367bb7.nix";
r0 = "/nix/store/3h1xwcij240kj243f23siw3p30hdbnrj-basement-0.0.12-r0-600669787199915545f99754496f13f955203b94dbb31de50093362c03367bb7.nix";
};
sha256 = "cf8f96fd92438739a516881abb7e14747118e82a12634d44acc83173fb87f535";
};
};
clock = {
"0.8.2" = {
revisions = {
default = "/nix/store/mdsf1fgbpi4m1yvsg5z8z4hk5w7i63x7-clock-0.8.2-r0-2a8441d9f531bb51bb1806e56e9e9a43e5f0214faea4f31219c15120128ca43a.nix";
r0 = "/nix/store/mdsf1fgbpi4m1yvsg5z8z4hk5w7i63x7-clock-0.8.2-r0-2a8441d9f531bb51bb1806e56e9e9a43e5f0214faea4f31219c15120128ca43a.nix";
};
sha256 = "57715a01df74568c638f1138b53642094de420bafd519e9f53ec7fe92876121e";
};
};
cryptonite = {
"0.29" = {
revisions = {
default = "/nix/store/i84rvw53j9b6p53dalg6xq85blrkrk01-cryptonite-0.29-r0-231db2acdaefc978865af9b72a6e65c4ebc70238174a7ad9076d68900f3d866d.nix";
r0 = "/nix/store/i84rvw53j9b6p53dalg6xq85blrkrk01-cryptonite-0.29-r0-231db2acdaefc978865af9b72a6e65c4ebc70238174a7ad9076d68900f3d866d.nix";
};
sha256 = "f104836bdaeed5243ff7e9fc0757d7255778f0af22976eef2b7789e7e1094283";
};
};
double-conversion = {
"2.0.2.0" = {
revisions = {
default = "/nix/store/cb41xbmf6abcq30sj2a1b00qim8nyhqx-double-conversion-2.0.2.0-r0-698f94e66b6263a1049b56ede47aa48e224c764f345c3130265742513443595b.nix";
r0 = "/nix/store/cb41xbmf6abcq30sj2a1b00qim8nyhqx-double-conversion-2.0.2.0-r0-698f94e66b6263a1049b56ede47aa48e224c764f345c3130265742513443595b.nix";
};
sha256 = "67c83bf4619624ef6b950578664cbcd3bc12eaed0d7a387997db5e0ba29fb140";
};
};
foundation = {
"0.0.26.1" = {
revisions = {
default = "/nix/store/5vw12rxa3as8b82kz1arddwzs45fzj6q-foundation-0.0.26.1-r0-9a2f63a33dc6b3c1425c4755522b8e619d04fdfcfef72e358155b965b28745a8.nix";
r0 = "/nix/store/5vw12rxa3as8b82kz1arddwzs45fzj6q-foundation-0.0.26.1-r0-9a2f63a33dc6b3c1425c4755522b8e619d04fdfcfef72e358155b965b28745a8.nix";
};
sha256 = "3c588f6bcf875762ac18b03b17a7ee3c0c60c8e2c884c0192269b0a97e89d526";
};
};
network = {
"3.1.2.1" = {
revisions = {
default = "/nix/store/sfc02hqr02pa3rwhha1skvlkiwmgvsf7-network-3.1.2.1-r0-ed4b1bb733613df5a2ebecd5533d08f20bacb0dc59ed207fd4b4670fe718713f.nix";
r0 = "/nix/store/sfc02hqr02pa3rwhha1skvlkiwmgvsf7-network-3.1.2.1-r0-ed4b1bb733613df5a2ebecd5533d08f20bacb0dc59ed207fd4b4670fe718713f.nix";
};
sha256 = "21869fd942cb9996ba26ba9418cdd44ac869f81caba08e5a2b2cdfe792ae4518";
};
"3.1.2.5" = {
revisions = {
default = "/nix/store/rrh5f3hb8g5bwgd6y7lwfky3nrgsg5b2-network-3.1.2.5-r0-433a5e076aaa8eb3e4158abae78fb409c6bd754e9af99bc2e87583d2bcd8404a.nix";
r0 = "/nix/store/rrh5f3hb8g5bwgd6y7lwfky3nrgsg5b2-network-3.1.2.5-r0-433a5e076aaa8eb3e4158abae78fb409c6bd754e9af99bc2e87583d2bcd8404a.nix";
};
sha256 = "ee914e9b43bfb0f415777eb0473236803b14a35d48f6172079260c92c6ceb335";
};
};
terminal-size = {
"0.3.2.1" = {
revisions = {
default = "/nix/store/k9gk020ygp6j94sa3xv46fkgrc8jl5zn-terminal-size-0.3.2.1-r0-7b2d8e0475a46961d07ddfb91dee618de70eff55d9ba0402ebeac1f9dcf9b18b.nix";
r0 = "/nix/store/k9gk020ygp6j94sa3xv46fkgrc8jl5zn-terminal-size-0.3.2.1-r0-7b2d8e0475a46961d07ddfb91dee618de70eff55d9ba0402ebeac1f9dcf9b18b.nix";
};
sha256 = "8e4fbfea182f3bf5769744196ca88bb2cb1c80caa617debe34336f90db27131e";
};
};
unix-compat = {
"0.5.3" = {
revisions = {
default = "/nix/store/mc1vh6wzg0vp1c1srxrqmpv9fsqay6dw-unix-compat-0.5.3-r0-9c6d68f9afb5baa6be55e8415dd401835ce0d4dfc2090f1c169fcd61c152ebac.nix";
r0 = "/nix/store/mc1vh6wzg0vp1c1srxrqmpv9fsqay6dw-unix-compat-0.5.3-r0-9c6d68f9afb5baa6be55e8415dd401835ce0d4dfc2090f1c169fcd61c152ebac.nix";
};
sha256 = "2fe56781422d5caf47dcbbe82c998bd33f429f8c7093483fad36cd2d31dbdceb";
};
};
};
};
};
}