Skip to content

Instantly share code, notes, and snippets.

@codebje
Created August 7, 2018 00:24
Show Gist options
  • Save codebje/000df013a2a4b7c10d6014d8bf7bccf3 to your computer and use it in GitHub Desktop.
Save codebje/000df013a2a4b7c10d6014d8bf7bccf3 to your computer and use it in GitHub Desktop.
Build a multi-project Cabal application with Nix
with builtins; rec {
cabalProjects = listToAttrs (if pathExists ./cabal.project
then projectParse
else [ { name = baseNameOf ./.; value = ./.; } ] );
projectParse = let
contents = readFile ./cabal.project;
trimmed = replaceStrings ["packages:" " "] ["" ""] contents;
packages = filter (x: isString x && x != "") (split "\n" trimmed);
package = p: substring 0 (stringLength p - 1) p;
paths = map (p: let p' = package p; in { name = p'; value = toPath (./. + "/${p'}"); } ) packages;
in paths;
}.cabalProjects
{forShell ? false}:
let
pkgs = import ./nixpkgs.nix {};
ghc = pkgs.haskell.packages.ghc822;
targets = import ./cabal.nix;
haskellPackages = ghc.extend (pkgs.lib.composeExtensions
(pkgs.haskell.lib.packageSourceOverrides (targets // {
# any version overrides or submodule package dependencies here
# some-package = "0.2.0.0"; # fetch specific hackage version
# some-package = ./dir/subproject; # git submodule packages
}))
(self: super: {
ghcWithPackages = p: super.ghcWithPackages (
# I like to have ghci-pretty and ghcid available in my nix-shell
f: p f ++ (if forShell then [ f.cabal-install f.ghci-pretty f.ghcid ] else [])
);
# any fetch/overrides go here
# some-package = pkgs.haskell.lib.dontCheck (self.callCabal2nix "some-package" (pkgs.fetchFromGitHub { ... }) {});
# some-package = pkgs.haskell.lib.overrideCabal super.some-package (drv: { patches = (drv.patches or [ ... ]); });
})
);
buildSet = pkgs.lib.foldl (ps: p: ps // { ${p.pname} = p; }) {} packages;
packages = map (t: haskellPackages.${t} ) (builtins.attrNames targets);
tools = [ pkgs.pkgconfig ];
in
if forShell
then haskellPackages.shellFor { packages = _: packages; buildInputs = tools; }
else buildSet
import ./. { forShell = true; }
@ip1981
Copy link

ip1981 commented Jun 4, 2020

This could be much simpler:

cabal.project:

packages: ./*/*.cabal

default.nix:

#...
localHaskellPackages =
    let
      islocal = n: t: !lib.hasPrefix "." n && t == "directory";
      files = lib.filterAttrs islocal (builtins.readDir ./.);
    in lib.mapAttrs (n: _: fltsrc (./. + "/${n}")) files;
#...

Full setup => https://github.com/ip1981/hakyll-template/tree/master/compiler

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment