{ nixpkgs }: with nixpkgs; let ghcCompiler = "ghc865"; ghcjsCompiler = "ghcjs86"; # provided by .envrc root = builtins.getEnv "BIZ_ROOT"; # general functions to put in a lib lines = s: lib.strings.splitString "\n" s; removeNull = ls: builtins.filter (x: x != null) ls; depsToPackageSet = packageSet: deps: lib.attrsets.attrVals deps packageSet; # returns true if a is a subset of b, where a and b are attrsets subset = a: b: builtins.all (x: builtins.elem x b) a; haskellDeps = import ./Deps/Haskell.nix; # gather data needed for compiling by analyzing the main module analyze = main: rec { # path to the module relative to the git root relpath = builtins.replaceStrings ["${root}/"] [""] (builtins.toString main); # Haskell-appropriate name of the module module = builtins.replaceStrings ["/" ".hs"] ["." ""] relpath; # file contents content = builtins.readFile main; # search for the ': out' declaration out = builtins.head (lib.lists.flatten (removeNull (map (builtins.match "^-- : out ([[:alnum:]._-]*)$") (lines content)))); # collect all of the ': dep' declarations deps = lib.lists.flatten (removeNull (map (builtins.match "^-- : dep ([[:alnum:]._-]*)$") (lines content))); sysdeps = lib.lists.flatten (removeNull (map (builtins.match "^-- : sys ([[:alnum:]._-]*)$") (lines content))); }; mkGhc = compiler: (deps: compiler (hp: if (subset deps haskellDeps) then depsToPackageSet hp deps else throw '' missing from nix/haskell-deps.nix: ${toString (lib.lists.subtractLists haskellDeps deps)} '')); ghc_ = mkGhc pkgs.haskell.packages.${ghcCompiler}.ghcWithHoogle; ghcjs_ = mkGhc pkgs.haskell.packages.${ghcjsCompiler}.ghcWithPackages; in { ghc = main: let data = analyze main; ghc = ghc_ data.deps; in stdenv.mkDerivation { name = data.module; src = ../../.; nativeBuildInputs = [ ghc ] ++ depsToPackageSet nixpkgs data.sysdeps; strictDeps = true; buildPhase = '' mkdir -p $out/bin # compile with ghc ${ghc}/bin/ghc \ -Werror \ -i. \ --make ${main} \ -main-is ${data.module} \ -o $out/bin/${data.out} ''; # the install process was handled above installPhase = "exit 0"; } // { env = ghc; }; ghcjs = main: let data = analyze main; ghcjs = ghcjs_ data.deps; in stdenv.mkDerivation { name = data.module; src = ../../.; nativeBuildInputs = [ ghcjs ]; strictDeps = true; buildPhase = '' mkdir -p $out/static # compile with ghcjs ${ghcjs}/bin/ghcjs \ -Werror \ -i. \ --make ${main} \ -main-is ${data.module} \ -o ${data.out} # optimize js output ${pkgs.closurecompiler}/bin/closure-compiler \ ${data.out}/all.js > $out/static/${data.out} ''; installPhase = "exit 0"; } // { env = ghcjs; }; env = mkShell { name = "bizdev"; buildInputs = [ # haskell deps (ghc_ haskellDeps) # ghcjs doesn't need everything, and many things fail to build (ghcjs_ [ "aeson" "clay" "containers" "miso" "protolude" "servant" "split" "string-quote" "text" "ghcjs-base" ]) # scheme deps nixpkgs.guile nixpkgs.inspekt3d nixpkgs.libfive # python deps (nixpkgs.python38.withPackages (p: [ p.black p.pylint ])) # tools nixpkgs.cmark nixpkgs.haskell.packages.${ghcCompiler}.fast-tags nixpkgs.figlet nixpkgs.hlint nixpkgs.lolcat nixpkgs.niv.niv nixpkgs.nixops nixpkgs.ormolu nixpkgs.python37Packages.black nixpkgs.python37Packages.pylint nixpkgs.wemux (pkgs.writeScriptBin "ftags" (builtins.readFile ../Ide/ftags.sh)) ]; shellHook = ". ${./ShellHook.sh}"; }; os = cfg: (nixos (args: cfg)).toplevel; }