diff options
author | Ben Sima <ben@bsima.me> | 2021-07-23 14:28:35 -0400 |
---|---|---|
committer | Ben Sima <ben@bsima.me> | 2021-11-26 13:47:37 -0500 |
commit | 0264f4a5dc37b16f872e6fa92bd8f1fc1e2b1826 (patch) | |
tree | db66845496f21afe845abaa23546b82be9c8adf0 /Biz/Bild.nix | |
parent | 7f311fd420e92b6d90007fdd3b2d843e6e1752c3 (diff) |
Automatically detect Haskell dependencies
This parses the files contents for imports, then uses ghc-pkg to lookup the
package that provides the module. Now I can do that analysis in Haskell instead
of nix, which is much easier to code with.
Diffstat (limited to 'Biz/Bild.nix')
-rw-r--r-- | Biz/Bild.nix | 104 |
1 files changed, 56 insertions, 48 deletions
diff --git a/Biz/Bild.nix b/Biz/Bild.nix index a3584ae..3cd5026 100644 --- a/Biz/Bild.nix +++ b/Biz/Bild.nix @@ -2,85 +2,97 @@ let - inherit (nixpkgs) lib stdenv; ghcCompiler = "ghc884"; ghcjsCompiler = "ghcjs86"; # provided by .envrc root = builtins.getEnv "BIZ_ROOT"; - # general functions to put in a lib - lines = s: lib.pipe s [ - (builtins.split "\n") - (builtins.filter (x: builtins.typeOf x == "string")) - ]; - removeNull = ls: builtins.filter (x: x != null) ls; - selectAttrs = deps: packageSet: - lib.attrsets.attrVals deps packageSet; + nixpkgs.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; + # 44 = lib.strings.stringLength "/nix/store/gia2r9mxhc900y1m97dlmr1g3rm3ich3-" + dropNixStore = s: nixpkgs.lib.strings.substring 44 (nixpkgs.lib.strings.stringLength s) s; + haskellDeps = hpkgs: import ./Bild/Deps/Haskell.nix hpkgs; mkGhcPackageSet = nixpkgs.haskell.packages.${ghcCompiler}.ghcWithHoogle; #mkGhcjsPackageSet = nixpkgs.haskell.packages.${ghcjsCompiler}.ghcWithPackages; in rec { - # 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 = lib.pipe content [ - lines - (map (builtins.match "^-- : out ([[:alnum:]._-]*)$")) - removeNull - lib.lists.flatten - builtins.head - ]; - # collect all of the ': dep' declarations - deps = lib.pipe content [ - lines - (map (builtins.match "^-- : dep ([[:alnum:]._-]*)$")) - removeNull - lib.lists.flatten - ]; - # collect ': sys' declarations - sysdeps = lib.pipe content [ - lines - (map (builtins.match "^-- : sys ([[:alnum:]._-]*)$")) - removeNull - lib.lists.flatten - ]; + inherit (nixpkgs) lib stdenv pkgs sources; + + # a standard nix build for `bild` - this should be the only hand-written + # builder we need + bild = stdenv.mkDerivation { + name = "bild"; + src = ../.; + nativeBuildInputs = [ ghcPackageSetFull ]; + buildInputs = [ ghcPackageSetFull nixpkgs.makeWrapper ]; + propagatedBuildInputs = [ ghcPackageSetFull ]; + strictDeps = true; + buildPhase = '' + mkdir -p $out/bin + ghc \ + -Werror \ + -i. \ + --make Biz/Bild.hs \ + -main-is Biz.Bild \ + -o $out/bin/bild + ''; + installPhase = '' + wrapProgram $out/bin/bild --prefix PATH : ${lib.makeBinPath [ ghcPackageSetFull ]} + ''; }; + # wrapper around bild + runBildAnalyze = main: stdenv.mkDerivation { + name = "bild-analysis"; + src = ../.; + USER = "nixbld"; + HOSTNAME = "nix-sandbox"; + BIZ_ROOT = "$src"; + buildPhase = '' + set -eux + mkdir $out + : analyzing with bild + ${bild}/bin/bild --analyze ${main} 1> $out/analysis.json 2> $out/stderr + set +eux + ''; + installPhase = "exit 0"; + }; + + # gather data needed for compiling by analyzing the main module + analyze = main: + builtins.head + (lib.trivial.importJSON + (runBildAnalyze main + "/analysis.json")); + ghcPackageSetFull = mkGhcPackageSet haskellDeps; ghc = main: let data = analyze main; - ghc = mkGhcPackageSet (hp: selectAttrs data.deps hp); + ghc = mkGhcPackageSet (hp: selectAttrs data.langdeps hp); + module = lib.strings.concatStringsSep "." data.namespace.path; in stdenv.mkDerivation { - name = data.module; + name = module; src = ../.; nativeBuildInputs = [ ghc ] ++ selectAttrs data.sysdeps nixpkgs.pkgs; strictDeps = true; buildPhase = '' + set -eux mkdir -p $out/bin - # compile with ghc + : compiling with ghc ${ghc}/bin/ghc \ -Werror \ -i. \ --make ${main} \ - -main-is ${data.module} \ + -main-is ${module} \ -o $out/bin/${data.out} ''; # the install process was handled above @@ -162,8 +174,4 @@ in rec { }; os = cfg: (nixpkgs.nixos (args: cfg)).toplevel; - - sources = nixpkgs.sources; - - pkgs = nixpkgs.pkgs; } |