Skip to content

Commit dc40e91

Browse files
committed
Update snapshot to 'nightly'
Instead of pinning the snapshot to a specific date, we set it to 'nightly', which should allow more flexibility i.e. users can build whichever ghc corresponds to the latest snapshot. This should hopefully decrease the chance of users running into issues with ghc minor version upgrades e.g. bounds errors. Snapshot updates that upgrade the ghc major version will almost certainly require manual intervention here, but failures will likely be caught by the CI job that builds everything with --dry-run, so there should be some warning.
1 parent bba2580 commit dc40e91

26 files changed

Lines changed: 389 additions & 90 deletions

.github/workflows/ci.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ jobs:
2929
- uses: actions/checkout@v4
3030
- uses: haskell-actions/setup@v2
3131
with:
32-
ghc-version: "9.10.3"
32+
# Should be the current stackage nightly, though this will likely go
33+
# out-of-date eventually, until a problem is reported.
34+
ghc-version: "9.12.3"
3335
- name: Configure
3436
run: |
3537
cabal configure --enable-tests --ghc-options -Werror

README.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ An impact assessment is due when
1414

1515
The procedure is as follows:
1616

17-
1. Rebase changes, mandated by your proposal, atop of `ghc-9.10` branch.
17+
1. Rebase changes, mandated by your proposal, atop the ghc branch (or tag) that corresponds to the current [stackage nightly](https://www.stackage.org/nightly). For example, if the latest snapshot ghc is `ghc-9.12.3`, we would want to rebase our changes on the `ghc-9.12.3-release` tag. See [GHC / Stack snapshot compatibility](#ghc--stack-snapshot-compatibility) for more info on choosing a good ghc.
1818

1919
2. Compile a patched GHC, say, `~/ghc/_build/stage1/bin/ghc`.
2020

@@ -36,6 +36,7 @@ The procedure is as follows:
3636
* You can interrupt `cabal` at any time and rerun again later.
3737
* Consider setting `--jobs` to retain free CPU cores for other tasks.
3838
* Full build requires roughly 7 Gb of free disk space.
39+
* If the build fails with an error about max amount of arguments in `gcc`, run again, but with smaller batch size. 250 worked well for me.
3940
4041
To get an idea of the current progress, we can run the following commands
4142
on the log file:
@@ -59,6 +60,46 @@ The procedure is as follows:
5960
6061
8. When everything finally builds, get back to CLC with a list of packages affected and patches required.
6162
63+
### GHC / Stack snapshot compatibility
64+
65+
#### GHC Minor update
66+
67+
As nightly changes ghc minor versions (e.g. `9.12.1 -> 9.12.3`), package bounds can change. This can be a problem because `clc-stackage` writes the snapshot's packages' version bounds as exact constraints to the generated `./generated/cabal.project.local`, to ensure we (transitively) build the same package version every time. While we attempt to mitigate such issues (boot packages' exact versions are ignored), it is possible for some to slip through.
68+
69+
User mitigations can include:
70+
71+
- Adding the package to [./excluded_pkgs.jsonc](excluded_pkgs.jsonc). The package will still be built as long as it is a (transitive) dependency of some other package in the snapshot, but will not have its exact bounds written to `cabal.project.local`.
72+
73+
- Manually downloading a snapshot (e.g. `https://www.stackage.org/nightly/cabal.config`), changing / removing the offending package(s), and supplying the file with the `--snapshot-path` param. Like `excluded_pkgs.jsonc`, this only impacts what is actually written to `cabal.project.local`.
74+
75+
- Adding constraints to `generated/cabal.project`. Even though we write most package versions as constraints, there is still some room for non-determinancy (hence, errors).
76+
77+
Boot packages are not written as exact versions, but it might be useful to write _some_ constraint e.g. `constraints: filepath > 1.5`.
78+
79+
We also might need to set some flags e.g. prevent cabal from setting the wrong automatic flag. For instance, depending on the resolver, cabal might try to build `bson` with the `_old-network` flag, which will not work with this package set, hence we disable it with `constraints: bson -_old-network`.
80+
81+
#### GHC Major update
82+
83+
When a snapshot upgrades the GHC *major* version, there is usually more work involved. In particular,
84+
85+
- New system dependencies will need to be added to the `flake.nix`.
86+
87+
- New packages will need to be added to `excluded_pkgs.jsonc` because e.g. the system deps are unreasonable or the packages are executables.
88+
89+
Until this is done, `clc-stackage` will likely fail. Such failures should hopefully be caught by CI that is run daily, but either way, please open an issue if `clc-stackage` seems out of date with stackage nightly.
90+
91+
While that is being resolved, the mitigations from the [previous section](#ghc-minor-update) may be useful.
92+
93+
#### Misc
94+
95+
The `flake.nix` line:
96+
97+
```nix
98+
compiler = pkgs.haskell.packages.ghc<vers>;
99+
```
100+
101+
can be a useful guide as to which GHC was last tested, as CI uses this ghc to build everything with `--dry-run`, which should report solver errors (e.g. bounds) at the very least.
102+
62103
### The clc-stackage exe
63104

64105
`clc-stackage` is an executable that will:

cabal.project

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
index-state: 2026-03-19T21:41:35Z
2-
31
packages: .
42

53
program-options

dev.md

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,28 +75,24 @@ The executable that actually runs. This is a very thin wrapper over `runner`, wh
7575

7676
## Updating to a new shapshot
7777

78-
1. Update to the desired snapshot:
78+
`clc-stackage` is based on `nightly` -- which changes automatically -- meaning we do not necessarily have to do anything when a new (minor) snapshot is released. On the other hand, *major* snapshot updates will almost certainly bring in new packages that need to be excluded, so there are some general "update steps" we will want to take:
7979

80-
```haskell
81-
-- CLC.Stackage.Parser.API
82-
stackageSnapshot :: String
83-
stackageSnapshot = "nightly-yyyy-mm-dd"
84-
```
80+
1. Modify [excluded_pkgs.json](excluded_pkgs.json) as needed. That is, updating the snapshot major verison will probably bring in some new packages that we do not want. The update process is essentially trial-and-error i.e. run `clc-stackage` as normal, and later add any failing packages that should be excluded.
8581

86-
2. Update the `index-state` in [cabal.project](cabal.project) and [generated/cabal.project](generated/cabal.project).
82+
2. Update `ghc-version` in [.github/workflows/ci.yaml](.github/workflows/ci.yaml).
8783

88-
3. Modify [excluded_pkgs.json](excluded_pkgs.json) as needed. That is, updating the snapshot will probably bring in some new packages that we do not want. The update process is essentially trial-and-error i.e. run `clc-stackage` as normal, and later add any failing packages that should be excluded.
84+
3. Update functional tests as needed i.e. exact package versions in `*golden` and `test/functional/snapshot.txt`.
8985

90-
4. Update references to the current ghc e.g.
86+
4. Optional: Update nix:
9187

92-
1. `ghc-version` in [.github/workflows/ci.yaml](.github/workflows/ci.yaml).
93-
2. [README.md](README.md).
88+
- Inputs (`nix flake update`).
89+
- GHC: Update the `compiler = pkgs.haskell.packages.ghc<vers>;` line.
90+
- Add to the `flake.nix`'s `ldDeps` and `deps` as needed to have the `nix` CI job pass. System libs available on nix can be found here: https://search.nixos.org/packages?channel=unstable.
9491

95-
5. Update functional tests as needed i.e. exact package versions in `*golden` and `test/functional/snapshot.txt`.
9692

97-
6. Optional: Update `clc-stackage.cabal`'s dependencies (i.e. `cabal outdated`).
93+
This job builds everything with `--dry-run`, so its success is a useful proxy for `clc-stackage`'s health. In other words, if the nix job fails, there is almost certainly a general issue (i.e. either a package should be excluded or new system dep is required), but if it succeeds, the package set is in pretty good shape (there may still be sporadic issues e.g. a package does not properly declare its system dependencies at config time).
9894

99-
7. Optional: Update nix inputs (`nix flake update`).
95+
5. Optional: Update `clc-stackage.cabal`'s dependencies (i.e. `cabal outdated`).
10096

10197
### Verifying snapshot
10298

excluded_pkgs.jsonc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@
270270
"midi-music-box",
271271
"misfortune",
272272
"mmark-cli",
273+
"mmark-ext", // ghc-syntax-highlighter
273274
"moffy-samples-gtk3",
274275
"moffy-samples-gtk3-run",
275276
"moffy-samples-gtk4",
@@ -359,6 +360,7 @@
359360
"sqlcli",
360361
"sqlcli-odbc",
361362
"sqlite-simple",
363+
"stakhanov", // hasql
362364
"stack-all",
363365
"stack-clean-old",
364366
"stack-templatizer",

generated/cabal.project

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
index-state: 2026-03-19T21:41:35Z
2-
31
-- should be an absolute path to your custom compiler
42
--with-compiler: /home/ghc/_build/stage1/bin/ghc
53

64
packages: .
75

86
optimization: False
97

10-
allow-newer:
11-
hoogle:crypton-connection,
12-
web-rep:transformers,
8+
-- The generated cabal.project.local has exact constraints for every (non-boot)
9+
-- package in the snapshot to ensure we build the same packages every time.
10+
-- We still want this to override individual package constraints e.g.
11+
-- web-rep has had an overly tight bound that excludes the transformers from
12+
-- the snapshot. The allow-newer ignores the error.
13+
allow-newer: *:*
14+
allow-older: *:*
1315

16+
constraints: bson -_old-network
1417
constraints: hlint +ghc-lib
1518
constraints: ghc-lib-parser-ex -auto
19+
constraints: path +os-string
1620
constraints: stylish-haskell +ghc-lib

src/CLC/Stackage/Builder.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module CLC.Stackage.Builder
55

66
-- * Misc
77
Batch.batchPackages,
8+
Process.cabalUpdate,
89
)
910
where
1011

src/CLC/Stackage/Builder/Process.hs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
module CLC.Stackage.Builder.Process
44
( buildProject,
5+
cabalUpdate,
56
)
67
where
78

@@ -122,6 +123,26 @@ buildProject env idx pkgs = do
122123

123124
addPackages = Set.union pkgsSet
124125

126+
-- | Runs "cabal update".
127+
cabalUpdate :: BuildEnv -> IO ()
128+
cabalUpdate env = do
129+
Logging.putTimeInfoStr env.hLogger "Running 'cabal update'"
130+
P.readProcessWithExitCode env.cabalPath ["update"] "" >>= \(ec, out, err) ->
131+
case ec of
132+
ExitSuccess -> pure ()
133+
ExitFailure _ -> do
134+
let msg =
135+
mconcat
136+
[ "Failed running 'cabal update': ",
137+
"Out: '",
138+
T.pack out,
139+
"', Err: '",
140+
T.pack err,
141+
"'"
142+
]
143+
Logging.putTimeErrStr env.hLogger msg
144+
throwIO ec
145+
125146
createCurrentLogsDir :: IO (OsPath, OsPath, OsPath)
126147
createCurrentLogsDir = do
127148
let dirPath = Paths.logsDir </> [osp|current-build|]

0 commit comments

Comments
 (0)