diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..41fbeb0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +**/result diff --git a/nix/default.nix b/nix/default.nix new file mode 100644 index 0000000..12f1291 --- /dev/null +++ b/nix/default.nix @@ -0,0 +1,11 @@ +{ nixpkgs ? ./nixpkgs }: +import (import nixpkgs) { + config = { allowUnfree = true; }; + overlays = [ + (self: super: { snack-lib = import ../snack;} ) + (self: super: { snack = self.writeScriptBin "snack" + '' + ${self.nix}/bin/nix-build snack.nix + ''; }) + ]; +} diff --git a/nix/nixpkgs/default.nix b/nix/nixpkgs/default.nix new file mode 100644 index 0000000..992b009 --- /dev/null +++ b/nix/nixpkgs/default.nix @@ -0,0 +1,6 @@ +let + spec = builtins.fromJSON (builtins.readFile ./nixpkgs-src.json); + rev = spec.rev; + url = "https://github.com/${spec.owner}/${spec.repo}/archive/${spec.rev}.tar.gz"; +in + builtins.fetchTarball url diff --git a/nix/src.json b/nix/nixpkgs/nixpkgs-src.json similarity index 100% rename from nix/src.json rename to nix/nixpkgs/nixpkgs-src.json diff --git a/nix/update b/nix/update index 5ba0682..abe6370 100755 --- a/nix/update +++ b/nix/update @@ -5,8 +5,6 @@ # See https://gist.github.com/zimbatm/de5350245874361762b6a4dfe5366530 set -euo pipefail -cd "$(dirname "$0")" || exit 1 - branch=master owner=NixOS @@ -16,7 +14,7 @@ url=https://github.com/$owner/$repo/archive/$rev.tar.gz release_sha256=$(nix-prefetch-url --unpack "$url") -cat < {}; - nixpkgs = _nixpkgs.fetchFromGitHub (_nixpkgs.lib.importJSON ./nix/src.json); - pkgs = import nixpkgs {config={}; overlays=[];}; + pkgs = import (../nix) {}; # Takes a (string) filepath and creates a derivation for that file (and for # that file only) @@ -13,17 +12,26 @@ let topLevel = (builtins.toString base) + "/"; actual = (pkgs.lib.strings.removePrefix topLevel path); expected = file; - in expected == actual; + in + (expected == actual) || + (type == "directory" && (pkgs.lib.strings.hasPrefix actual expected)); + mod = fileToModule file; in pkgs.stdenv.mkDerivation { - name = file; + name = mod; src = builtins.filterSource (pred file) base; - builder = pkgs.writeScript (file + "-builder") + builder = pkgs.writeScript (mod + "-builder") # TODO: make sure the file actually exists and that there's only one '' + echo "Singling out module ${mod} (file is ${file})" source $stdenv/setup mkdir -p $out - cp -a $src/* $out/ + echo "Running: cp $src/${file} $out/${file}" + echo "Listing $src" + ls $src/**/* + mkdir -p $(dirname $out/${file}) + cp $src/${file} $out/${file} + echo "Done: Singling out module ${mod} (file is ${file})" ''; }; @@ -36,6 +44,13 @@ let moduleToFile = mod: (pkgs.lib.strings.replaceChars ["."] ["/"] mod) + ".hs"; + moduleToObject = mod: + (pkgs.lib.strings.replaceChars ["."] ["/"] mod) + ".o"; + + fileToModule = file: + pkgs.lib.strings.removeSuffix ".hs" + (pkgs.lib.strings.replaceChars ["/"] ["."] file); + singleOutModule = base: mod: singleOut base (moduleToFile mod); buildModule = base: mod: @@ -66,7 +81,7 @@ let echo "Compiling module ${mod.moduleName}" # Set a tmpdir we have control over, otherwise GHC fails, not sure why mkdir -p tmp - ghc -tmpdir tmp/ ${mod.moduleName}.hs -c \ + ghc -tmpdir tmp/ ${moduleToFile mod.moduleName} -c \ -outputdir $out \ 2>&1 echo "Done building module ${mod.moduleName}" @@ -84,16 +99,17 @@ 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 if x.moduleIsMain then "Main.o" - else x.moduleName + ".o"; + else moduleToObject x.moduleName; attrs1 = f attrs0 mod; f = acc: elem: if pkgs.lib.attrsets.hasAttr elem.moduleName acc then acc - # TODO: module path instead of module name - # TODO: can't use "moduleName.o" because some modules get - # renamed to "Main.o" else acc // { "${elem.moduleName}" = "${buildModule base elem}/${objectName elem}"; @@ -120,8 +136,8 @@ let ]; }; - # TODO: use ghc -M for module dependencies - modB = makeModuleSpec "B" [] false; - modA = makeModuleSpec "A" [modB] true; - -in linkModuleObjects ./. modA + ## TODO: use ghc -M for module dependencies +in + { + inherit linkModuleObjects makeModuleSpec; + } diff --git a/A.hs b/tests/flat/A.hs similarity index 100% rename from A.hs rename to tests/flat/A.hs diff --git a/B.hs b/tests/flat/B.hs similarity index 100% rename from B.hs rename to tests/flat/B.hs diff --git a/tests/flat/README.md b/tests/flat/README.md new file mode 100644 index 0000000..077a01e --- /dev/null +++ b/tests/flat/README.md @@ -0,0 +1,3 @@ +# Flat + +Makes sure that two modules, `A.hs` and `B.hs`, can be built into an executable diff --git a/tests/flat/snack.nix b/tests/flat/snack.nix new file mode 100644 index 0000000..9d45ae8 --- /dev/null +++ b/tests/flat/snack.nix @@ -0,0 +1,6 @@ +# This "snack" passing is ugly, figure out a nice way of passing snack-lib +with (import ../../nix {}).snack-lib; +let + modB = makeModuleSpec "B" [] false; + modA = makeModuleSpec "A" [modB] true; +in linkModuleObjects ./. modA diff --git a/tests/nested/Foo/A.hs b/tests/nested/Foo/A.hs new file mode 100644 index 0000000..d0fe9b9 --- /dev/null +++ b/tests/nested/Foo/A.hs @@ -0,0 +1,3 @@ +import Foo.B.C + +main = putStrLn var diff --git a/tests/nested/Foo/B/C.hs b/tests/nested/Foo/B/C.hs new file mode 100644 index 0000000..0e77cb9 --- /dev/null +++ b/tests/nested/Foo/B/C.hs @@ -0,0 +1,3 @@ +module Foo.B.C where + +var = "Hello, World!" diff --git a/tests/nested/README.md b/tests/nested/README.md new file mode 100644 index 0000000..8deb2cc --- /dev/null +++ b/tests/nested/README.md @@ -0,0 +1,4 @@ +# Nested + +Make sure that nested modules (e.g. `Foo.A` and `Foo.B.C`) can be built into an +executable diff --git a/tests/nested/snack.nix b/tests/nested/snack.nix new file mode 100644 index 0000000..e6345b7 --- /dev/null +++ b/tests/nested/snack.nix @@ -0,0 +1,6 @@ +# This "snack" passing is ugly, figure out a nice way of passing snack-lib +with (import ../../nix {}).snack-lib; +let + modB = makeModuleSpec "Foo.B.C" [] false; + modA = makeModuleSpec "Foo.A" [modB] true; +in linkModuleObjects ./. modA