From f2f36881490dcc0c4104cd403cea5d6645b28a7c Mon Sep 17 00:00:00 2001 From: Lennart Spitzner Date: Mon, 8 Jun 2020 15:49:25 +0200 Subject: [PATCH] Add nix expressions --- .gitignore | 1 + default.nix | 1 + nix/.gitignore | 2 + nix/README.md | 32 ++++++++++++++ nix/all.nix | 99 ++++++++++++++++++++++++++++++++++++++++++++ nix/ci.sh | 50 ++++++++++++++++++++++ nix/via-hackage.nix | 58 ++++++++++++++++++++++++++ nix/via-stackage.nix | 89 +++++++++++++++++++++++++++++++++++++++ shell.nix | 1 + stack-8.4.yaml | 69 ++++++++++++++++++++++++++++++ stack-8.6.yaml | 68 ++++++++++++++++++++++++++++++ stack-8.8.yaml | 65 +++++++++++++++++++++++++++++ 12 files changed, 535 insertions(+) create mode 100644 default.nix create mode 100644 nix/.gitignore create mode 100644 nix/README.md create mode 100644 nix/all.nix create mode 100755 nix/ci.sh create mode 100644 nix/via-hackage.nix create mode 100644 nix/via-stackage.nix create mode 100644 shell.nix create mode 100644 stack-8.4.yaml create mode 100644 stack-8.6.yaml create mode 100644 stack-8.8.yaml diff --git a/.gitignore b/.gitignore index 82ad53c..de26cfe 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /*.pdf dist/ dist-newstyle/ +ci-out/ .cabal-sandbox/ .stack-work/ cabal.sandbox.config diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..2143997 --- /dev/null +++ b/default.nix @@ -0,0 +1 @@ +(import ./nix/all.nix {}).default.multistate \ No newline at end of file diff --git a/nix/.gitignore b/nix/.gitignore new file mode 100644 index 0000000..7556e9b --- /dev/null +++ b/nix/.gitignore @@ -0,0 +1,2 @@ +nixpkgs.nix +local-extra-deps.nix diff --git a/nix/README.md b/nix/README.md new file mode 100644 index 0000000..2b962a0 --- /dev/null +++ b/nix/README.md @@ -0,0 +1,32 @@ + +This nix setup expects the iohk haskell-nix overlay to be available/included +when importing ``. Also, you might need a specific commit if you +want to test against all supported ghcs (8.4 - 8.10, currently). + +# Useful commands: + +~~~~.sh +# enter a shell for a specific build-plan +# (cabal-solved with ghc-8.4 in this case) +nix-shell nix/all.nix -A '"hackage-8.4".shell' +# run tests against ghcs 8.4 through 8.10, both against hackage and stackage package sets +nix/ci.sh +~~~~ + + +# Files in this directory: + +all.nix - main entrypoint into this package's nix world +via-hackage.nix - how to build this via cabal-solved package-set +via-stackage.nix - how to build via stackage-based package set +nixpkgs.nix - optional - if you want to use a custom nixpkgs channel + (the replacement needs to have haskell-nix overlay _and_ + the cabal-check feature enabled though!) +local-extra-deps.nix - optional - for defining local addition deps for + dev testing + +(plus some currently unused:) + +materialized - materializations of cabal-solved build-plans +plan.nix - manual materialization of unsolved build-plan (used with + stackage snapshot to build package set) diff --git a/nix/all.nix b/nix/all.nix new file mode 100644 index 0000000..5ef5b44 --- /dev/null +++ b/nix/all.nix @@ -0,0 +1,99 @@ +let + importOrElse = maybePath: otherwise: + if builtins.pathExists maybePath then import maybePath else otherwise; + pkgs = importOrElse ./nixpkgs.nix + ( let + haskellNix = import ( + builtins.fetchTarball + https://github.com/lspitzner/haskell.nix/archive/4ad436d66d1a553d1a36d89fcab9329f10ae36e9.tar.gz + ) { version = 2; }; + nixpkgsSrc = haskellNix.sources.nixpkgs-1909; + in + import nixpkgsSrc haskellNix.nixpkgsArgs + ); + gitignoreSrc = pkgs.fetchFromGitHub { + # owner = "hercules-ci"; + owner = "lspitzner"; # TODO switch back to the above once PR is merged + # see https://github.com/hercules-ci/gitignore.nix/pull/44 + repo = "gitignore.nix"; + rev = "97d53665298d2b31b79e5fe4b60edb12a6661547"; + sha256 = "sha256:1b3z2ikpg32zsfrhv4fb17dqavgg7d4wahslxlm37w68y7adsdav"; + }; + inherit (import gitignoreSrc { inherit (pkgs) lib; }) gitignoreSource gitignoreFilter; + cleanedSource = pkgs.lib.cleanSourceWith { + name = "butcher"; + src = ./..; + filter = p: t: + let baseName = baseNameOf (toString p); + in gitignoreFilter ./.. p t + && baseName != ".gitignore" + && baseName != "nix" + && baseName != "shell.nix" + && baseName != "default.nix"; + }; + localExtraDeps = importOrElse ./local-extra-deps.nix (_: []) {inherit pkgs;}; + args = { + inherit pkgs; + inherit cleanedSource; + pkg-def-extras = localExtraDeps; + }; + inherit (builtins) hasAttr; +in +assert pkgs.lib.assertMsg (hasAttr "haskell-nix" pkgs) "need iohk haskell-nix overlay!"; +let + versions = { + # "stack-8.0" = import ./via-stack.nix (args // { resolver = "lts-9.21"; }); + # "stack-8.2" = import ./via-stack.nix (args // { resolver = "lts-11.22"; }); + "stackage-8.4" = import ./via-stackage.nix (args // { + # resolver = "lts-12.26"; + stackFile = "stack-8.4.yaml"; + }); + "stackage-8.6" = import ./via-stackage.nix (args // { + # resolver = "lts-14.27"; + stackFile = "stack-8.6.yaml"; + }); + "stackage-8.8" = import ./via-stackage.nix (args // { + # resolver = "lts-15.12"; + stackFile = "stack-8.8.yaml"; + }); + "hackage-8.4" = import ./via-hackage.nix (args // { + ghc-ver = "ghc844"; + index-state = "2020-05-01T00:00:00Z"; + # plan-sha256 = "0s6rfanb6zxhr5zbinp7h25ahwasciwj3ambsr6zdxm1l782b3ap"; + # materialized = ./materialized/hackage-8.4; + configureArgs = "--allow-newer multistate:*"; + }); + "hackage-8.6" = import ./via-hackage.nix (args // { + ghc-ver = "ghc865"; + index-state = "2020-05-01T00:00:00Z"; + # plan-sha256 = "01m95xirrh00dvdxrpsx8flhcwlwcvgr3diwlnkw7lj5f3i7rfrl"; + # materialized = ./materialized/hackage-8.6; + configureArgs = "--allow-newer multistate:*"; + }); + "hackage-8.8" = import ./via-hackage.nix (args // { + ghc-ver = "ghc883"; + index-state = "2020-05-01T00:00:00Z"; + # plan-sha256 = "14qs7ynlf7p2qvdk8sf498y87ss5vab3ylnbpc8sacqbpv2hv4pf"; + # materialized = ./materialized/hackage-8.8; + configureArgs = "--allow-newer multistate:*"; + }); + } // (if hasAttr "ghc8101" pkgs.haskell-nix.compiler + then { + "hackage-8.10" = import ./via-hackage.nix (args // { + ghc-ver = "ghc8101"; + index-state = "2020-06-06T00:00:00Z"; + # index-sha256 = "1h1x65840jl6w2qvyq9csc7b3ivadr933glarnmydk2b23vw2i77"; + # plan-sha256 = "1s8a6cb5qgf4ky5s750rzx6aa52slp1skazh8kbx0dbfjd6df7yw"; + # materialized = ./materialized/hackage-8.10; + configureArgs = "--allow-newer multistate:* --constraint 'splitmix<0.1'"; + }); + } else builtins.trace "warn: ghc 8.10 is not avaiable, will not be tested!" {} + ); + linkFarmFromDrvs = name: drvs: + let mkEntryFromDrv = drv: { name = drv.name; path = drv; }; + in pkgs.linkFarm name (map mkEntryFromDrv drvs); +in +versions // { + inherit cleanedSource; + default = versions."stackage-8.8"; +} \ No newline at end of file diff --git a/nix/ci.sh b/nix/ci.sh new file mode 100755 index 0000000..cbf3d21 --- /dev/null +++ b/nix/ci.sh @@ -0,0 +1,50 @@ + +OUTDIR="ci-out" +SUMMARY="$OUTDIR/0-summary" +CABAL_CHECK_ATTRPATH="hackage-8.10" + +set -x + +mkdir -p "$OUTDIR" +echo "# test summary" > "$SUMMARY" + +function build-one { + local ATTRPATH=$1 + # nix-build --no-out-link nix/all.nix -A "\"$ATTRPATH\".butcher.components.library"\ + # 2> >(tee "$OUTDIR/$ATTRPATH-1-build-lib.txt" >&2) + # (($? == 0)) || { echo "$ATTRPATH: build src failed" >> "$SUMMARY"; return 1; } + # nix-build --no-out-link nix/all.nix -A "\"$ATTRPATH\".butcher.components.tests"\ + # 2> >(tee "$OUTDIR/$ATTRPATH-2-build-test.txt" >&2) + # (($? == 0)) || { echo "$ATTRPATH: build test failed" >> "$SUMMARY"; return 1; } + OUT=$(nix-build -o "$OUTDIR/$ATTRPATH-test-result.txt" nix/all.nix -A "\"$ATTRPATH\".butcher.checks.tests"\ + 2> >(tee "$OUTDIR/$ATTRPATH-build.txt" >&2)) + (($? == 0)) || { echo "$ATTRPATH: run test failed" >> "$SUMMARY"; return 1; } + echo "$ATTRPATH: $(grep examples "$OUTDIR/$ATTRPATH-test-result.txt")" >> "$SUMMARY" +} + +function cabal-check { + nix-build --no-out-link nix/all.nix -A "\"$CABAL_CHECK_ATTRPATH\".checks.cabal-check"\ + 2> >(tee "$OUTDIR/cabal-check.txt" >&2) + (($? == 0)) || { echo "cabal-check: failed" >> "$SUMMARY"; return 1; } + echo "cabal-check: success" >> "$SUMMARY" +} + +find "$OUTDIR" -name "stackage*" -delete +find "$OUTDIR" -name "hackage*" -delete +rm "$OUTDIR/cabal-check.txt" +CLEANEDSOURCE=$(nix-instantiate --eval --read-write-mode nix/all.nix -A "cleanedSource.outPath") +(($? == 0)) || exit 1 +( eval "cd $CLEANEDSOURCE; find" ) > "$OUTDIR/1-cleanedSource.txt" + +build-one "stackage-8.4" +build-one "stackage-8.6" +build-one "stackage-8.8" + +build-one "hackage-8.4" +build-one "hackage-8.6" +build-one "hackage-8.8" +build-one "hackage-8.10" + +cabal-check + +cat "$SUMMARY" diff --git a/nix/via-hackage.nix b/nix/via-hackage.nix new file mode 100644 index 0000000..f9c39af --- /dev/null +++ b/nix/via-hackage.nix @@ -0,0 +1,58 @@ +{ pkgs +, cleanedSource +, pkg-def-extras ? [] +, ghc-ver +, index-state +, index-sha256 ? null +, plan-sha256 ? null +, materialized ? null +, configureArgs ? null +}: +let + butcher-plan = pkgs.haskell-nix.importAndFilterProject (pkgs.haskell-nix.callCabalProjectToNix { + src = cleanedSource; + inherit index-state index-sha256 plan-sha256 materialized configureArgs; + # ghc = pkgs.haskell-nix.compiler.${ghc-ver}; + compiler-nix-name = ghc-ver; + }); +in rec { + inherit butcher-plan pkgs; + + hsPkgs = + let + in let pkg-set = pkgs.haskell-nix.mkCabalProjectPkgSet + { plan-pkgs = butcher-plan.pkgs; + pkg-def-extras = pkg-def-extras; + modules = [ + { ghc.package = pkgs.haskell-nix.compiler.${ghc-ver}; } + ]; + }; + in pkg-set.config.hsPkgs; + + inherit (hsPkgs) butcher; + inherit (hsPkgs.butcher) checks; + shell = hsPkgs.shellFor { + # Include only the *local* packages of your project. + packages = ps: with ps; [ + butcher + ]; + + # Builds a Hoogle documentation index of all dependencies, + # and provides a "hoogle" command to search the index. + withHoogle = false; + + # You might want some extra tools in the shell (optional). + + # Some common tools can be added with the `tools` argument + # tools = { cabal = "3.2.0.0"; }; + # See overlays/tools.nix for more details + + # Some you may need to get some other way. + buildInputs = with pkgs.haskellPackages; + [ pkgs.haskell-nix.cabal-install ghcid bash pkgs.nix ]; + + # Prevents cabal from choosing alternate plans, so that + # *all* dependencies are provided by Nix. + exactDeps = true; + }; +} diff --git a/nix/via-stackage.nix b/nix/via-stackage.nix new file mode 100644 index 0000000..172a76f --- /dev/null +++ b/nix/via-stackage.nix @@ -0,0 +1,89 @@ +{ pkgs +, cleanedSource +, stackFile +, pkg-def-extras ? [] +}: +let + # package-desc = import ./plan.nix; + # butcher-plan = { + # inherit resolver; + # extras = hackage: + # { butcher = args: package-desc args // { + # src = pkgs.haskell-nix.cleanSourceHaskell { + # src = pkgs.haskell-nix.haskellLib.cleanGit { src = ./..; name = "butcher"; }; + # name = "butcher"; + # }; + # }; + # }; + # }; + # this does not work at all, does not use local package (!) + # butcher-plan = (pkgs.haskell-nix.importAndFilterProject ( + # (pkgs.haskell-nix.callStackToNix { + # name = "butcher-plan"; + # src = ./..; + # stackYamlFile = builtins.toFile "stack.yaml" '' + # resolver: ${resolver} + # packages: + # - '.' + # extra-deps: [] + # extra-package-dbs: [] + # ''; + # ignorePackageYaml = true; + # }) + # )); + cleanedSource = pkgs.haskell-nix.cleanSourceHaskell { name = "butcher-"+stackFile; src = ./..; }; + butcher-nix = pkgs.haskell-nix.callStackToNix { + name = "butcher"; + src = cleanedSource; + stackYaml = stackFile; + }; + butcher-plan = pkgs.haskell-nix.importAndFilterProject butcher-nix; + # butcher-pkgs = { + # inherit (butcher-plan.pkgs) modules resolver; + # extras = butcher-plan.pkgs.extras ps; + # }; + generatedCache = pkgs.haskell-nix.genStackCache { + src = cleanedSource; + stackYaml = stackFile; + }; + hsPkgs = (pkgs.haskell-nix.mkStackPkgSet { + stack-pkgs = butcher-plan.pkgs; + pkg-def-extras = pkg-def-extras; + modules = pkgs.lib.singleton (pkgs.haskell-nix.mkCacheModule generatedCache); + }).config.hsPkgs; +in { + inherit butcher-plan hsPkgs pkgs; + inherit (hsPkgs) butcher; + inherit (hsPkgs.butcher) checks; + shell = hsPkgs.shellFor { + # Include only the *local* packages of your project. + packages = ps: with ps; [ + butcher + ]; + + # Builds a Hoogle documentation index of all dependencies, + # and provides a "hoogle" command to search the index. + withHoogle = false; + + # You might want some extra tools in the shell (optional). + + # Some common tools can be added with the `tools` argument + # tools = { cabal = "3.2.0.0"; }; + # See overlays/tools.nix for more details + + # Some you may need to get some other way. + buildInputs = with pkgs.haskellPackages; + [ cabal-install ghcid bash pkgs.nix ]; + + # Prevents cabal from choosing alternate plans, so that + # *all* dependencies are provided by Nix. + exactDeps = true; + }; +} +# pkgs.haskell-nix.stackProject { +# src = pkgs.haskell-nix.haskellLib.cleanGit { src = ./.; name = "butcher"; }; +# pkg-def-extras = pkg-def-extras; +# modules = [ +# { doHaddock = false; } +# ]; +# } diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..f8a2f7e --- /dev/null +++ b/shell.nix @@ -0,0 +1 @@ +(import ./nix/all.nix {}).default.shell diff --git a/stack-8.4.yaml b/stack-8.4.yaml new file mode 100644 index 0000000..7ecfbda --- /dev/null +++ b/stack-8.4.yaml @@ -0,0 +1,69 @@ +# Resolver to choose a 'specific' stackage snapshot or a compiler version. +# A snapshot resolver dictates the compiler version and the set of packages +# to be used for project dependencies. For example: +# +# resolver: lts-3.5 +# resolver: nightly-2015-09-21 +# resolver: ghc-7.10.2 +# +# The location of a snapshot can be provided as a file or url. Stack assumes +# a snapshot provided as a file might change, whereas a url resource does not. +# +# resolver: ./custom-snapshot.yaml +# resolver: https://example.com/snapshots/2018-01-01.yaml +resolver: lts-12.26 + +# User packages to be built. +# Various formats can be used as shown in the example below. +# +# packages: +# - some-directory +# - https://example.com/foo/bar/baz-0.0.2.tar.gz +# subdirs: +# - auto-update +# - wai +packages: +- . +# The following packages have been ignored due to incompatibility with the +# resolver compiler, dependency conflicts with other packages +# or unsatisfied dependencies. +#- . + +# Dependency packages to be pulled from upstream that are not in the resolver. +# These entries can reference officially published versions as well as +# forks / in-progress versions pinned to a git hash. For example: +# +# extra-deps: +# - acme-missiles-0.3 +# - git: https://github.com/commercialhaskell/stack.git +# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a +# +extra-deps: +- deque-0.4.2.3 +- extra-1.7.1 +- strict-list-0.1.5 +- barbies-2.0.1.0 + +# Override default flag values for local packages and extra-deps +# flags: {} + +# Extra package databases containing global packages +# extra-package-dbs: [] + +# Control whether we use the GHC we find on the path +# system-ghc: true +# +# Require a specific version of stack, using version ranges +# require-stack-version: -any # Default +# require-stack-version: ">=2.1" +# +# Override the architecture used by stack, especially useful on Windows +# arch: i386 +# arch: x86_64 +# +# Extra directories used by stack for building +# extra-include-dirs: [/path/to/dir] +# extra-lib-dirs: [/path/to/dir] +# +# Allow a newer minor version of GHC than the snapshot specifies +# compiler-check: newer-minor diff --git a/stack-8.6.yaml b/stack-8.6.yaml new file mode 100644 index 0000000..4f9b75e --- /dev/null +++ b/stack-8.6.yaml @@ -0,0 +1,68 @@ +# Resolver to choose a 'specific' stackage snapshot or a compiler version. +# A snapshot resolver dictates the compiler version and the set of packages +# to be used for project dependencies. For example: +# +# resolver: lts-3.5 +# resolver: nightly-2015-09-21 +# resolver: ghc-7.10.2 +# +# The location of a snapshot can be provided as a file or url. Stack assumes +# a snapshot provided as a file might change, whereas a url resource does not. +# +# resolver: ./custom-snapshot.yaml +# resolver: https://example.com/snapshots/2018-01-01.yaml +resolver: lts-14.4 + +# User packages to be built. +# Various formats can be used as shown in the example below. +# +# packages: +# - some-directory +# - https://example.com/foo/bar/baz-0.0.2.tar.gz +# subdirs: +# - auto-update +# - wai +packages: +- . +# Dependency packages to be pulled from upstream that are not in the resolver. +# These entries can reference officially published versions as well as +# forks / in-progress versions pinned to a git hash. For example: +# +# extra-deps: +# - acme-missiles-0.3 +# - git: https://github.com/commercialhaskell/stack.git +# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a +# +# extra-deps: [] + +extra-deps: +- deque-0.4.2.3@sha256:7cc8ddfc77df351ff9c16e838ccdb4a89f055c80a3111e27eba8d90e8edde7d0,1853 +- strict-list-0.1.4@sha256:0fa869e2c21b710b7133e8628169f120fe6299342628edd3d5087ded299bc941,1631 +- semigroupoids-5.3.3@sha256:260b62cb8539bb988e7f551f10a45ef1c81421c0d79010e9bde9321bad4982a7,7363 +- base-orphans-0.8.1@sha256:defd0057b5db93257528d89b5b01a0fee9738e878c121c686948ac4aa5dded63,2927 +- hashable-1.3.0.0 +- unordered-containers-0.2.10.0 + +# Override default flag values for local packages and extra-deps +# flags: {} + +# Extra package databases containing global packages +# extra-package-dbs: [] + +# Control whether we use the GHC we find on the path +# system-ghc: true +# +# Require a specific version of stack, using version ranges +# require-stack-version: -any # Default +# require-stack-version: ">=2.1" +# +# Override the architecture used by stack, especially useful on Windows +# arch: i386 +# arch: x86_64 +# +# Extra directories used by stack for building +# extra-include-dirs: [/path/to/dir] +# extra-lib-dirs: [/path/to/dir] +# +# Allow a newer minor version of GHC than the snapshot specifies +# compiler-check: newer-minor diff --git a/stack-8.8.yaml b/stack-8.8.yaml new file mode 100644 index 0000000..8f497d2 --- /dev/null +++ b/stack-8.8.yaml @@ -0,0 +1,65 @@ +# Resolver to choose a 'specific' stackage snapshot or a compiler version. +# A snapshot resolver dictates the compiler version and the set of packages +# to be used for project dependencies. For example: +# +# resolver: lts-3.5 +# resolver: nightly-2015-09-21 +# resolver: ghc-7.10.2 +# +# The location of a snapshot can be provided as a file or url. Stack assumes +# a snapshot provided as a file might change, whereas a url resource does not. +# +# resolver: ./custom-snapshot.yaml +# resolver: https://example.com/snapshots/2018-01-01.yaml +resolver: lts-15.12 + +# User packages to be built. +# Various formats can be used as shown in the example below. +# +# packages: +# - some-directory +# - https://example.com/foo/bar/baz-0.0.2.tar.gz +# subdirs: +# - auto-update +# - wai +packages: +- . +# The following packages have been ignored due to incompatibility with the +# resolver compiler, dependency conflicts with other packages +# or unsatisfied dependencies. +#- . + +# Dependency packages to be pulled from upstream that are not in the resolver. +# These entries can reference officially published versions as well as +# forks / in-progress versions pinned to a git hash. For example: +# +# extra-deps: +# - acme-missiles-0.3 +# - git: https://github.com/commercialhaskell/stack.git +# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a +# +# extra-deps: [] + +# Override default flag values for local packages and extra-deps +# flags: {} + +# Extra package databases containing global packages +# extra-package-dbs: [] + +# Control whether we use the GHC we find on the path +# system-ghc: true +# +# Require a specific version of stack, using version ranges +# require-stack-version: -any # Default +# require-stack-version: ">=2.1" +# +# Override the architecture used by stack, especially useful on Windows +# arch: i386 +# arch: x86_64 +# +# Extra directories used by stack for building +# extra-include-dirs: [/path/to/dir] +# extra-lib-dirs: [/path/to/dir] +# +# Allow a newer minor version of GHC than the snapshot specifies +# compiler-check: newer-minor