Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache cabal2nix expr to avoid IFD #231

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions nix/build-haskell-package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,37 @@ let
name = "${name}";
inherit src;
};

callPackageKeepDeriver = src: args:
pkgs.haskell.lib.compose.overrideCabal
(orig: {
passthru = orig.passthru or { } // {
# When using callCabal2nix or callHackage, it is often useful
# to debug a failure by inspecting the Nix expression
# generated by cabal2nix. This can be accessed via this
# cabal2nixDeriver field.
cabal2nixDeriver = src;
};
})
(self.callPackage src args);

callCabal2nixWithOptions = name: src: expr: args:
pkgs.haskell.lib.compose.overrideCabal
(orig: {
inherit src;
})
(callPackageKeepDeriver expr args);
in

name: root:
name: root: expr:
lib.pipe root
[
# Avoid rebuilding because of changes in parent directories
(mkNewStorePath "source-${name}")
(x: log.traceDebug "${name}.mkNewStorePath ${x.outPath}" x)

(root: self.callCabal2nix name root { })
(x: log.traceDebug "${name}.cabal2nixDeriver ${x.cabal2nixDeriver.outPath}" x)
(root: callCabal2nixWithOptions name root expr { })
# (x: log.traceDebug "${name}.cabal2nixDeriver ${x.cabal2nixDeriver.outPath}" x)

# Make sure all files we use are included in the sdist, as a check
# for release-worthiness.
Expand Down
23 changes: 22 additions & 1 deletion nix/modules/project/outputs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,24 @@ in
);
};

gen-pkgset =
let
drv = pkgs.runCommandNoCC "cabal2nix-generated" { } (
"mkdir -p $out\n" +
builtins.concatStringsSep "\n" (
lib.mapAttrsToList (name: expr: "cp -a ${expr} $out/${name}.nix") config.packagesNix
)
);
in
pkgs.writeShellApplication {
name = "gen-pkgset";
runtimeInputs = [ pkgs.rsync ];
text = ''
set -x
mkdir -p .haskellSrc2nix
rsync -a --delete --chmod=u+rw ${drv}/ .haskellSrc2nix
'';
};
in
{
outputs = {
Expand All @@ -113,8 +131,11 @@ in

apps =
lib.mkMerge
(lib.mapAttrsToList (_: packageInfo: packageInfo.exes) config.outputs.packages);
(lib.mapAttrsToList (_: packageInfo: packageInfo.exes) config.outputs.packages ++ [{
gen-pkgset.program = gen-pkgset;
}]);
};

};
}

56 changes: 52 additions & 4 deletions nix/modules/project/packages/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,64 @@ in
build-haskell-package = import ../../../build-haskell-package.nix {
inherit pkgs lib self log;
};
callPackageKeepDeriver = src: args:
pkgs.haskell.lib.compose.overrideCabal
(orig: {
passthru = orig.passthru or { } // {
# When using callCabal2nix or callHackage, it is often useful
# to debug a failure by inspecting the Nix expression
# generated by cabal2nix. This can be accessed via this
# cabal2nixDeriver field.
cabal2nixDeriver = src;
};
})
(self.callPackage src args);
getOrMkPackage = name: cfg:
if lib.types.path.check cfg.source
then
log.traceDebug "${name}.callCabal2nix ${cfg.source}"
(build-haskell-package name cfg.source)
log.traceDebug "${name}.callCabal2nix[cached] ${cfg.source}"
(build-haskell-package name cfg.source "${project.config.projectRoot}/.haskellSrc2nix/${name}.nix")
else
log.traceDebug "${name}.callHackage ${cfg.source}"
(self.callHackage name cfg.source { });
log.traceDebug "${name}.callHackage[cached] ${cfg.source}"
(
# (self.callHackage name cfg.source { })
# callPackageKeepDeriver (self.hackage2nix name cfg.source) {}
callPackageKeepDeriver "${project.config.projectRoot}/.haskellSrc2nix/${name}.nix" { }
);
in
lib.mapAttrs getOrMkPackage project.config.packages;
};

# cabal2nix generated Nix expressions for packages
# uses `hackage2nix`
packagesNix = lib.mkOption {
default =
lib.mapAttrs
(name: cfg:
let
self = project.config.basePackages;
callCabal2nixWithOptionsExr = name: src: extraCabal2nixOptions:
let
filter = path: type:
pkgs.lib.hasSuffix ".cabal" path ||
baseNameOf path == "package.yaml";
in
self.haskellSrc2nix {
inherit name extraCabal2nixOptions;
src =
if pkgs.lib.canCleanSource src
then pkgs.lib.cleanSourceWith { inherit src filter; }
else src;
};
readCabal2NixExpr = drv:
"${builtins.trace drv.outPath drv}/default.nix";
in
readCabal2NixExpr (if lib.types.path.check cfg.source
# FIXME: Patch `src` to not point to nix store.
then callCabal2nixWithOptionsExr name cfg.source ""
else self.hackage2nix name cfg.source)
)
project.config.packages;
};
};
}
Loading