mirror of
https://github.com/nmattia/snack.git
synced 2025-01-06 04:25:30 +03:00
major refactor
This commit is contained in:
parent
d414ace1ee
commit
cc2bf83650
41
bin/snack
41
bin/snack
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ END_HEREDOC
|
||||
|
||||
export -f capture_io
|
||||
|
||||
export SNACK="snack -n $(readlink -f ./nix)"
|
||||
|
||||
fail() {
|
||||
echo "ERROR: $*"
|
||||
exit 1
|
||||
|
@ -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
|
||||
;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
14
snack-lib/wrapper.nix
Normal 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;
|
||||
}
|
@ -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" ];
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"];
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 []);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 []);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 []);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 []);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user