diff options
Diffstat (limited to 'nixpkgs/pkgs/test/haskell')
15 files changed, 406 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/test/haskell/cabalSdist/default.nix b/nixpkgs/pkgs/test/haskell/cabalSdist/default.nix new file mode 100644 index 000000000000..1031e51e4f14 --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/cabalSdist/default.nix @@ -0,0 +1,28 @@ +{ lib, haskellPackages, runCommand }: + +let + localRaw = haskellPackages.callPackage ./local/generated.nix {}; +in +lib.recurseIntoAttrs rec { + + helloFromCabalSdist = haskellPackages.buildFromCabalSdist haskellPackages.hello; + + # A more complicated example with a cabal hook. + hercules-ci-cnix-store = haskellPackages.buildFromCabalSdist haskellPackages.hercules-ci-cnix-store; + + localFromCabalSdist = haskellPackages.buildFromCabalSdist localRaw; + + assumptionLocalHasDirectReference = runCommand "localHasDirectReference" { + drvPath = builtins.unsafeDiscardOutputDependency localRaw.drvPath; + } '' + grep ${./local} $drvPath >/dev/null + touch $out + ''; + + localHasNoDirectReference = runCommand "localHasNoDirectReference" { + drvPath = builtins.unsafeDiscardOutputDependency localFromCabalSdist.drvPath; + } '' + grep -v ${./local} $drvPath >/dev/null + touch $out + ''; +} diff --git a/nixpkgs/pkgs/test/haskell/cabalSdist/local/CHANGELOG.md b/nixpkgs/pkgs/test/haskell/cabalSdist/local/CHANGELOG.md new file mode 100644 index 000000000000..53cc3ae43d8a --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/cabalSdist/local/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for local + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/nixpkgs/pkgs/test/haskell/cabalSdist/local/app/Main.hs b/nixpkgs/pkgs/test/haskell/cabalSdist/local/app/Main.hs new file mode 100644 index 000000000000..65ae4a05d5db --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/cabalSdist/local/app/Main.hs @@ -0,0 +1,4 @@ +module Main where + +main :: IO () +main = putStrLn "Hello, Haskell!" diff --git a/nixpkgs/pkgs/test/haskell/cabalSdist/local/generated.nix b/nixpkgs/pkgs/test/haskell/cabalSdist/local/generated.nix new file mode 100644 index 000000000000..bfa299962bcb --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/cabalSdist/local/generated.nix @@ -0,0 +1,12 @@ +# nix run ../../../../..#cabal2nix -- ./. +{ mkDerivation, base, lib }: +mkDerivation { + pname = "local"; + version = "0.1.0.0"; + src = ./.; + isLibrary = false; + isExecutable = true; + executableHaskellDepends = [ base ]; + description = "Nixpkgs test case"; + license = lib.licenses.mit; +} diff --git a/nixpkgs/pkgs/test/haskell/cabalSdist/local/local.cabal b/nixpkgs/pkgs/test/haskell/cabalSdist/local/local.cabal new file mode 100644 index 000000000000..1670aa3af631 --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/cabalSdist/local/local.cabal @@ -0,0 +1,13 @@ +cabal-version: 2.4 +name: local +version: 0.1.0.0 + +synopsis: Nixpkgs test case +license: MIT +extra-source-files: CHANGELOG.md + +executable local + main-is: Main.hs + build-depends: base + hs-source-dirs: app + default-language: Haskell2010 diff --git a/nixpkgs/pkgs/test/haskell/default.nix b/nixpkgs/pkgs/test/haskell/default.nix new file mode 100644 index 000000000000..8f1f21d65b51 --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/default.nix @@ -0,0 +1,10 @@ +{ lib, callPackage }: + +lib.recurseIntoAttrs { + shellFor = callPackage ./shellFor { }; + cabalSdist = callPackage ./cabalSdist { }; + documentationTarball = callPackage ./documentationTarball { }; + setBuildTarget = callPackage ./setBuildTarget { }; + incremental = callPackage ./incremental { }; + upstreamStackHpackVersion = callPackage ./upstreamStackHpackVersion { }; +} diff --git a/nixpkgs/pkgs/test/haskell/documentationTarball/default.nix b/nixpkgs/pkgs/test/haskell/documentationTarball/default.nix new file mode 100644 index 000000000000..337510281012 --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/documentationTarball/default.nix @@ -0,0 +1,21 @@ +{ pkgs, haskellPackages }: + +let + drv = haskellPackages.vector; + docs = pkgs.haskell.lib.compose.documentationTarball drv; + +in pkgs.runCommand "test haskell.lib.compose.documentationTarball" { + meta = { + inherit (docs.meta) platforms; + }; +} '' + tar xvzf "${docs}/${drv.name}-docs.tar.gz" + + # Check for Haddock html + find "${drv.name}-docs" | grep -q "Data-Vector.html" + + # Check for source html + find "${drv.name}-docs" | grep -q "src/Data.Vector.html" + + touch "$out" +'' diff --git a/nixpkgs/pkgs/test/haskell/incremental/default.nix b/nixpkgs/pkgs/test/haskell/incremental/default.nix new file mode 100644 index 000000000000..4509939ba4f4 --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/incremental/default.nix @@ -0,0 +1,35 @@ +# Demonstration of incremental builds for Haskell. Useful for speeding up CI. +# +# See: https://www.haskellforall.com/2022/12/nixpkgs-support-for-incremental-haskell.html +# See: https://felixspringer.xyz/homepage/blog/incrementalHaskellBuildsWithNix + +{ haskell, lib }: + +let + inherit (haskell.lib.compose) overrideCabal; + + # Incremental builds work with GHC >=9.4. + temporary = haskell.packages.ghc944.temporary; + + # This will do a full build of `temporary`, while writing the intermediate build products + # (compiled modules, etc.) to the `intermediates` output. + temporary-full-build-with-incremental-output = overrideCabal (drv: { + doInstallIntermediates = true; + enableSeparateIntermediatesOutput = true; + }) temporary; + + # This will do an incremental build of `temporary` by copying the previously + # compiled modules and intermediate build products into the source tree + # before running the build. + # + # GHC will then naturally pick up and reuse these products, making this build + # complete much more quickly than the previous one. + temporary-incremental-build = overrideCabal (drv: { + previousIntermediates = temporary-full-build-with-incremental-output.intermediates; + }) temporary; +in + temporary-incremental-build.overrideAttrs (old: { + meta = { + maintainers = lib.teams.mercury.members; + }; + }) diff --git a/nixpkgs/pkgs/test/haskell/setBuildTarget/Bar.hs b/nixpkgs/pkgs/test/haskell/setBuildTarget/Bar.hs new file mode 100644 index 000000000000..010014082c7d --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/setBuildTarget/Bar.hs @@ -0,0 +1,4 @@ +module Main where + +main :: IO () +main = putStrLn "Hello, Bar!" diff --git a/nixpkgs/pkgs/test/haskell/setBuildTarget/Foo.hs b/nixpkgs/pkgs/test/haskell/setBuildTarget/Foo.hs new file mode 100644 index 000000000000..fec7bb11fe6c --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/setBuildTarget/Foo.hs @@ -0,0 +1,4 @@ +module Main where + +main :: IO () +main = putStrLn "Hello, Foo!" diff --git a/nixpkgs/pkgs/test/haskell/setBuildTarget/Setup.hs b/nixpkgs/pkgs/test/haskell/setBuildTarget/Setup.hs new file mode 100644 index 000000000000..9a994af677b0 --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/setBuildTarget/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/nixpkgs/pkgs/test/haskell/setBuildTarget/default.nix b/nixpkgs/pkgs/test/haskell/setBuildTarget/default.nix new file mode 100644 index 000000000000..f0c78c510449 --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/setBuildTarget/default.nix @@ -0,0 +1,43 @@ +{ pkgs, haskellPackages }: + +let + # This can be regenerated by running `cabal2nix .` in the current directory. + pkgDef = + { mkDerivation, base, lib }: + mkDerivation { + pname = "haskell-setBuildTarget"; + version = "0.1.0.0"; + src = ./.; + isLibrary = false; + isExecutable = true; + executableHaskellDepends = [ base ]; + license = lib.licenses.bsd3; + }; + + drv = haskellPackages.callPackage pkgDef {}; + + test = target: excluded: + let only = pkgs.haskell.lib.compose.setBuildTarget target drv; + in '' + if [[ ! -f "${only}/bin/${target}" ]]; then + echo "${target} was not built" + exit 1 + fi + + if [[ -f "${only}/bin/${excluded}" ]]; then + echo "${excluded} was built, when it should not have been" + exit 1 + fi + ''; + +in +pkgs.runCommand "test haskell.lib.compose.setBuildTarget" { + meta = { + inherit (drv.meta) platforms; + }; +} '' + ${test "foo" "bar"} + ${test "bar" "foo"} + touch "$out" +'' + diff --git a/nixpkgs/pkgs/test/haskell/setBuildTarget/haskell-setBuildTarget.cabal b/nixpkgs/pkgs/test/haskell/setBuildTarget/haskell-setBuildTarget.cabal new file mode 100644 index 000000000000..7395e139451c --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/setBuildTarget/haskell-setBuildTarget.cabal @@ -0,0 +1,16 @@ +cabal-version: >=1.10 +name: haskell-setBuildTarget +version: 0.1.0.0 +author: Isaac Shapira +maintainer: fresheyeball@protonmail.com +build-type: Simple + +executable foo + main-is: Foo.hs + build-depends: base + default-language: Haskell2010 + +executable bar + main-is: Bar.hs + build-depends: base + default-language: Haskell2010 diff --git a/nixpkgs/pkgs/test/haskell/shellFor/default.nix b/nixpkgs/pkgs/test/haskell/shellFor/default.nix new file mode 100644 index 000000000000..83daf079cc0f --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/shellFor/default.nix @@ -0,0 +1,57 @@ +{ lib, writeText, haskellPackages, cabal-install }: + +(haskellPackages.shellFor { + packages = p: [ p.constraints p.linear ]; + # WARNING: When updating this, make sure that the libraries passed to + # `extraDependencies` are not actually transitive dependencies of libraries in + # `packages` above. We explicitly want to test that it is possible to specify + # `extraDependencies` that are not in the closure of `packages`. + extraDependencies = p: { libraryHaskellDepends = [ p.conduit ]; }; + nativeBuildInputs = [ cabal-install ]; + phases = [ "unpackPhase" "buildPhase" "installPhase" ]; + unpackPhase = '' + sourceRoot=$(pwd)/scratch + mkdir -p "$sourceRoot" + cd "$sourceRoot" + tar -xf ${haskellPackages.constraints.src} + tar -xf ${haskellPackages.linear.src} + cp ${writeText "cabal.project" "packages: constraints* linear*"} cabal.project + ''; + buildPhase = '' + export HOME=$(mktemp -d) + mkdir -p $HOME/.cabal + touch $HOME/.cabal/config + + # Check that the extraDependencies.libraryHaskellDepends arg is correctly + # picked up. This uses ghci to interpret a small Haskell program that uses + # a package from extraDependencies. + ghci <<EOF + :set -XOverloadedStrings + :m + Conduit + runResourceT $ connect (yield "done") (sinkFile "outfile") + EOF + + if [[ "done" != "$(cat outfile)" ]]; then + echo "ERROR: extraDependencies appear not to be available in the environment" + exit 1 + fi + + # Check packages arg + cabal v2-build --offline --verbose constraints linear --ghc-options="-O0 -j$NIX_BUILD_CORES" + ''; + installPhase = '' + touch $out + ''; +}).overrideAttrs (oldAttrs: { + meta = + let + oldMeta = oldAttrs.meta or {}; + oldMaintainers = oldMeta.maintainers or []; + additionalMaintainers = with lib.maintainers; [ cdepillabout ]; + allMaintainers = oldMaintainers ++ additionalMaintainers; + in + oldMeta // { + maintainers = allMaintainers; + inherit (cabal-install.meta) platforms; + }; +}) diff --git a/nixpkgs/pkgs/test/haskell/upstreamStackHpackVersion/default.nix b/nixpkgs/pkgs/test/haskell/upstreamStackHpackVersion/default.nix new file mode 100644 index 000000000000..f3ddbcd3e016 --- /dev/null +++ b/nixpkgs/pkgs/test/haskell/upstreamStackHpackVersion/default.nix @@ -0,0 +1,152 @@ + +# This derivation confirms that the version of hpack used by stack in Nixpkgs +# is the exact same version as the upstream stack release. +# +# It is important to make sure the version of hpack used by stack in Nixpkgs +# matches with the version of hpack used by the upstream stack release. This +# is because hpack works slightly differently based on the version, and it can +# be frustrating to use hpack in a team setting when members are using different +# versions. See for more info: https://github.com/NixOS/nixpkgs/issues/223390 +# +# This test is written as a fixed-output derivation, because we need to access +# accesses the internet to download the upstream stack release. + +{ cacert, curl, lib, stack, stdenv }: + +let + # Find the hpack derivation that is a dependency of stack. Throw exception + # if hpack cannot be found. + hpack = + lib.findFirst + (v: v.pname or "" == "hpack") + (throw "could not find stack's hpack dependency") + stack.passthru.getCabalDeps.executableHaskellDepends; + + # This is a statically linked version of stack, so it should be usable within + # the Nixpkgs builder (at least on x86_64-linux). + stackDownloadUrl = + "https://github.com/commercialhaskell/stack/releases/download/v${stack.version}/stack-${stack.version}-linux-x86_64.tar.gz"; + + # This test code has been explicitly pulled out of the derivation below so + # that it can be hashed and added to the `name` of the derivation. This is + # so that this test derivation won't be cached if the body of the test is + # modified. + # + # WARNING: When modifying this script, make sure you don't introduce any + # paths to the Nix store within it. We only want this derivation to be re-run + # when the stack version (or the version of its hpack dependency) changes in + # Nixpkgs. + testScript = '' + curl=( + curl + --location + --max-redirs 20 + --retry 3 + --disable-epsv + --cookie-jar cookies + --user-agent "curl " + --insecure + ) + + # Fetch the statically-linked upstream Stack binary. + echo "Trying to download a statically linked stack binary from ${stackDownloadUrl} to ./stack.tar.gz ..." + "''${curl[@]}" "${stackDownloadUrl}" > ./stack.tar.gz + tar xf ./stack.tar.gz + + upstream_stack_version_output="$(./stack-${stack.version}-linux-x86_64/stack --version)" + echo "upstream \`stack --version\` output: $upstream_stack_version_output" + + nixpkgs_stack_version_output="$(stack --version)" + echo "nixpkgs \`stack --version\` output: $nixpkgs_stack_version_output" + + # Confirm that the upstream stack version is the same as the stack version + # in Nixpkgs. This check isn't strictly necessary, but it is a good sanity + # check. + + if [[ "$upstream_stack_version_output" =~ "Version "([0-9]+((\.[0-9]+)+)) ]]; then + upstream_stack_version="''${BASH_REMATCH[1]}" + + echo "parsed upstream stack version: $upstream_stack_version" + echo "stack version from nixpkgs: ${stack.version}" + + if [[ "${stack.version}" != "$upstream_stack_version" ]]; then + echo "ERROR: stack version in Nixpkgs (${stack.version}) does not match the upstream version for some reason: $upstream_stack_version" + exit 1 + fi + else + echo "ERROR: Upstream stack version cannot be found in --version output: $upstream_stack_version" + exit 1 + fi + + # Confirm that the hpack version used in the upstream stack release is the + # same as the hpack version used by the Nixpkgs stack binary. + + if [[ "$upstream_stack_version_output" =~ hpack-([0-9]+((\.[0-9]+)+)) ]]; then + upstream_hpack_version="''${BASH_REMATCH[1]}" + + echo "parsed upstream stack's hpack version: $upstream_hpack_version" + echo "Nixpkgs stack's hpack version: ${hpack.version}" + + if [[ "${hpack.version}" != "$upstream_hpack_version" ]]; then + echo "ERROR: stack's hpack version in Nixpkgs (${hpack.version}) does not match the upstream stack's hpack version: $upstream_hpack_version" + echo "The stack derivation in Nixpkgs needs to be fixed up so that it depends on hpack-$upstream_hpack_version, instead of ${hpack.name}" + exit 1 + fi + else + echo "ERROR: Upstream stack's hpack version cannot be found in --version output: $upstream_hpack_version" + exit 1 + fi + + # Output a string with a known hash. + echo "success" > $out + ''; + + testScriptHash = builtins.hashString "sha256" testScript; +in + +stdenv.mkDerivation { + + # This name is very important. + # + # The idea here is that want this derivation to be re-run everytime the + # version of stack (or the version of its hpack dependency) changes in + # Nixpkgs. We also want to re-run this derivation whenever the test script + # is changed. + # + # Nix/Hydra will re-run derivations if their name changes (even if they are a + # FOD and they have the same hash). + # + # The name of this derivation contains the stack version string, the hpack + # version string, and a hash of the test script. So Nix will know to + # re-run this version when (and only when) one of those values change. + name = "upstream-stack-hpack-version-test-${stack.name}-${hpack.name}-${testScriptHash}"; + + # This is the sha256 hash for the string "success", which is output upon this + # test succeeding. + outputHash = "sha256-gbK9TqmMjbZlVPvI12N6GmmhMPMx/rcyt1yqtMSGj9U="; + outputHashMode = "flat"; + outputHashAlgo = "sha256"; + + nativeBuildInputs = [ curl stack ]; + + impureEnvVars = lib.fetchers.proxyImpureEnvVars; + + buildCommand = '' + # Make sure curl can access HTTPS sites, like GitHub. + # + # Note that we absolutely don't want the Nix store path of the cacert + # derivation in the testScript, because we don't want to rebuild this + # derivation when only the cacert derivation changes. + export SSL_CERT_FILE="${cacert}/etc/ssl/certs/ca-bundle.crt" + '' + testScript; + + meta = with lib; { + description = "Test that the stack in Nixpkgs uses the same version of Hpack as the upstream stack release"; + maintainers = with maintainers; [ cdepillabout ]; + + # This derivation internally runs a statically-linked version of stack from + # upstream. This statically-linked version of stack is only available for + # x86_64-linux, so this test can only be run on x86_64-linux. + platforms = [ "x86_64-linux" ]; + }; +} |