1
1
mirror of https://github.com/nmattia/snack.git synced 2025-01-06 04:25:30 +03:00

major refactor

This commit is contained in:
Nicolas Mattia 2018-06-17 15:54:57 +02:00
parent d414ace1ee
commit cc2bf83650
20 changed files with 143 additions and 128 deletions

View File

@ -3,8 +3,10 @@ set -euo pipefail
## Defaults
NIXPKGS=
NIX_BUILD=nix-build
SNACK_NIX=snack.nix
SNACK_NIX="./snack.nix"
WRAPPER_NIX=
COMMAND=
## Functions
@ -21,6 +23,12 @@ Snack is a Haskell build tool
Options:
-f | --snack-nix <PATH>: sets the path ot the "snack.nix" file. Default: "./snack.nix"
-w | --wrapper-nix <PATH>: sets the path ot the nix wrapper file. This file
should take at least one argument, "snackNix", which is the path to the
"snack.nix".
-n | --nixpkgs <PATH>: use the path to import nixpkgs. The expression should
take no arguments and evaluate to a set containing at least
"snack-lib".
-h | --help: Shows this help
Commands:
@ -41,6 +49,16 @@ while [[ $# -gt 0 ]]; do
shift
shift
;;
-w | --wrapper-nix)
WRAPPER_NIX="$2"
shift
shift
;;
-n | --nixpkgs)
NIXPKGS="$2"
shift
shift
;;
-h | --help)
show_usage
exit 0
@ -62,16 +80,31 @@ if [[ -z "$COMMAND" ]]; then
exit 1
fi
if [[ -z "$WRAPPER_NIX" ]]; then
log_error "missing <wrapper>\n"
show_usage
exit 1
fi
call_snack() {
"$NIX_BUILD" \
--no-out-link \
-A $1 \
"$WRAPPER_NIX" \
--arg snackNix "$SNACK_NIX" \
--arg nixpkgs "$NIXPKGS"
}
case $COMMAND in
build)
"$NIX_BUILD" --no-out-link --show-trace -A build "$SNACK_NIX"
call_snack build
;;
ghci)
res=$("$NIX_BUILD" --no-out-link -A ghci "$SNACK_NIX")
res=$(call_snack ghci)
"$res"
;;
run)
res=$("$NIX_BUILD" --no-out-link -A build "$SNACK_NIX")
res=$(call_snack build)
"$res/out"
;;
esac

View File

@ -3,7 +3,7 @@ _: pkgs: {
snack-exe = pkgs.writeScriptBin
"snack"
(builtins.replaceStrings
["NIX_BUILD=nix-build"]
["NIX_BUILD=${pkgs.nix}/bin/nix-build"]
["NIX_BUILD=nix-build" "WRAPPER_NIX="]
["NIX_BUILD=${pkgs.nix}/bin/nix-build" "WRAPPER_NIX=${../snack-lib/wrapper.nix}"]
(builtins.readFile ../bin/snack));
}

View File

