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

Add support for extra data files

This commit is contained in:
Nicolas Mattia 2018-05-19 20:05:40 +02:00
parent 54944a8cd8
commit 9b6a99b174
7 changed files with 77 additions and 19 deletions

View File

@ -10,3 +10,7 @@ set -eux
pushd tests/packages
snack build
popd
pushd tests/template-haskell
snack build
popd

View File

@ -1,4 +1,5 @@
# TODO: currently single out derivations prepend the PWD to the path
# TODO: commented out modules (-- Foo.Module) aren't parsed properly
# 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
@ -40,10 +41,11 @@ let
'';
};
makeModuleSpec = modName: deps: isMain:
makeModuleSpec = modName: deps: isMain: modFiles:
{ moduleName = modName;
moduleIsMain = isMain;
moduleDependencies = deps;
moduleFiles = modFiles;
};
moduleToFile = mod:
@ -63,13 +65,14 @@ let
# Create a module spec by following the dependencies. This assumes that the
# specified module is a "Main" module.
makeModuleSpecRec = base:
makeModuleSpecRec = base: filesByModuleName:
pkgs.lib.fix
(f: isMain: modName:
makeModuleSpec
modName
(map (f false) (listModuleDependencies base modName))
isMain
(filesByModuleName modName)
) true;
buildModule = ghc: base: mod:
@ -82,6 +85,11 @@ let
# TODO: symlink instead of copy
then "rsync -r ${pkgs.lib.strings.escapeShellArgs depsDirs} ."
else "";
makeFilesTree =
if pkgs.lib.lists.length mod.moduleFiles >= 1
# TODO: symlink instead of copy
then "rsync -r ${pkgs.lib.strings.escapeShellArgs mod.moduleFiles} ."
else "";
makeSymModule =
# TODO: symlink instead of copy
"rsync -r ${singleOutModule base mod.moduleName}/ .";
@ -97,6 +105,8 @@ let
${makeSymtree}
echo "Creating module symlink for module ${mod.moduleName}"
${makeSymModule}
echo "Creating files symlink for module ${mod.moduleName}"
${makeFilesTree}
echo "Compiling module ${mod.moduleName}"
# Set a tmpdir we have control over, otherwise GHC fails, not sure why
mkdir -p tmp
@ -192,10 +202,11 @@ let
in go mod' {};
# TODO: it's sad that we pass ghcWithDeps + dependencies
linkModuleObjects = ghc: dependencies: base: mod:
linkModuleObjects = ghc: ghcOpts: dependencies: base: mod:
let
objAttrs = flattenModuleObjects ghc base mod;
objList = pkgs.lib.attrsets.mapAttrsToList (x: y: y) objAttrs;
ghcOptsArgs = pkgs.lib.strings.escapeShellArgs ghcOpts;
packageList = map (p: "-package ${p}") dependencies;
in pkgs.stdenv.mkDerivation
{ name = "linker";
@ -207,6 +218,7 @@ let
${ghc}/bin/ghc \
${pkgs.lib.strings.escapeShellArgs packageList} \
${pkgs.lib.strings.escapeShellArgs objList} \
${ghcOptsArgs} \
-o $out/out
'';
};
@ -217,9 +229,10 @@ let
# Write a new ghci executable that loads all the modules defined in the
# module spec
ghciExecutable = ghc: base: modSpec:
ghciExecutable = ghc: ghcOpts: base: modSpec:
let
ghciArgs = pkgs.lib.strings.escapeShellArgs absoluteModuleFiles;
ghciArgs = pkgs.lib.strings.escapeShellArgs
(ghcOpts ++ absoluteModuleFiles);
absoluteModuleFiles = map prependBase moduleFiles;
moduleFiles = map moduleToFile modules;
modules = allModuleNames modSpec;
@ -238,23 +251,29 @@ let
};
snack = executable:
let
ghc = pkgs.haskellPackages.ghcWithPackages
(ps: map (p: ps.${p}) deps);
deps = executable.dependencies;
ghcOpts =
if (builtins.hasAttr "ghc-options" executable)
then executable.ghc-options
else [];
base = executable.src;
foo =
if (builtins.hasAttr "extra-files" executable)
then
if builtins.isList executable.extra-files
then (_x: executable.extra-files)
else executable.extra-files
else (x: []);
mainModName = executable.main;
in
{
build =
let
ghc = pkgs.haskellPackages.ghcWithPackages
(ps: map (p: ps.${p}) deps);
deps = executable.dependencies;
base = executable.src;
mainModName = executable.main;
in linkModuleObjects ghc deps base (makeModuleSpecRec base mainModName);
linkModuleObjects ghc ghcOpts deps base (makeModuleSpecRec base foo mainModName);
ghci =
let
ghc = pkgs.haskellPackages.ghcWithPackages
(ps: map (p: ps.${p}) deps);
deps = executable.dependencies;
base = executable.src;
mainModName = executable.main;
in ghciExecutable ghc base (makeModuleSpecRec base mainModName);
ghciExecutable ghc ghcOpts base (makeModuleSpecRec base foo mainModName);
};

View File

@ -0,0 +1,9 @@
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Data.FileEmbed
import qualified Data.ByteString.Char8 as BS8
main :: IO ()
main = BS8.putStrLn $(embedFile "./foo.txt")

View File

@ -0,0 +1 @@
Hello, World!

View File

@ -0,0 +1,11 @@
let
pkgs = import ../../nix {};
snack = pkgs.snack-lib.snack;
in
snack
{ main = "Main";
src = ./.;
dependencies = ["file-embed"];
extra-files =
(modName: if modName == "Main" then [ ./foo.txt ] else []);
}

View File

@ -0,0 +1,5 @@
import Conduit
import FooBar
main :: IO ()
main = runConduit $ spitOut .| takeC 5 .| digest

View 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