mirror of
https://github.com/nmattia/snack.git
synced 2024-12-01 03:03:55 +03:00
Support haskell dependencies
This commit is contained in:
parent
3c27e2efb0
commit
ac18afcf88
12
README.md
12
README.md
@ -9,3 +9,15 @@ $ $(nix-build)/out
|
||||
```
|
||||
|
||||
See the [test suite](./script/test) for examples.
|
||||
|
||||
Example:
|
||||
|
||||
``` shell
|
||||
$ ./script/test
|
||||
$ ./tests/packages/result/out
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
```
|
||||
|
@ -2,7 +2,8 @@
|
||||
import (import nixpkgs) {
|
||||
config = { allowUnfree = true; };
|
||||
overlays = [
|
||||
(self: super: { snack-lib = import ../snack;} )
|
||||
(self: super: { snack-lib = import ../snack {};} )
|
||||
(self: super: { snack-lib-with = extra: import ../snack extra;} )
|
||||
(self: super: { snack = self.writeScriptBin "snack"
|
||||
''
|
||||
${self.nix}/bin/nix-build snack.nix
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "42b9b8f7c8687cb26e69c3559e0e1346fb0e680f",
|
||||
"sha256": "01zcd0dh9x3qf5yflclbrcvff9yh8k9pmccc7vjlq3phc440qsyb"
|
||||
"rev": "584270e39743020d8aa056b40eea00fcaa2b595f",
|
||||
"sha256": "1p8hrz7xz73gzcqw62f3zfkmf3pkwwn1b41xzs7ayxafkmzsh0hw"
|
||||
}
|
||||
|
@ -18,3 +18,7 @@ popd
|
||||
pushd tests/dependencies
|
||||
snack build
|
||||
popd
|
||||
|
||||
pushd tests/packages
|
||||
snack build
|
||||
popd
|
||||
|
@ -1,7 +1,17 @@
|
||||
# TODO: currently single out derivations append the PWD
|
||||
# TODO: currently single out derivations prepend the PWD to the path
|
||||
# TODO: make dependecies on GHC per-module if possible
|
||||
# TODO: there are too many "does file exist"
|
||||
# TODO: make sure that filters for "base" are airtight
|
||||
# TODO: use --make everywhere ?!? NOTE: this is tricky because GHC flags
|
||||
# change: when a module is built with its dependencies, the flags for the
|
||||
# dependencies change as well, which causes them to be recompiled
|
||||
{ pkgs ? import (../nix) {} # nixpkgs
|
||||
, dependencies ? [] # The list of haskell dependencies, e.g. conduit, mtl, etc
|
||||
, ghcWith ? pkgs.haskellPackages.ghcWithPackages
|
||||
}:
|
||||
let
|
||||
# Use pinned packages
|
||||
pkgs = import (../nix) {};
|
||||
# GHC with the package DB
|
||||
ghc = ghcWith (ps: map (p: ps.${p}) dependencies);
|
||||
|
||||
# Takes a (string) filepath and creates a derivation for that file (and for
|
||||
# that file only)
|
||||
@ -56,6 +66,8 @@ let
|
||||
singleOutModulePath = base: mod:
|
||||
"${singleOut base (moduleToFile mod)}/${moduleToFile mod}";
|
||||
|
||||
# Create a module spec by following the dependencies. This assumes that the
|
||||
# specified module is a "Main" module.
|
||||
makeModuleSpecRec = base:
|
||||
pkgs.lib.fix
|
||||
(f: isMain: modName:
|
||||
@ -68,7 +80,6 @@ let
|
||||
buildFrom = base: modName: linkModuleObjects base
|
||||
(makeModuleSpecRec base modName);
|
||||
|
||||
|
||||
buildModule = base: mod:
|
||||
let
|
||||
objectName = mod.moduleName;
|
||||
@ -103,17 +114,42 @@ let
|
||||
echo "Done building module ${mod.moduleName}"
|
||||
'';
|
||||
buildInputs =
|
||||
[ pkgs.haskellPackages.ghc
|
||||
[ ghc
|
||||
pkgs.rsync
|
||||
];
|
||||
};
|
||||
|
||||
# Generate a list of haskell module names needed by the haskell file
|
||||
# Generate a list of haskell module names needed by the haskell file,
|
||||
# excluding modules that are not present in this project/base
|
||||
listModuleDependencies = base: modName:
|
||||
builtins.fromJSON
|
||||
(builtins.readFile (listModuleDependenciesJSON base modName));
|
||||
pkgs.lib.filter
|
||||
(doesModuleExist base)
|
||||
(builtins.fromJSON
|
||||
(builtins.readFile (listAllModuleDependenciesJSON base modName))
|
||||
);
|
||||
|
||||
listModuleDependenciesJSON = base: modName:
|
||||
doesFileExist = base: filename: builtins.fromJSON (builtins.readFile
|
||||
(
|
||||
pkgs.stdenv.mkDerivation
|
||||
{ name = "does-file-exist";
|
||||
src = null;
|
||||
|
||||
builder = pkgs.writeScript "does-file-exist"
|
||||
''
|
||||
if [ ! -f ${base}/${filename} ]; then
|
||||
echo -n "false" > $out
|
||||
else
|
||||
echo -n "true" > $out
|
||||
fi
|
||||
'';
|
||||
}
|
||||
));
|
||||
doesModuleExist = base: modName: doesFileExist base (moduleToFile modName);
|
||||
|
||||
# TODO: if module doesn't exist locally, don't include it
|
||||
# Lists all module dependencies, not limited to modules existing in this
|
||||
# project
|
||||
listAllModuleDependenciesJSON = base: modName:
|
||||
pkgs.stdenv.mkDerivation
|
||||
{ name = "module-deps";
|
||||
src = null;
|
||||
@ -145,10 +181,9 @@ let
|
||||
go = mod: attrs0:
|
||||
let
|
||||
objectName = x:
|
||||
# TODO: can't use "moduleName.o" because some modules get
|
||||
# renamed to "Main.o" :/
|
||||
# Also, hard coding the object file based on the module name feels
|
||||
# icky
|
||||
# TODO: can't justuse "moduleName.o" because some modules get
|
||||
# renamed to "Main.o" :/ Also, hard coding the object file based on
|
||||
# the module name feels icky
|
||||
if x.moduleIsMain
|
||||
then "Main.o"
|
||||
else moduleToObject x.moduleName;
|
||||
@ -168,6 +203,7 @@ let
|
||||
let
|
||||
objAttrs = flattenModuleObjects base mod;
|
||||
objList = pkgs.lib.attrsets.mapAttrsToList (x: y: y) objAttrs;
|
||||
packageList = map (p: "-package ${p}") dependencies;
|
||||
in pkgs.stdenv.mkDerivation
|
||||
{ name = "linker";
|
||||
src = null;
|
||||
@ -175,10 +211,13 @@ let
|
||||
''
|
||||
source $stdenv/setup
|
||||
mkdir -p $out
|
||||
ghc ${pkgs.lib.strings.escapeShellArgs objList} -o $out/out
|
||||
ghc \
|
||||
${pkgs.lib.strings.escapeShellArgs packageList} \
|
||||
${pkgs.lib.strings.escapeShellArgs objList} \
|
||||
-o $out/out
|
||||
'';
|
||||
buildInputs =
|
||||
[ pkgs.haskellPackages.ghc
|
||||
[ ghc
|
||||
];
|
||||
};
|
||||
|
||||
@ -188,7 +227,6 @@ in
|
||||
inherit
|
||||
buildFrom
|
||||
linkModuleObjects
|
||||
listModuleDependenciesJSON
|
||||
makeModuleSpec
|
||||
;
|
||||
}
|
||||
|
5
tests/packages/snack.nix
Normal file
5
tests/packages/snack.nix
Normal file
@ -0,0 +1,5 @@
|
||||
# This "snack" passing is ugly, figure out a nice way of passing snack-lib
|
||||
with (import ../../nix {}).snack-lib-with
|
||||
{ dependencies = ["conduit"] ;
|
||||
};
|
||||
buildFrom ./src "Foo"
|
5
tests/packages/src/Foo.hs
Normal file
5
tests/packages/src/Foo.hs
Normal file
@ -0,0 +1,5 @@
|
||||
import Conduit
|
||||
import FooBar
|
||||
|
||||
main :: IO ()
|
||||
main = runConduit $ spitOut .| takeC 5 .| digest
|
9
tests/packages/src/FooBar.hs
Normal file
9
tests/packages/src/FooBar.hs
Normal file
@ -0,0 +1,9 @@
|
||||
module FooBar where
|
||||
|
||||
import Conduit
|
||||
|
||||
spitOut :: ConduitT () Int IO ()
|
||||
spitOut = yieldMany [ 1 ..]
|
||||
|
||||
digest :: ConduitT Int Void IO ()
|
||||
digest = mapM_C print
|
Loading…
Reference in New Issue
Block a user