1
1
mirror of https://github.com/nmattia/snack.git synced 2024-09-11 11:55:36 +03:00

Support extra packages in yaml

This commit is contained in:
Nicolas Mattia 2019-02-26 23:37:52 +01:00
parent e8cef886cf
commit f09f33fed4
9 changed files with 89 additions and 43 deletions

View File

@ -20,7 +20,7 @@ let
"${y2j} ${writeText "y2j" text} > $out" "${y2j} ${writeText "y2j" text} > $out"
); );
in builtins.fromJSON json; in builtins.fromJSON json;
in in rec
{ {
# Returns an attribute set with two fields: # Returns an attribute set with two fields:
# - library: a package spec # - library: a package spec
@ -28,6 +28,19 @@ in
pkgSpecsFromHPack = packageYaml: pkgSpecsFromHPack = packageYaml:
let let
package = fromYAML (builtins.readFile packageYaml); 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 # Snack drops the version bounds because here it has no meaning
dropVersionBounds = dropVersionBounds =
@ -37,51 +50,43 @@ in
topExtensions = optAttr package "default-extensions" []; topExtensions = optAttr package "default-extensions" [];
topGhcOpts = optAttr package "ghc-options" []; topGhcOpts = optAttr package "ghc-options" [];
libs = withAttr package "library" [] (component: libs = withAttr package "library" [] (component:
[{ [ (commonAttrs component //
src = { dependencies = topDeps ++ mkDeps component; }
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" []);
}]
); );
exes = exes =
withAttr package "executables" [] (lib.mapAttrsToList (k: v: mkExe k v)) ++ withAttr package "executables" [] (lib.mapAttrsToList (k: v: mkExe k v)) ++
withAttr package "executable" [] (comp: [(mkExe package.name comp)] ); withAttr package "executable" [] (comp: [(mkExe package.name comp)] );
mkExe = nn: component: mkExe = nn: component:
let with
depOrPack = {
lib.lists.partition depsAndPacks = lib.foldl
(x: x == package.name) (acc: x:
(optAttr component "dependencies" []); if x == package.name then tap acc "packs" (ps: ps ++ libs)
in else if lib.hasPrefix "./" x then tap acc "packs" (ps:
{ main = fileToModule component.main; ps ++
name = nn; # This is extremely brittle:
src = # - there could be more than one package
let # - this needs to make sure it only picks libraries
base = builtins.dirOf packageYaml; # - it only works with "package.yaml"
source-dirs = optAttr component "source-dirs" "."; [
in (lib.head
if builtins.isList source-dirs ( pkgSpecsFromHPack
then builtins.map (sourceDir: ("${builtins.toString base}/${x}/package.yaml")
builtins.toPath "${builtins.toString base}/${sourceDir}" )
) source-dirs )
else ]
builtins.toPath "${builtins.toString base}/${source-dirs}"; )
dependencies = topDeps ++ dropVersionBounds depOrPack.wrong; else tap acc "deps" (ds: ds ++ [x])
extensions = topExtensions ++ (optAttr component "extensions" []); ) { deps = []; packs = []; } (optAttr component "dependencies" []);
ghcOpts = topGhcOpts ++ (optAttr component "ghc-options" []); };
packages = if lib.length depOrPack.right > 0 then libs else []; commonAttrs component //
}; { main = fileToModule component.main;
name = nn;
dependencies = topDeps ++ dropVersionBounds depsAndPacks.deps; # depOrPack.wrong;
packages = depsAndPacks.packs;
};
in exes ++ libs; in exes ++ libs;
} }

View File

@ -50,4 +50,6 @@ withAttr = obj: attrName: def: f:
optAttr = obj: attrName: def: optAttr = obj: attrName: def:
if builtins.hasAttr attrName obj then obj.${attrName} else def; if builtins.hasAttr attrName obj then obj.${attrName} else def;
tap = obj: attrName: f: obj // { "${attrName}" = f (obj.${attrName}) ; };
} }

View File

@ -1,4 +1,4 @@
name: snack-readme name: any-paths
dependencies: dependencies:
- lens - lens
@ -11,7 +11,7 @@ executable:
main: Main.hs main: Main.hs
source-dirs: ./app source-dirs: ./app
dependencies: dependencies:
- snack-readme - any-paths
default-extensions: default-extensions:
- OverloadedStrings - OverloadedStrings

3
tests/packages-2/Main.hs Normal file
View File

@ -0,0 +1,3 @@
import Lib (fromLib)
main = putStrLn fromLib

1
tests/packages-2/golden Normal file
View File

@ -0,0 +1 @@
hello

View File

@ -0,0 +1,4 @@
module Lib (fromLib) where
fromLib :: String
fromLib = "hello"

View File

@ -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: .

View File

@ -0,0 +1,6 @@
name: snack-packages
executable:
main: Main.hs
dependencies:
- ./lib

19
tests/packages-2/test Executable file
View File

@ -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