stack2nix
stack2nix copied to clipboard
Allow changing nixpkgs to update Haskell package versions
Stack2nix is cool if you have to maintain a stack.yaml
and want a reliable way to turn it into a nix file. However it does not work well as a migration tool yet.
For instance here is the haskell-ide-engine stack.yaml. Stack2nix outputs a 1.59MB nix file that pins all the haskell packages. This means you can't change nixpkgs to get different haskell packages versions (you will always get the ones stack would have chosen). This locks you into maintaining a stack.yaml file and running stack2nix
(instead of bumping nixpkgs
to a newer commit).
I think if stack2nix
took a nixpkgs ref as an input it could get much closer to the hand crafted translation. It could compare the nixpkgs derivations to the ones it would have output and only output the differences.
Here is an example of a by hand translation and I think something like stack2nix --migrate --nixpkgs '<nixpkgs>'
should be able to get pretty close to this:
with import <nixpkgs> { };
let
rootName = name: builtins.elemAt (lib.splitString "/" name) 0;
isValidFile = name: files: builtins.elem (rootName name) files;
relative = path: name: lib.removePrefix (toString path + "/") name;
onlyFiles = files: path: builtins.filterSource (name: type: isValidFile (relative path name) files) path;
ghc = (pkgs.haskell.packages.ghc843.extend (pkgs.haskell.lib.packageSourceOverrides {
haskell-ide-engine = onlyFiles ["LICENSE" "Setup.hs" "app" "haskell-ide-engine.cabal" "src" "test"] ./.;
hie-plugin-api = ./hie-plugin-api;
HaRe = ./submodules/HaRe;
cabal-helper = ./submodules/cabal-helper;
ghc-mod = ./submodules/ghc-mod;
ghc-mod-core = ./submodules/ghc-mod/core;
haskell-lsp = ./submodules/haskell-lsp;
haskell-lsp-types = ./submodules/haskell-lsp/haskell-lsp-types;
haskell-lsp-test = ./submodules/haskell-lsp-test;
leksah-server = ../leksah/vendor/leksah-server;
base-compat = "0.9.3";
cabal-plan = "0.3.0.0";
haddock-api = "2.20.0";
haddock-library = "1.6.0";
})).extend(self: super: {
hlint = haskell.lib.dontCheck super.hlint;
constrained-dynamic = haskell.lib.doJailbreak super.constrained-dynamic;
haddock-api = haskell.lib.dontCheck super.haddock-api;
haddock-library = haskell.lib.dontCheck (haskell.lib.dontHaddock super.haddock-library);
ghc-exactprint = haskell.lib.dontCheck super.ghc-exactprint;
leksah-server = haskell.lib.dontCheck super.leksah-server;
});
in {
inherit ghc;
shells = {
ghc = ghc.shellFor {
packages = p: [
p.haskell-ide-engine
p.hie-plugin-api
p.HaRe
p.cabal-helper
p.ghc-mod
p.ghc-mod-core
p.haskell-lsp
p.haskell-lsp-types
p.haskell-lsp-test
];
};
};
}
If ./
is included as package, the list of files passed to onlyFiles
should be added to prevent non package files from triggering builds (I made that list by running cabal sdist
and looking at the top level items in the .tar.gz
file it produced).
The main issue with mixing cabal2nix and stack is that they have different build plans. For example, cabal2nix always includes tests and benchmarks dependencies, while stack does only for packages in locations
section. There are many subtle differences how they use hackage as an api and findings show mixing the two is painful to get right. I'd actually like to use cabal2nix just as low-level library in #111 and stack do the whole build plan as it sees it. This would get rid of many issues that people face with stack2nix these days.
Of course, the above is doable if one wants to live with addressing those issues manually.
For example, cabal2nix always includes tests and benchmarks dependencies, while stack does only for packages in
locations
section.
Could a custom version of pkgs.haskell.lib.packageSourceOverrides
disable tests and benchmarks for everything except the except the packages it is overriding with callCabal2nix
?