-
Notifications
You must be signed in to change notification settings - Fork 701
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
Top-level command for Freezing dependencies #1519
Conversation
Yes, please do that. Force push is fine for WIP branches. |
Done. |
Thanks for working on this. Code looks fine on a first glance. Regarding your open issues:
The presence/absence of a sandbox shouldn't affect anything except the choice of package DB, so I don't see a problem here. If there's no
I'm with @tibbe on this. The fact that |
Of course I am fine with just overriding the constraints section. I just sounds like a lot of wasted effort for a non-ideal solution. It is less effort to write out a cabal.freeze. Of course you then need to have the code that reads the cabal.config constraints section also read cabal.freeze, but that doesn't sound very hard either and this is all forwards progress, not temporary hacks to be later erased. But either is ok with me :) |
I'm fine with overwriting if we decide to use a separate |
A brief look at how loading constraints from
To support upgrading dependencies we would need to be able to load the package environment without the freeze file's constraints being included. Implementing that shouldn't require much more than passing some flags down to Unless I'm missing something, I think this is the way to go. |
I don't know if this is a good idea. As you discovered, we need to figure out how this new file interacts with the other files and in particular how the user is now supposed to change the list of dependencies, now when we have a feel the user isn't supposed to edit! What's the supposed workflow for freezing dependencies and then subsequently change them? |
First build of the application:
Repeatable builds across the teamAnother user pulls the git repo and installs the frozen dependencies:
Upgrading a direct dependencyA new version of foo is released. It has new functionality which I want and
Upgrading an indirect dependencyA new version of bar is released. It contains an important bug fix.
What's missingWe don't yet have either I'm assuming in this that Ninja edit: changed |
I think this is wrong. The .cabal is for saying what you can build this package with, the freeze file (whether it's cabal.config or cabal.freeze) is for saying what you want to build with. They might often be the same, but not necessarily so. That is why we need to put the constraints in cabal.config, it's a user-editable file with the purpose of talking about what you want to build a particular package with. |
The user changes dependencies in the .cabal file. It they want to upgrade for example, they put a new lower bound in the .cabal file. Just running the
Obviously we don't want to actually delete cabal.freeze, but running |
oh, whoops, I was offline for a while, responding to tibbe's original comment today |
But the use case stated that the new functionality is wanted and backwards Let's add a new use case to cover your complaint. Increase upper bound for a direct dependencyA new version of baz is released. Our application is to remain compatible with the previous version but is to also admit the new version.
|
I mostly like the idea of refreezing by rerunning So my examples would change so that
becomes
And similar for |
my comment is still relevant, we don't need to require --upgrade-dependencies and --ignore-frozen flags, the user can just run @tibbe I think we all agree that we should keep the cabal.config file constraints field so that the user can manually add specific constraints there. There is no reason for an application developer to use cabal.config constraints (and have to manually edit 2 files, they should only manually edit 1 file). But I am sure it will still be useful for distributing libraries or open source applications. |
@tibbe To clarify the point further, you are properly advocating for the Library section of the .cabal file. As an application developer at work I am not interested in listing lower version ranges that an application can be built with. Downgrades are rare other than immediately after a deploy, in which case I can just look at the previous commit of the .cabal file and revert it. The .cabal file can contain larger upper bounds that can indicate what could be built by upgrading versions. But if I really want that kind of information I can always just put a comment in the .cabal file so that the information is all in one place rather than spreading it across 2 files. As a distributor of an open source application, I may want to indicate all the versions that my application could be built with in the .cabal file. As a distributor of a library, I definitely want to indicate all versions that my application can be built with, and use cabal.config as a development tool to reproduce bugs. |
@gregwebs you're right about not requiring the |
@benarmston I agree it isn't going to be perfect and that we will need some advanced options, I am advocating for a default. My understanding is that since the dependencies are already installed, it will essentially be using cabal.freeze, but again I know that isn't a perfect process. The |
@gregwebs I think then that we can agree then that we need both a way to upgrade everything and a way to upgrade just a specific set of packages. Let's leave disagreements about what the default should be until we've decided on whether there should be a |
@tibbe I think I may have missed the point of your complaint. Was it about the equality constraint rather than marking an old version no longer compatible? If so, you're right that equality constraints shouldn't be used in a My understanding is that
I think that is a perfectly valid change to a I'm primarily a proprietary-application developer rather than a library developer, and choosing not to maintain backwards compatibility with versions of a library I'm not using is a common choice. For open source applications and library developers there are obviously different dynamics at play. Perhaps it would be helpful if we collected the use cases we wished to support with this feature. We'd then be able to talk with an explicit common focus in mind. As it stands at the moment, I think that the implicit differences in our expectations of how cabal is used and how this feature will be useful are hindering the conversation. |
Perhaps taking a step back will help. There are two people involved in this process, the package author and the package builder. Sometimes they're the same person, but not necessarily so.
What is this user-editable file that the builder can edit to influence which dependencies are used? It's Here's an example that I hope shows why
It is not enough to to now run Temporarily changing the |
I suspect that this is the root of the confusion. For both you and Greg builder == author, we also support builder != author and that only works if there's a user-editable file other than the .cabal file where version constraints are specified and checked into source control. If you only check in a machine-generate |
Another way to state the distinction
We completely understand that the industry use case of building binaries is not going to be appropriate for the open source use case of distributing code. Nobody is opposing using cabal.config. We have gone to a lot of effort to explain why forcing cabal.config on industry users is far from ideal. @benarmston and I need to continue down this path or abandon cabal as the primary build tool as much of industry does. We would really appreciate your help in making sure what we are doing will also make distributing source code a more pleasant experience. So lets figure out how to support both use cases. If we can start by agreeing we want to support both to the fullest extent possible and that using cabal.config is not sufficient for industry users building binaries, we can move forward with this. |
I think this complicates things:
You're also not getting any expressive power for this extra complication. If you insist you can just edit the .cabal file, run freeze and have the cabal.config file be completely managed by Cabal (since you're not making any manual changes to it).
I hate to disappoint, but Cabal is an opinionated piece of software. I'm happy to support alternative use cases, as long as I don't have to compromise on the "happy path" we're designing for the UI. I was about to merge the patches before cabal.freeze was added. |
I completely disagree that fewer files == less complexity. It is much simpler for the implementer and user if cabal.freeze is machine generated (as a comment at the top will indicate) and if cabal.config is user edited.
Why is this complicated? Doesn't it already do this for cabal.config?
Please keep merging patches, including this one. This has not been a "happy path" for me. Unfortunately I am far beyond the time I had imagined it would take to discuss this feature. @benarmston I will leave the rest of the discussion up to you. |
I am very pleased to see progress on this important issue. Thanks to all! Our needs have been well represented by @gregwebs; I hope the feature will be as close as possible to what he has described in this thread. There has been discussion of the need for --ignore-all-frozen and --ignore-frozen flags, as suggested by @benarmston. Regardless of what is decided on that point, it still makes sense also to implement a simpler and more general --ignore-constraint flag. See #949. I need to manage cabal projects with very large and complex indirect dependency graphs - for example, those that tend to arise for complex web apps, with ~150 nodes, and more than an order of magnitude more nodes in the graph considered by the solver. And I need reproducible builds; and also feature-equivalent builds with different GHC versions. Until now, the tools provided by cabal were just not sufficient, and the work was difficult and time consuming. These new features, together with other features already added such as constraints in local |
@benarmston Are you OK with changing this back to not use the extra |
@tibbe I've been trying to find the time to write some use cases to convince you that using a If I can't find the time this week, or if I can but fail to convince you, I'll change this back to not use |
@benarmston Sounds good to me. I will be out for a week, starting Wednesday, so I might be a bit slow to respond. |
Personally, I think Regarding opinionated, UI, etc., for me this often times boils down to personal taste (and we had similar discussions here many times). For me the core issue here is that the core infrastructure components (GHC/Cabal/Hackage/Haddock...) are too closely tied together which makes it inherently hard to fork and try new ideas (which by extension hampers innovation). |
@benarmston have you found any time to look into this? I think it's a really important feature for 1.20. |
Add new top-level `freeze` command, which resolves the dependencies to exact versions and writes a `constraints` section to `cabal.config`. This causes future builds to use the same fully constrained dependencies. The command takes a number of options related to resolving dependencies, namely, `--solver`, `--max-backjumps`, `reorder-goals` and `--shadow-installed-packages`. These are used to create an `InstallPlan` in much the same way that `install` does so. The `InstallPlan` is converted to a list and all `PlanPackage`s are inspected to determine their exact version. These versions are then either written to `cabal.config` or to standard output depending on the presence of `--dry-run`. Limitations in resolving dependencies ------------------------------------- In order to keep the initial implementation of this new command simpler, a number of options are not yet supported. There should be no great difficulty in supporting the options `--flags`, `--enable-{tests,benchmarks}`, `--constraint` and `--preference`. However, the options concerned with compilers may prove more difficult. Different versions of GHC ship with different library versions, the constraints that are written currently include all dependencies, including `base`. This prevents the constraints, as written, from being used with alternate versions of GHC. There are three solutions to this problem: 1) have the user edit the constraints section, 2) exclude certain packages from the list of constraints, 3) develop a mechanism for per-arch-os-compiler constraining. As neither (2) nor (3) have been developed we default to (1). The lack of a good story for per-compiler constraints has lead to the options `--with-compiler`, `--ghc`, `--uhc` et al, not being supported. Further limitations: -------------------- - The `cabal.config` file is completely overwritten. Just the `constraints` section should be overwritten.
@tibbe I apologise for having taken so long to respond to you on this. I have found only a little time to work on this over the last month or so. As previously agreed upon, although not in the suggested time scales, I've reverted the commit introducing the use of I agree with you, this is an important feature for 1.20. So I'd like to remove any obstacles for getting this branch merged, and ensuring that some form of freezing is included. Then any discussion on whether to use a You had written previously that you were close to merging the commit in this state, i.e., pre Regarding the work I'd already done on using a |
@benarmston Thanks for taking the time to do the changes. I've merged the commit so it will be a part of 1.20, expected early next year. I will file a separate bug for making cabal freeze more convenient by only updating the constraints section. |
Filed issue #1615. |
@benarmston: Can you confirm that Continuing in #2265. |
This series of patches implements a new top-level command,
freeze
, which will resolve the dependencies to exact versions and write a constraints section tocabal.config
.The new command takes a number of options related to resolving dependencies, namely,
--solver
,--max-backjumps
,--reorder-goals
and--shadow-installed-packages
. Previously, I had asked whether other option are required. As no-one said that they are, I've taken that to mean that they are not.Issues that may still need addressing include:
cabal.config
can be entirely overwritten.Regarding the last point, @tibbe has stated that it should not, whilst @gregwebs is of the opinion that it is fine to do so. Before I invest any time in replacing only the
constraints
section, I'd like to have some agreement on whether or not it is required.This branch contains a number of dead-end efforts. If you'd like them to be rebased away, let me know. I've hesitated doing that as I didn't want to force push.
See issues #1502 and #1499 for discussion of this feature.