From f09f33fed429f40d8eefd66bf1b970db5a614d2f Mon Sep 17 00:00:00 2001 From: Nicolas Mattia Date: Tue, 26 Feb 2019 23:37:52 +0100 Subject: [PATCH] Support extra packages in yaml --- snack-lib/hpack.nix | 87 ++++++++++++++++--------------- snack-lib/lib.nix | 2 + tests/any-paths/package.yaml | 4 +- tests/packages-2/Main.hs | 3 ++ tests/packages-2/golden | 1 + tests/packages-2/lib/Lib.hs | 4 ++ tests/packages-2/lib/package.yaml | 6 +++ tests/packages-2/package.yaml | 6 +++ tests/packages-2/test | 19 +++++++ 9 files changed, 89 insertions(+), 43 deletions(-) create mode 100644 tests/packages-2/Main.hs create mode 100644 tests/packages-2/golden create mode 100644 tests/packages-2/lib/Lib.hs create mode 100644 tests/packages-2/lib/package.yaml create mode 100644 tests/packages-2/package.yaml create mode 100755 tests/packages-2/test diff --git a/snack-lib/hpack.nix b/snack-lib/hpack.nix index 4c61a50..2cb7616 100644 --- a/snack-lib/hpack.nix +++ b/snack-lib/hpack.nix @@ -20,7 +20,7 @@ let "${y2j} ${writeText "y2j" text} > $out" ); in builtins.fromJSON json; -in +in rec { # Returns an attribute set with two fields: # - library: a package spec @@ -28,6 +28,19 @@ in pkgSpecsFromHPack = packageYaml: let package = fromYAML (builtins.readFile packageYaml); + base = builtins.dirOf packageYaml; + commonAttrs = component: + { ghcOpts = topGhcOpts ++ (optAttr component "ghc-options" []); + extensions = topExtensions ++ (optAttr component "extensions" []); + src = + with { source-dirs = optAttr component "source-dirs" "."; }; + if builtins.isList source-dirs + then builtins.map (sourceDir: + builtins.toPath "${builtins.toString base}/${sourceDir}" + ) source-dirs + else + builtins.toPath "${builtins.toString base}/${source-dirs}"; + }; # Snack drops the version bounds because here it has no meaning dropVersionBounds = @@ -37,51 +50,43 @@ in topExtensions = optAttr package "default-extensions" []; topGhcOpts = optAttr package "ghc-options" []; libs = withAttr package "library" [] (component: - [{ - src = - let - base = builtins.dirOf packageYaml; - source-dirs = optAttr component "source-dirs" "."; - in - if builtins.isList source-dirs - then builtins.map (sourceDir: - builtins.toPath "${builtins.toString base}/${sourceDir}" - ) source-dirs - else - builtins.toPath "${builtins.toString base}/${source-dirs}"; - dependencies = topDeps ++ mkDeps component; - extensions = topExtensions ++ (optAttr component "extensions" []); - ghcOpts = topGhcOpts ++ (optAttr component "ghc-options" []); - }] + [ (commonAttrs component // + { dependencies = topDeps ++ mkDeps component; } + ) + ] ); exes = withAttr package "executables" [] (lib.mapAttrsToList (k: v: mkExe k v)) ++ withAttr package "executable" [] (comp: [(mkExe package.name comp)] ); mkExe = nn: component: - let - depOrPack = - lib.lists.partition - (x: x == package.name) - (optAttr component "dependencies" []); - in - { main = fileToModule component.main; - name = nn; - src = - let - base = builtins.dirOf packageYaml; - source-dirs = optAttr component "source-dirs" "."; - in - if builtins.isList source-dirs - then builtins.map (sourceDir: - builtins.toPath "${builtins.toString base}/${sourceDir}" - ) source-dirs - else - builtins.toPath "${builtins.toString base}/${source-dirs}"; - dependencies = topDeps ++ dropVersionBounds depOrPack.wrong; - extensions = topExtensions ++ (optAttr component "extensions" []); - ghcOpts = topGhcOpts ++ (optAttr component "ghc-options" []); - packages = if lib.length depOrPack.right > 0 then libs else []; - }; + with + { + depsAndPacks = lib.foldl + (acc: x: + if x == package.name then tap acc "packs" (ps: ps ++ libs) + else if lib.hasPrefix "./" x then tap acc "packs" (ps: + ps ++ + # This is extremely brittle: + # - there could be more than one package + # - this needs to make sure it only picks libraries + # - it only works with "package.yaml" + [ + (lib.head + ( pkgSpecsFromHPack + ("${builtins.toString base}/${x}/package.yaml") + ) + ) + ] + ) + else tap acc "deps" (ds: ds ++ [x]) + ) { deps = []; packs = []; } (optAttr component "dependencies" []); + }; + commonAttrs component // + { main = fileToModule component.main; + name = nn; + dependencies = topDeps ++ dropVersionBounds depsAndPacks.deps; # depOrPack.wrong; + packages = depsAndPacks.packs; + }; in exes ++ libs; } diff --git a/snack-lib/lib.nix b/snack-lib/lib.nix index c4329c6..29433c2 100644 --- a/snack-lib/lib.nix +++ b/snack-lib/lib.nix @@ -50,4 +50,6 @@ withAttr = obj: attrName: def: f: optAttr = obj: attrName: def: if builtins.hasAttr attrName obj then obj.${attrName} else def; +tap = obj: attrName: f: obj // { "${attrName}" = f (obj.${attrName}) ; }; + } diff --git a/tests/any-paths/package.yaml b/tests/any-paths/package.yaml index 95bc5ac..74df982 100644 --- a/tests/any-paths/package.yaml +++ b/tests/any-paths/package.yaml @@ -1,4 +1,4 @@ -name: snack-readme +name: any-paths dependencies: - lens @@ -11,7 +11,7 @@ executable: main: Main.hs source-dirs: ./app dependencies: - - snack-readme + - any-paths default-extensions: - OverloadedStrings diff --git a/tests/packages-2/Main.hs b/tests/packages-2/Main.hs new file mode 100644 index 0000000..55bea88 --- /dev/null +++ b/tests/packages-2/Main.hs @@ -0,0 +1,3 @@ +import Lib (fromLib) + +main = putStrLn fromLib diff --git a/tests/packages-2/golden b/tests/packages-2/golden new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/tests/packages-2/golden @@ -0,0 +1 @@ +hello diff --git a/tests/packages-2/lib/Lib.hs b/tests/packages-2/lib/Lib.hs new file mode 100644 index 0000000..5d4b957 --- /dev/null +++ b/tests/packages-2/lib/Lib.hs @@ -0,0 +1,4 @@ +module Lib (fromLib) where + +fromLib :: String +fromLib = "hello" diff --git a/tests/packages-2/lib/package.yaml b/tests/packages-2/lib/package.yaml new file mode 100644 index 0000000..456af76 --- /dev/null +++ b/tests/packages-2/lib/package.yaml @@ -0,0 +1,6 @@ +name: snack-packages-2 + +# NOTE: should not fail if library is empty +# For some reason, Nix returns null as opposed to {} +library: + source-dirs: . diff --git a/tests/packages-2/package.yaml b/tests/packages-2/package.yaml new file mode 100644 index 0000000..7e1f437 --- /dev/null +++ b/tests/packages-2/package.yaml @@ -0,0 +1,6 @@ +name: snack-packages + +executable: + main: Main.hs + dependencies: + - ./lib diff --git a/tests/packages-2/test b/tests/packages-2/test new file mode 100755 index 0000000..314a800 --- /dev/null +++ b/tests/packages-2/test @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# vim: ft=sh sw=2 et + +set -euo pipefail + + +test() { + $SNACK build + $SNACK run | diff golden - + + TMP_FILE=$(mktemp) + + capture_io "$TMP_FILE" main | $SNACK ghci + + diff golden $TMP_FILE + rm $TMP_FILE +} + +SNACK="snack --package-file ./package.yaml" test