This project is organized into several libraries and a single executable. Roughly, the idea is:
- Download a snapshot
s
from stackage.org. - Prune
s
based on packages we know we do not want (e.g. system deps). - Generate a custom
generated.cabal
file for the given package set, and try to build it.
Futhermore, we allow for building subsets of the entire stackage package set with the --batch
feature. This will split the package set into disjoint groups, and build each group sequentially. The process can be interrupted at any time (e.g. CTRL-C
), and progress will be saved in a "cache" (json file), so we can pick up where we left off.
utils
is a library containing common utilities e.g. logging and hardcoded file paths.
parser
contains the parsing functionality. In particular, parser
is responsible for querying stackage's REST endpoint and retrieving the package set. That package set is then filtered according to excluded_pkgs.json. The primary function is:
-- CLC.Stackage.Parser
getPackageList :: IO [PackageResponse]
If you want to get the list of the packages to be built (i.e. stackage_snapshot - excluded_packages), load the parser into the repl with cabal repl parser
, and run the following:
-- CLC.Stackage.Parser
-- printPackageList :: Bool -> Maybe Os -> IO ()
λ. printPackageList True Nothing
This will write the package list used for each OS to pkgs_<os>.txt
.
builder
is responsible for building a given package set. The primary functions are:
-- CLC.Stackage.Builder
writeCabalProjectLocal :: NonEmpty Package -> IO ()
batchPackages :: BuildEnv -> NonEmpty (PackageGroup, Int)
buildProject :: BuildEnv -> Int -> PackageGroup -> IO ()
That is:
-
writeCabalProjectLocal
will be called once at start-up, and write the entire package set to acabal.project.local
'sconstraints
section. This ensures the same transitive deps are used every time. -
batchPackages
splits the entire package set into separate groups, based on the--batch
value. If--batch
is not given, then we will have a single group containing every package. -
buildProject
will write the given package group to the generated cabal file, and attempt to build it.
runner
orchestrates everything. The primary function is:
run :: Logging.Handle -> IO ()
Which takes in a logging handler (we use the handler pattern for testing), and then:
- Sets up the environment based on CLI args and previous cache data.
- Runs the parser and builder until it either finishes or is interrupted.
- Saves the current progress to the cache.
- Prints out a summary.
The reason this logic is a library function and not the executable itself is for testing.
The executable that actually runs. This is a very thin wrapper over runner
, which merely sets up the logging handler.
-
Update to the desired snapshot:
-- CLC.Stackage.Parser.API stackageSnapshot :: String stackageSnapshot = "nightly-2024-03-26"
-
Update the
index-state
in cabal.project and generated/cabal.project. -
Modify 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. -
Update references to the current ghc e.g.
ghc-version
in .github/workflows/ci.yaml.- README.md.
-
Optional: Update
clc-stackage.cabal
's dependencies (i.e.cabal outdated
). -
Optional: Update nix inputs (
nix flake update
).
There are two test suites, unit
and functional
. The latter actually runs all of the logic, though it uses the generalized runner:
runModifyPackages :: Logging.Handle -> ([Package] -> [Package]) -> IO ()
This allows us to limit the number of packages to something reasonable to build on CI.
If the functional tests fail, it can be difficult to see what the actual error is, given that the error message is in the logs, which will be deleted by default. To keep the logs and generated files, run with:
$ NO_CLEANUP=1 cabal test functional
Note that this only saves files from the last test, so if you want to examine test output for a particular test, you need to run only that test.