Recommended way to use `cabal freeze` for an executable?
- Dominant language
- Haskell
- Stars
- 1.7k
- Forks
- 750
- Avg merge
- 4d 3h
- Merged PRs (30d)
- 28
Description
Having used Javascript's NPM in the past, I like it that `cabal` has `freeze` option, to create a freeze file, which from what I understand, is similar to package.lock.json in npm world.
Since I have a Haskell executable that has multiple team members working on it + gets built in the CI, I would like to use freeze file to make build reproducible -> meaning that when same git commit is executed on CI or on machine of developer A or machine of developer B, they are all guaranteed to get the same result. This is how package.lock.json is used also. So it doesn't really matter which dependency bounds are specified in myproject.cabal, nor does it matter if new patches were released for the packages we use in the project -> all that matters is the freeze file.
From what I understood, good workflow for this would be:
- When developing locally, when you want to in any way update dependencies used in the project, you should run `cabal freeze` once you are done. So for example, you will modify the version boundaries for some package in myproject.cabal, or you will add a new dependency, or remove an existing one, or do `cabal update` and want to get patches -> whatever you do, at the end you should do `cabal freeze`, so that these changes are reflected in the freeze file.
One thing I wasn't sure about though is: does `cabal` actually use only `cabal.project.freeze` when `cabal.project.freeze` exists, does that happen by default? Testing it out locally, and googling about it, I developed a notion that it doesn't use exclusively freeze file, or maybe doesn't use it at all, at least not by default. But if that is so, what is the purpose of freeze file?
When I say testing locally, I mean that I generate freeze file with `cabal freeze`, run `cabal build`, it says it is up to date, but then if I update some dependency bound in myproject.cabal and run `cabal build` again, it will rebuild! While I would expect it to ignore the change, due to using freeze file.
Another question: is there a way to run `cabal freeze` automatically on any change in dependencies, the same way `package.lock.json` is generated automatically?
Also, https://cabal.readthedocs.io/en/3.6/cabal-package.html?highlight=freeze#freezing-dependency-versions
-> it says output is cabal.config, but that is not correct is it? Isn't output cabal.project.freeze ?
EDIT:
TODO (for the PR I would love to create at the end of this):
- [ ] Mention in docs that although `cabal build` will do a bit of work if you modify .cabal, it will not produce a new build, it will still be the same old build (due to the freeze file). It just looks like it is doing smth new, because cabal file got touched.
- [ ] Fix [the mention of cabal.config being output of freeze](https://cabal.readthedocs.io/en/3.6/cabal-package.html?highlight=freeze#freezing-dependency-versions) -> it should say it returns `cabal.project.freeze`.
- [ ] Make it clear, somewhere in docs, that dependency versions from freeze file are combined with other files, which effectively results in dependency versions from freeze file are the ones that dictate what will be installed, resulting in reproducibility. Emphasize that this way freeze file becomes a part of project configuration and is by default used in all cabal operations -> there is nothing we need to do to use it, same as there is nothing we need to do to use `cabal.project`.
- [ ] Describe the standard workflow for dealing with freeze files, when developing an executable (when to run `cabal freeze`, when to delete freeze file, should it be committed, ...). Consider discussing executable vs library use cases (how it is not that important for a library) -> not sure if that is too opinionated though, but I have seen that opinion reiterated on multiple blog posts.
Contributor guide
Assessment
This issue has not been assessed yet.