Revamp flake.nix to use haskell-flake (nix build / nix run)#11707
Conversation
Build the local pandoc packages (pandoc, pandoc-cli, pandoc-lua-engine, pandoc-server) via haskell-flake (https://haskell.nixos.asia). nix build # -> the pandoc executable (from pandoc-cli) nix run # runs it cabal.project's source-repository-package (texmath) and the dependency versions that nixpkgs ships too old for pandoc 3.10 are overridden here.
Builds the flake (`nix build .#default`) on ubuntu-latest and macos-latest, caching the Nix store between runs.
|
@jgm I'll undraft this PR once it is ready for review. In the meanwhile, could you please approve the Github workflows? EDIT: Not critical though, as I got Claude to do it on my fork:
|
|
One design question before taking this further: how would you like the flake to handle dependencies that nixpkgs ships too old (or not at all) for pandoc 3.10? nixpkgs' Haskell set currently lags pandoc's Three ways to maintain this going forward — which do you prefer?
This mostly determines who carries the update burden and how closely the flake tracks your releases, so your preference would steer the rest of the PR. |
|
Thanks for doing this and for the detailed writeup! The thing I don't like about this (not necessarily a deal-breaker) is the need to manually track versions. We already have to do something like this in stack.yaml, and it's a pain; I've considered removing stack.yaml because of it. I need to think about the costs and benefits. I didn't understand what you said here:
I didn't see the special versions needed for the wasm32 build listed in the flake? |
What would you use for pandoc development without stack.yaml? Direct cabal, or would you switch to Nix primarily for development? In any case, I'm happy to assist with the Nix related stuff.
Do we need the flake to build the wasm version as well? I've explicitly ignored it for now. |
…truth) Rather than hand-maintaining a version map, parse stack.yaml's extra-deps at eval time (IFD: yaml -> json) so the flake follows the same pins pandoc already maintains there. On a release, bumping stack.yaml updates the flake automatically. Only a small nixpkgs-baseline gap (hslua-core/classes/aeson, which stack's LTS resolver already ships new enough) remains pinned flake-side. The texmath source-repository-package is also derived from stack.yaml's git entry, replacing the dedicated texmath flake input.
|
In c9e7c50 the flake now derives its dependency overrides (and the texmath git pin) from stack.yaml's extra-deps, parsed at eval time — single source of truth, so bumping stack.yaml on a release updates the flake automatically. Only a 3-package gap (hslua-core/classes/aeson) stays pinned flake-side, since your LTS already ships those new enough but nixpkgs doesn't. |
I'd just use cabal. It has worked well for a long time and I haven't used stack in ages. I will check out your changes here. If it just requires manual intervention on stack.yaml, which I already do, then I think we might have a winner! |
| # are not pinned in stack.yaml but still need overriding here. | ||
| hslua-core = "2.3.2.1"; | ||
| hslua-classes = "2.3.2"; | ||
| hslua-aeson = "2.3.2"; |
There was a problem hiding this comment.
I wonder if it would be less fragile to just add these to stack.yaml with a comment to check the nixpkgs version (with a URL for where to look) before removing the lines?
There was a problem hiding this comment.
I added these to stack.yaml so that this can be simplified.
| # The package name is taken from the repo basename. | ||
| gitSources = lib.listToAttrs (map | ||
| (d: lib.nameValuePair | ||
| (lib.removeSuffix ".git" (baseNameOf d.git)) | ||
| { source = builtins.fetchGit { url = d.git; rev = d.commit; allRefs = true; }; }) | ||
| (builtins.filter builtins.isAttrs stackExtraDeps)); |
There was a problem hiding this comment.
What if the repo basename is different from package name? E.g. my typst-hs, where the package name is typst. This is not uncommon for the pandoc deps I pin to git commits. Another example is the skylighting dependencies. They all live in one repository, with several packages in different subdirectories. This latter problem could be avoided if the stack subdirs is parsed too.
| # The sub-packages' `COPYING.md` is a `../COPYING.md` symlink that | ||
| # dangles once the sub-directory is isolated as a source, breaking | ||
| # the `license-file` copy during install. Replace it with the real | ||
| # file from the repo root. |
There was a problem hiding this comment.
I'm open to replacing these symlinks with regular files if they are troublesome. That would simplify this.
| # pandoc 3.10's dependencies (citeproc 0.13, typst 0.10, commonmark | ||
| # 0.3, ...) are newer than the all-cabal-hashes snapshot pinned in | ||
| # nixpkgs, so `callHackage` can't find them. Point the package set at |
There was a problem hiding this comment.
Probably shouldn't hard-code versions in this comment, as it will get stale.
There was a problem hiding this comment.
Hm, but I guess this URL will need to be manually updated every time we rely on a new package from Hackage?
| # haskell-flake's cabal.project parser can't handle pandoc's | ||
| # `if arch(wasm32)` conditional blocks, so disable auto-discovery | ||
| # and list the packages explicitly. Sub-package sources are derived | ||
| # from the flake root (`self`) so they are recognized as local | ||
| # (i.e. under `projectRoot`). |
There was a problem hiding this comment.
Would this be a lot simpler if we didn't use if arch()? We could maybe switch to using the --project-file cabal option with a separate wasm-specific cabal project file for the wasm build.
| # The sub-package `.cabal` files reference `license-file: COPYING.md` | ||
| # via a `../COPYING.md` symlink that dangles once the sub-directory | ||
| # is isolated as a source; building from sdist would fail on it. The | ||
| # license file isn't needed to compile, so build from source directly. |
There was a problem hiding this comment.
There's this comment and the above comment about COPYING.md. Is one of them obsolete? I was a bit confused about the workaround. Again, the easiest solution might be getting rid of the symlink in our sources.
| # The git sources (texmath) and the bumped Hackage deps: skip | ||
| # tests/haddock and relax stale bounds against this GHC's boot libs. |
There was a problem hiding this comment.
Let's remove the reference to texmath, as that may change and we'll forget to change the comment.
| cabalFlags.embed_data_files = true; | ||
| # Skip the (slow) test suite and haddock in `nix build`. |
There was a problem hiding this comment.
Is there a need to set this, given that it is set to True by default in the cabal.project file ?
...but will make the new nix flake easier. See #11707.


