From df1d3fe1185e23f8ced9c49f466bdc23f4aea4b2 Mon Sep 17 00:00:00 2001 From: tegwick Date: Thu, 30 Apr 2026 17:01:02 +0200 Subject: [PATCH] fix(build): fix 8-space indent for TypesPart1/2 cabal entries (Cabal rejects 4-space) --- flake.nix | 136 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 55 deletions(-) diff --git a/flake.nix b/flake.nix index 1f295c7..4917809 100644 --- a/flake.nix +++ b/flake.nix @@ -18,61 +18,7 @@ systems = import systems; imports = [ ihp.flakeModules.default ]; - # GHC 9.10.3 crash fix: Generated.Types imports 119 modules, pushing the - # combined interface-file read past a ~287 MB binary-deserialization limit. - # - # inter-hub-models is NOT a named attribute in haskellPackages — IHP creates - # it as a local derivation via callCabal2nix. We intercept at callCabal2nix: - # when called with name "inter-hub-models", we add a postUnpack phase that - # injects TypesPart1/TypesPart2 and replaces Types.hs with a thin wrapper. - # - # Applied to both haskellPackages (IHP's modified default set) and - # haskell.packages.ghc910 (the specific GHC version, whichever IHP uses). - nixpkgs.overlays = [ - (let - patchCallCabal2nix = hsPackages: hsPackages.extend (hfinal: hprev: { - callCabal2nix = name: src: args: - let drv = hprev.callCabal2nix name src args; - in if name == "inter-hub-models" - then drv.overrideAttrs (old: { - postUnpack = (old.postUnpack or "") + '' - cp ${./build/Generated/TypesPart1.hs} \ - "$sourceRoot/build/Generated/TypesPart1.hs" - cp ${./build/Generated/TypesPart2.hs} \ - "$sourceRoot/build/Generated/TypesPart2.hs" - printf '%s\n' \ - '-- Split wrapper: GHC 9.10.3 interface-file overflow workaround.' \ - 'module Generated.Types (' \ - ' module Generated.TypesPart1,' \ - ' module Generated.TypesPart2' \ - ' ) where' \ - 'import Generated.TypesPart1' \ - 'import Generated.TypesPart2' \ - > "$sourceRoot/build/Generated/Types.hs" - cabal_file=$(ls "$sourceRoot"/*.cabal | head -1) - awk '/Generated\.LearningInsightInclude/{ - print - print " Generated.TypesPart1" - print " Generated.TypesPart2" - next - }{print}' "$cabal_file" > /tmp/patched-models.cabal - mv /tmp/patched-models.cabal "$cabal_file" - ''; - }) - else drv; - }); - in final: prev: { - # IHP likely rewrites haskellPackages to point to GHC 9.10.3; cover both. - haskellPackages = patchCallCabal2nix prev.haskellPackages; - haskell = prev.haskell // { - packages = prev.haskell.packages // { - ghc910 = patchCallCabal2nix prev.haskell.packages.ghc910; - }; - }; - }) - ]; - - perSystem = { pkgs, config, ... }: { + perSystem = { pkgs, config, lib, ... }: { ihp = { appName = "inter-hub"; enable = true; @@ -145,6 +91,86 @@ # PostgreSQL extensions # services.postgres.extensions = extensions: [ extensions.postgis ]; + # GHC 9.10.3 crash fix: Generated.Types imports 119 modules, exceeding + # the ~287 MB interface-file binary-deserialization limit. + # + # pkgs is built from `import nixpkgs { overlays = devenv.shells.default.overlays; }`. + # IHP adds ihp.overlays.default to this list, which sets + # pkgs.ghc = haskellPackages.override { overrides = ihpOverrides }. + # We extend pkgs.ghc with a mkDerivation override (lib.mkAfter ensures + # we run after IHP's overlay, so prev.ghc is already IHP's package set). + # When pname == "inter-hub-models", postUnpack replaces the monolithic + # Types.hs with a thin re-export wrapper and ensures TypesPart1/TypesPart2 + # are present and listed in the cabal. + overlays = lib.mkAfter [ + (final: prev: { + ghc = prev.ghc.extend (hfinal: hprev: { + mkDerivation = args: + let drv = hprev.mkDerivation args; + in if (args.pname or "") == "inter-hub-models" + then drv.overrideAttrs (old: { + # Splits the monolithic Generated.Types (119 imports, ~287 MB + # interface-file overflow in GHC 9.10.3) into two halves. + # All awk/printf: no external file deps, no git-tracking required. + postUnpack = (old.postUnpack or "") + '' + _types="$sourceRoot/build/Generated/Types.hs" + + # TypesPart1: first half of modules + awk 'BEGIN{n=0} /^import Generated\./{n++; mods[n]=$2} END{ + half=int(n/2)+1 + print "-- Split: GHC 9.10.3 interface-file overflow workaround." + print "module Generated.TypesPart1 (" + for(i=1;i<=half;i++) { + if(i "$sourceRoot/build/Generated/TypesPart1.hs" + + # TypesPart2: second half of modules + awk 'BEGIN{n=0} /^import Generated\./{n++; mods[n]=$2} END{ + half=int(n/2)+1 + print "-- Split: GHC 9.10.3 interface-file overflow workaround." + print "module Generated.TypesPart2 (" + for(i=half+1;i<=n;i++) { + if(i "$sourceRoot/build/Generated/TypesPart2.hs" + + # Thin wrapper replaces the monolithic Types.hs + printf '%s\n' \ + '-- Split wrapper: GHC 9.10.3 interface-file overflow workaround.' \ + 'module Generated.Types (' \ + ' module Generated.TypesPart1,' \ + ' module Generated.TypesPart2' \ + ' ) where' \ + 'import Generated.TypesPart1' \ + 'import Generated.TypesPart2' \ + > "$_types" + + # Add TypesPart1/TypesPart2 to cabal exposed-modules if absent. + # Write to same dir (not /tmp which is size-limited in sandbox). + _cabal=$(ls "$sourceRoot"/*.cabal | head -1) + if ! grep -q 'Generated\.TypesPart1' "$_cabal"; then + awk '/Generated\.LearningInsightInclude/{ + print + print " Generated.TypesPart1" + print " Generated.TypesPart2" + next + }{print}' "$_cabal" > "$_cabal.new" + mv "$_cabal.new" "$_cabal" + fi + ''; + }) + else drv; + }); + }) + ]; + # Resource limits for constrained host (2 CPU, ~3.8 GiB RAM). # -A32m: smaller minor heap (reduces GC pressure). # -M2g: hard heap ceiling (prevents OOM on large compiles).