-
Notifications
You must be signed in to change notification settings - Fork 710
Qualified constraints: documentation and unit tests (issue #3502) #4236
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
Conversation
I also moved all the detail about constraint syntax that was in the Nix-style local build cabal.project section into the section on the --constraint command line option. This reduces some duplication of information.
Added Arbitrary instance for UserQualifier. Added more test cases for user constraint parsing.
Thanks, we should definitely merge this. The docs made it a lot clearer to me about what kind of syntax bikeshedding we might want to do for constraints. I think the current syntax is close; in particular, In part, this is a bit related to the underlying model of how much flexibility the solver should have in choosing the dependencies for executables. One way to design the system is to be as flexible as possible: then, it should be possible to single out how we are depsolving a particular executable from a particular build-tools-dependency of a particular package. But maybe that's too much and a user who is actually wanting to exert some control here only cares about, "well, I just want to change what dep alex is using." In that case, the syntax should simplify to handle that case. Does this make sense? |
So, let me give a concrete suggestion. It should be possible to say |
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.
LGTM. Thanks!
I checked the use sites of the new types, and I think that the only ones that need to be updated are Distribution.Solver.Modular.Preference
and Distribution.Client.CmdFreeze.projectFreezeConstraints
.
Two cases of pattern matching that are particularly worth inspecting are packageVersionConstraintMap in Distribution.Client.Dependency and pcName in Distribution.Solver.Modular.
packageVersionConstraintMap
should be able to ignore constraint qualifiers because resolveWithoutDependencies
doesn't use qualifiers when choosing packages. pcName
is used for indexing the constraints used by the solver. I think it is okay for pcName
to throw out the qualifier and just use the PackageName
as a key, because there probably won't be a large number of constraints for each package name.
If that's all okay, I'll leave it to you to add the changelog entry once the solver part is done!
Yes, the changelog can wait.
or do not use ``bar`` at all, write: | ||
|
||
:: | ||
$ cabal install --constraint="bar == 2.1" |
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.
This needs another newline after the "::" to form a code block.
# Example use of the 'exe' (executable build tool) | ||
# qualifier. This constraint applies to package baz when it | ||
# is a dependency of the build tool bar being used | ||
# build package foo. |
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.
to build
I like the idea of trying to make the syntax more similar to new-build's targets. We may also want to make it consistent with the implication constraints from @dcoutts's package-collections branch: 657448b#diff-2a65a1064ba8104a25e44b665f4aabf5R193
So this syntax would apply to all non-lib components? It seems similar to independent goals qualifiers, which allow different targets to have different dependency versions. |
@ezyang @grayjay If/when you need to change the syntax, it should be easy to do. Just update the following four sections of code:
The syntax that we've got currently was never intended as final, and I agree it could be improved, particularly the |
@grayjay How do the independent goal qualifiers look like? :) Oh, those are the like, |
Yes, the independent goals are numbered internally, but I imagine they would look similar to your suggested syntax if we ever exposed them.
I meant to add that the current syntax for build tool dependencies, |
Hmm, found this. I wrote up a plan for cross compiling involving changing the qualifier type to a list: #1493 (comment) . I figure this is quite relevant to bike shedding syntax. |
Ok, so if understand this stuff right, qualifying comes from "encapulating" edges in the dependency DAG. If we think about solving per-package, these encapuslating edges are the single connection between between otherwise-disconnected subgraphs. Solving per-component is weirder as each non-setup component would have and edge to the setup component coming from the same package, though technically those exes could be configured separately so not the same node restoring single connection property? Let's assume that for the following so we have the single-connection property. Today we do some "pruning" (I talk about this in the linked comment), but a qualification is a chain of these encapsulating edges that must be traversed to reach the package in question. [Formally, Now if we do want to be less flexible, or the single-edge property doesn't hold, that's means we don't have a tree, so qualifications do not uniquely reach a node. I guess we have to whittle down the space of connections then---which incidentally this pruning might do. Anyways, back to the syntax, it might make sense to again forget about the is pruning, and except that syntactically different constraints may in fact conflict. Maybe I'm wrong and actually that's a horrible design, but for the sake of argument let me try to give a grammar for the full unadulterated paths-as-qualifiers for components.
|
@Ericson2314 The solver previously allowed unlimited qualifiers, but they were removed in #3220 because of a problem with cyclic dependencies. If we need more qualifiers, there might be other ways to prevent the list from growing too long, such as a fixed bound on the length.
I like the use of arrows here. |
…ifiers. This commit comments out the part of haskell#4219 that parses build tool dependency qualifiers, to disable the feature until we finalize the syntax. It also comments out the part of haskell#4236 that tests the parsing.
…ifiers. This commit comments out the part of haskell#4219 that parses build tool dependency qualifiers, to disable the feature until we finalize the syntax. It also comments out the part of haskell#4236 that tests the parsing.
I made a pull request (#4252) to disallow the |
|
||
:: | ||
|
||
# Note: this is just syntax sugar for '> 1 && < 1', and is |
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.
Btw, why do we use this arbitrary > 1 && < 1
contradiction instead of the more canonical < 0
constraint?
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.
Patches accepted :) But -none
is literally implemented this way:
noVersion :: VersionRange
noVersion = IntersectVersionRanges (LaterVersion v) (EarlierVersion v)
where v = mkVersion [1]
We could change this as long as it is actually impossible to have negative version numbers :)
@@ -361,7 +361,7 @@ dontUpgradeNonUpgradeablePackages params = | |||
where | |||
extraConstraints = | |||
[ LabeledPackageConstraint | |||
(PackageConstraint (scopeToplevel pkgname) PackagePropertyInstalled) | |||
(PackageConstraint (ScopeAnyQualifier pkgname) PackagePropertyInstalled) |
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.
Wow, did we seriously apply this to top-level only before? Worth a comment!
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.
scopeTopLevel
was only added in #4219 (originally unqualified
). Before that, every constraint applied to all occurrences of the package, so the constraints above always prevented base
, etc. from being installed.
# qualifier. This constraint applies to package baz when it | ||
# is a dependency of the build tool bar being used | ||
# build package foo. | ||
$ cabal install --constraint="foo:bar:exe.baz == 1.0" |
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.
Yeah, I have to say, if I saw this in a source code file, I would definitely have a hard time telling what the bar is supposed to mean.
|
||
A package can be specified multiple times in ``constraints``, in | ||
which case the specified constraints are intersected. This is | ||
useful, since the syntax does not allow you to specify multiple |
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 this is still useful advice to reiterate here, since it's not obvious from the command line flag discussion.
|
||
:: | ||
|
||
# Note: this is just syntax sugar for '> 1 && < 1', and is |
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.
Patches accepted :) But -none
is literally implemented this way:
noVersion :: VersionRange
noVersion = IntersectVersionRanges (LaterVersion v) (EarlierVersion v)
where v = mkVersion [1]
We could change this as long as it is actually impossible to have negative version numbers :)
In this PR:
ScopeAnyQualifier
.--constraint
command line option and theconstraints
field of cabal.project (let me know if any objections to my moving things around).@grayjay You asked me before if there is anything else you'll need to do aside from enforcing the constraints in
Distribution.Solver.Modular.Preference
. Mainly just the following:PackageConstraint
/UserConstraint
values are constructed and pattern-matched (you can just grep for these identifiers). Where they are constructed, check that the correctConstraintScope
has been applied (I have currently set them all toscopeTopLevel
except for the non-upgradeable packages one that is set toScopeAnyQualifier
). Where they are pattern-matched, check if you need to handle the qualifier in any way (currently qualifiers are just being ignored at these places). Two cases of pattern matching that are particularly worth inspecting arepackageVersionConstraintMap
inDistribution.Client.Dependency
andpcName
inDistribution.Solver.Modular
.