Summary
Revamps
flake.nixto use haskell-flake so that:nix buildbuilds thepandocexecutable (frompandoc-cli)nix runruns itnix developgives a dev shell (cabal, HLS, the wasm toolchain, the various profiling/validation tools — unchanged from before)This is a fresh take on the stale #9952.
Verified end-to-end from a clean checkout on both platforms (
nix build+nix run -- --version+ a markdown→HTML conversion):nix buildnix run -- --version→pandoc 3.10,+server +luaA
NixGitHub Actions workflow builds the flake onubuntu-latestandmacos-latest.Notable points
cabal.projectparser can't handle theif arch(wasm32)conditional blocks, so the packages are listed explicitly in the flake instead of auto-discovered.all-cabal-hashesis too old for pandoc 3.10's dependency versions, so the flake points the Haskell package set at a recent snapshot.asciidoc, not at all) for pandoc 3.10'sbuild-dependsare pinned to the highest in-range Hackage versions (collected in onebumpedDepsmap):typst,citeproc,commonmark*,emojis,djot,pandoc-types,asciidoc, and thehslua2.5 family.texmathuses thesource-repository-packagegit pin via a flake input.COPYING.mdis a../COPYING.mdsymlink that dangles once a sub-directory is isolated as a source; the flake builds them from source (not sdist) and copies the real license file in.Opening as a draft for discussion (e.g. whether to track the fast-moving pandoc-ecosystem deps as flake inputs instead of Hackage version pins).
🤖 Generated with Claude Code