-
Notifications
You must be signed in to change notification settings - Fork 730
Improved docs on cabal freeze. #8053
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1017,24 +1017,70 @@ disambiguation purposes. Example: | |
| $ cabal repl bench:baz | ||
|
|
||
| Freezing dependency versions | ||
| """""""""""""""""""""""""""" | ||
|
|
||
| If a package is built in several different environments, such as a | ||
| development environment, a staging environment and a production | ||
| environment, it may be necessary or desirable to ensure that the same | ||
| dependency versions are selected in each environment. This can be done | ||
| with the ``freeze`` command: | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
| .. code-block:: console | ||
|
|
||
| $ cabal freeze | ||
|
|
||
| The command writes the selected version for all dependencies to the | ||
| ``cabal.config`` file. All environments which share this file will use | ||
| the dependency versions specified in it. | ||
| generates ``cabal.project.freeze`` file, which describes the exact dependency tree as it was resolved at that moment by Cabal. | ||
| This means it captures an exact version of every dependency, including dependencies of dependencies, recursively all the way. | ||
|
|
||
| Since ``cabal`` reads ``cabal.project.freeze`` when present, and takes into consideration the version constraints in it, | ||
| this means that by producing ``cabal.project.freeze`` you are guaranteed that every future ``cabal`` call will use the exact same set of dependencies, | ||
| regardless of any updates (even patches) that might get published for these dependencies in the meantime. | ||
| Therefore, we have effectively "frozen" the dependencies in place, making our build consistent and reproducible. | ||
|
|
||
| ``cabal.project.freeze`` is intended to be committed to the version control. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should warn about the fact
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An alternative could be only freeze the hackage index state, as commented here: #8059 (comment)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also i would note it also freezes cabal flags and it could drive to unexpected results: #7944
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, and it is also dependent on ghc version 🙂 : #7367
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And there is another request about makes docs clear on what to do when you have both a executable and a library: #5750.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Martinsos sorry, i dont want to scare you. I am reviewing the existing issues about freeze and it turns out it has several caveats.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hah @jneira, no worries, nothing to be scared of :D, I am glad you are sharing all this info as I wasn't aware of it! Let me play a bit more with Some questions immediately:
Btw, looking at different issues -> different GHC versions, different OS-es, it seems to me the proper solution might be in the direction of having per-environment (where environment is defined as combo of os, ghc and arch) freeze files. Meaning that user could define environments it cares about, and then on
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
well there are two kind of cabal flags, automatic and manual and that determines its freezing imo:
But |
||
|
|
||
| Do you need this? | ||
| """"""""""""""""" | ||
|
|
||
| Why would you want this? Don't we want to get minor updates of our dependencies, or at least patches, as soon as we can? | ||
| Well, although they shouldn't, it is possible that any kind of update introduces new bugs, performance issues, or some other kind of unexpected behaviour. | ||
| This is where ``cabal.project.freeze`` comes in, as it ensures that dependencies don't unexpectedly change. | ||
| You can still update your dependencies, but you have to do it on purpose, by modifying or by deleting and regenerating ``cabal.project.freeze`` file, | ||
| and in the meantime you are guaranteed no surprises will happen. | ||
|
|
||
| This consistency can be valuable as it ensures that all teammates, deployments, and continuous integration are installing the exactly same dependencies. | ||
| So if you are running and testing the code on your local machine, you are guaranteed that your teammate and your continuos integration will be running the exact same code, | ||
| and that at the end that exact same code will get deployed. | ||
|
|
||
| Usual use-case for using ``cabal freeze`` is when developing end-user code, for example an executable that you will distribute. | ||
| On the other hand, if you are developing a library, you will not want to distribute it together with the ``cabal.project.freeze`` file, as it would make it very hard for cabal to resolve dependencies for users of the library, since they would be too strict. | ||
|
|
||
| Common workflow | ||
| """"""""""""""" | ||
|
|
||
| Common workflow for using ``cabal freeze``, if you changed any dependencies in ``<yourproject>.cabal`` file or want to update their versions, is to delete ``cabal.project.freeze`` file (if it already exists) and run ``cabal freeze`` to generate fresh version of ``cabal.project.freeze``. | ||
|
|
||
| You might in some cases want to skip deletion of ``cabal.project.freeze``, but keep in mind that in that case ``cabal freeze`` will use existing ``cabal.project.freeze`` when resolving dependencies, therefore not updating any existing dependencies, only adding new ones. | ||
| If not sure, best to delete ``cabal.project.freeze`` first and then run ``cabal freeze``. | ||
|
|
||
| Finally, you will always want to commit the new ``cabal.project.freeze`` to the version control. | ||
|
|
||
| Ensuring everything is frozen | ||
| """"""""""""""""""""""""""""" | ||
|
|
||
| Since ``cabal`` reads both ``<yourproject>.cabal`` and ``cabal.project.freeze`` files and combines version constraints from them, you can get into a state where not all dependencies are frozen, i.e. if you add a dependency to ``<yourproject>.cabal`` but forget to regenerate ``cabal.project.freeze`` after it -> now this new dependency will not be frozen and might get updated unexpectedly. | ||
|
|
||
| To check if you are in such state, you can just run ``cabal freeze`` and check if ``cabal.project.freeze`` changed its contents -> if so, somebody forgot to regenerate ``cabal.project.freeze`` previously. This will also fix the problem at the same time. | ||
|
|
||
| To automate this check, you can make it a part of your continuous integration, or a part of your pre-commit hook. | ||
|
|
||
| Example of how this can be done via bash script: | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| [[ -f cabal.project.freeze ]] || exit 1 | ||
| OLD_FREEZE_SUM=$(md5sum cabal.project.freeze) | ||
| cabal freeze || exit 1 | ||
| NEW_FREEZE_SUM=$(md5sum cabal.project.freeze) | ||
| exit [[ "$NEW_FREEZE_SUM" == "$OLD_FREEZE_SUM" ]] | ||
|
|
||
|
|
||
| Generating dependency version bounds | ||
| """""""""""""""""""""""""""""""""""" | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
| Cabal also has the ability to suggest dependency version bounds that | ||
| conform to `Package Versioning Policy`_, which is | ||
|
|
@@ -1063,7 +1109,7 @@ For example, given the following dependencies specified in | |
| bar >= 1.1 && < 1.2 | ||
|
|
||
| Listing outdated dependency version bounds | ||
| """""""""""""""""""""""""""""""""""""""""" | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
| Manually updating dependency version bounds in a ``.cabal`` file or a | ||
| freeze file can be tedious, especially when there's a lot of | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you definitely want to include the caveats from #8059 that this is a platform-specific freeze, and as such is not necessarily usable by other people.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I mostly agree with this comment: #8059 (comment)