@ -33,6 +33,8 @@ END_HEREDOC
export -f capture_io
export SNACK="snack -n $(readlink -f ./nix)"
fail() {
echo "ERROR: $*"
exit 1

View File

@ -204,58 +204,50 @@ let
executable = pkgDescr:
let
topPkgSpec = mkPackageSpec pkgDescr;
pkgs = flattenPackages topPkgSpec;
baseByModuleName = modName:
(pkgSpecByModuleName pkgs topPkgSpec modName).packageBase;
let res = pkgSpecByModuleName topPkgSpec null modName;
in if res == null then null else res.packageBase;
depsByModuleName = modName:
(pkgSpecByModuleName pkgs (abort "should not happen") modName).packageDependencies;
(pkgSpecByModuleName
topPkgSpec
(abort "asking dependencies for external module: ${modName}")
modName).packageDependencies;
ghcOptsByModuleName = modName:
(pkgSpecByModuleName pkgs (abort "should not happen") modName).packageGhcOpts;
(pkgSpecByModuleName
topPkgSpec
(abort "asking ghc options for external module: ${modName}")
modName).packageGhcOpts;
ghcWith = deps: haskellPackages.ghcWithPackages
(ps: map (p: ps.${p}) deps);
ghcOpts = topPkgSpec.packageGhcOpts;
base = topPkgSpec.packageBase;
extraFiles = topPkgSpec.packageExtraFiles;
extraDirs = topPkgSpec.packageExtraDirectories;
mainModName = topPkgSpec.packageMain;
topModuleSpec =
makeModuleSpecRec
baseByModuleName
extraFiles
extraDirs
depsByModuleName
ghcOptsByModuleName
mainModName;
in
{
build =
linkModuleObjects
ghcWith
(makeModuleSpecRec
baseByModuleName
extraFiles
extraDirs
depsByModuleName
ghcOptsByModuleName
mainModName);
topModuleSpec;
ghci =
ghciExecutable
ghcWith
ghcOpts
(makeModuleSpecRec
baseByModuleName
extraFiles
extraDirs
depsByModuleName
ghcOptsByModuleName
mainModName);
(allTransitiveGhcOpts topPkgSpec)
topModuleSpec;
};
library =
{ src
, dependencies ? [] # TODO: handle this
}:
{
inherit src dependencies;
# TODO: add build for libraries
};
in
{
inherit
executable
library
;
}

View File

@ -42,7 +42,7 @@ rec {
makeModuleSpec
modName
(map (f false)
(listModuleImports baseByModuleName modName)
(lib.lists.filter (mn: baseByModuleName mn != null) (listModuleImports baseByModuleName modName))
)
isMain
(filesByModuleName modName)

View File

@ -29,22 +29,17 @@ rec {
singleOutModulePath = base: mod:
"${singleOut base (moduleToFile mod)}/${moduleToFile mod}";
# Generate a list of haskell module names needed by the haskell file,
# excluding modules that are not present in this project/base
# Generate a list of haskell module names needed by the haskell file
listModuleImports = baseByModuleName: modName:
lib.filter
(doesModuleExist baseByModuleName)
(builtins.fromJSON
(builtins.readFile (listAllModuleImportsJSON (baseByModuleName modName) modName))
);
builtins.fromJSON
(builtins.readFile (listAllModuleImportsJSON (baseByModuleName modName) modName))
;
listModulesInDir = dir: map fileToModule (listFilesInDir dir);
doesModuleExist = baseByModuleName: modName:
doesFileExist (baseByModuleName modName) (moduleToFile modName);
# Lists all module dependencies, not limited to modules existing in this
# project
listAllModuleImportsJSON = base: modName:

View File

@ -43,10 +43,17 @@ rec {
(pkgSpec: pkgSpec.packageDependencies)
(flattenPackages topPkgSpec);
# TODO: nub
allTransitiveGhcOpts = topPkgSpec:
lib.lists.concatMap
(pkgSpec: pkgSpec.packageGhcOpts)
(flattenPackages topPkgSpec);
# Returns the first package spec that contains a module with given name. If
# none is found, returns the supplied default value.
pkgSpecByModuleName = pkgs: def: modName:
# Traverses all transitive packages and returns the first package spec that
# contains a module with given name. If none is found, returns the supplied
# default value.
pkgSpecByModuleName = topPkgSpec: def: modName:
( lib.findFirst
(pkgSpec:
lib.lists.elem
@ -54,6 +61,6 @@ rec {
(listModulesInDir pkgSpec.packageBase)
)
def
pkgs
(flattenPackages topPkgSpec)
);
}

14
snack-lib/wrapper.nix Normal file
View File

@ -0,0 +1,14 @@
{ snackNix
, nixpkgs ? null
}:
let
pkgs =
if nixpkgs == null
then import <nixpkgs> {}
else import nixpkgs {};
snack = pkgs.snack-lib;
in
{
build = (snack.executable (import snackNix)).build;
ghci = (snack.executable (import snackNix)).ghci;
}

View File

@ -1,13 +1,10 @@
let
pkgs = import ../../nix {};
snack = pkgs.snack-lib;
my-lib = snack.library
my-lib =
{ src = ./src;
dependencies = [ "conduit" ];
};
in
snack.executable
{ main = "Foo";
src = ./app;
dependencies = [ my-lib "conduit" ];
}
{ main = "Foo";
src = ./app;
dependencies = [ my-lib "conduit" ];
}

View File

@ -3,12 +3,12 @@
set -euo pipefail
snack build
snack run | diff golden -
$SNACK build
$SNACK run | diff golden -
TMP_FILE=$(mktemp)
capture_io "$TMP_FILE" main | snack ghci
capture_io "$TMP_FILE" main | $SNACK ghci
diff golden $TMP_FILE
rm $TMP_FILE

View File

@ -1,9 +1,4 @@
let
pkgs = import ../../nix {};
snack = pkgs.snack-lib;
in
snack.executable
{ main = "Foo";
src = ./src;
dependencies = ["conduit"];
}
{ main = "Foo";
src = ./src;
dependencies = ["conduit"];
}

View File

@ -3,12 +3,12 @@
set -euo pipefail
snack build
snack run | diff golden -
$SNACK build
$SNACK run | diff golden -
TMP_FILE=$(mktemp)
capture_io "$TMP_FILE" main | snack ghci
capture_io "$TMP_FILE" main | $SNACK ghci
diff golden $TMP_FILE
rm $TMP_FILE

View File

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

View File

@ -3,12 +3,12 @@
set -euo pipefail
snack build -f code/snack.nix
snack run -f code/snack.nix | diff golden -
$SNACK build -f code/snack.nix
$SNACK run -f code/snack.nix | diff golden -
TMP_FILE=$(mktemp)
capture_io "$TMP_FILE" main | snack -f code/snack.nix ghci
capture_io "$TMP_FILE" main | $SNACK -f code/snack.nix ghci
diff golden $TMP_FILE
rm $TMP_FILE

View File

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

View File

@ -3,12 +3,12 @@
set -euo pipefail
snack build
snack run | diff golden -
$SNACK build
$SNACK run | diff golden -
TMP_FILE=$(mktemp)
capture_io "$TMP_FILE" main | snack ghci
capture_io "$TMP_FILE" main | $SNACK ghci
diff golden $TMP_FILE
rm $TMP_FILE

View File

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

View File

@ -3,12 +3,12 @@
set -euo pipefail
snack build
snack run | diff golden -
$SNACK build
$SNACK run | diff golden -
TMP_FILE=$(mktemp)
capture_io "$TMP_FILE" main | snack ghci
capture_io "$TMP_FILE" main | $SNACK ghci
diff golden $TMP_FILE
rm $TMP_FILE

View File

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

View File

@ -3,12 +3,12 @@
set -euo pipefail
snack build
snack run | diff golden -
$SNACK build
$SNACK run | diff golden -
TMP_FILE=$(mktemp)
capture_io "$TMP_FILE" main | snack ghci
capture_io "$TMP_FILE" main | $SNACK ghci
diff golden $TMP_FILE
rm $TMP_FILE