-
Notifications
You must be signed in to change notification settings - Fork 696
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
Qualified constraints (issue #3502) #4219
Changes from 1 commit
39c3cb6
79d562b
ee86697
d2bf16e
702a39d
b992fae
14b5e9d
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 |
---|---|---|
@@ -1,46 +1,75 @@ | ||
{-# LANGUAGE DeriveGeneric #-} | ||
|
||
-- | Per-package constraints. Package constraints must be respected by the | ||
-- solver. Multiple constraints for each package can be given, though obviously | ||
-- it is possible to construct conflicting constraints (eg impossible version | ||
-- range or inconsistent flag assignment). | ||
-- | ||
module Distribution.Solver.Types.PackageConstraint ( | ||
PackageProperty(..), | ||
dispPackageProperty, | ||
PackageConstraint(..), | ||
dispPackageConstraint, | ||
showPackageConstraint, | ||
) where | ||
|
||
import Distribution.Compat.Binary (Binary(..)) | ||
import Distribution.PackageDescription (FlagAssignment, unFlagName) | ||
import Distribution.Package (PackageName) | ||
import Distribution.Solver.Types.OptionalStanza | ||
import Distribution.Text (display) | ||
import Distribution.Version (VersionRange, simplifyVersionRange) | ||
import Distribution.PackageDescription (FlagAssignment, dispFlagAssignment) | ||
import Distribution.Solver.Types.OptionalStanza | ||
import Distribution.Solver.Types.PackagePath (QPN, dispQPN) | ||
|
||
import GHC.Generics (Generic) | ||
import Distribution.Compat.Binary (Binary) | ||
|
||
-- | Per-package constraints. Package constraints must be respected by the | ||
-- solver. Multiple constraints for each package can be given, though obviously | ||
-- it is possible to construct conflicting constraints (eg impossible version | ||
-- range or inconsistent flag assignment). | ||
-- | ||
data PackageConstraint | ||
= PackageConstraintVersion PackageName VersionRange | ||
| PackageConstraintInstalled PackageName | ||
| PackageConstraintSource PackageName | ||
| PackageConstraintFlags PackageName FlagAssignment | ||
| PackageConstraintStanzas PackageName [OptionalStanza] | ||
import Distribution.Text (disp, flatStyle) | ||
import qualified Text.PrettyPrint as Disp | ||
import Text.PrettyPrint ((<+>)) | ||
|
||
-- | A package property is a logical predicate on packages. | ||
data PackageProperty | ||
= PackagePropertyVersion VersionRange | ||
| PackagePropertyInstalled | ||
| PackagePropertySource | ||
| PackagePropertyFlags FlagAssignment | ||
| PackagePropertyStanzas [OptionalStanza] | ||
deriving (Eq, Show, Generic) | ||
|
||
instance Binary PackageProperty | ||
|
||
-- | Pretty-prints a package property. | ||
dispPackageProperty :: PackageProperty -> Disp.Doc | ||
dispPackageProperty (PackagePropertyVersion verrange) = disp verrange | ||
dispPackageProperty PackagePropertyInstalled = Disp.text "installed" | ||
dispPackageProperty PackagePropertySource = Disp.text "source" | ||
dispPackageProperty (PackagePropertyFlags flags) = dispFlagAssignment flags | ||
dispPackageProperty (PackagePropertyStanzas stanzas) = | ||
Disp.hsep $ map (Disp.text . showStanza) stanzas | ||
|
||
-- | A package constraint consists of a package plus a property | ||
-- that must hold for that package. | ||
data PackageConstraint = PackageConstraint QPN PackageProperty | ||
deriving (Eq, Show, Generic) | ||
|
||
instance Binary PackageConstraint | ||
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 that your changes to 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. Yes, I think you're right - I'll look into that. |
||
|
||
-- | Provide a textual representation of a package constraint | ||
-- for debugging purposes. | ||
-- | Pretty-prints a package constraint. | ||
dispPackageConstraint :: PackageConstraint -> Disp.Doc | ||
dispPackageConstraint (PackageConstraint qpn prop) = | ||
dispQPN qpn <+> dispPackageProperty prop | ||
|
||
-- | Alternative textual representation of a package constraint | ||
-- for debugging purposes (slightly more verbose than that | ||
-- produced by 'dispPackageConstraint'). | ||
-- | ||
showPackageConstraint :: PackageConstraint -> String | ||
showPackageConstraint (PackageConstraintVersion pn vr) = | ||
display pn ++ " " ++ display (simplifyVersionRange vr) | ||
showPackageConstraint (PackageConstraintInstalled pn) = | ||
display pn ++ " installed" | ||
showPackageConstraint (PackageConstraintSource pn) = | ||
display pn ++ " source" | ||
showPackageConstraint (PackageConstraintFlags pn fs) = | ||
"flags " ++ display pn ++ " " ++ unwords (map (uncurry showFlag) fs) | ||
showPackageConstraint pc@(PackageConstraint qpn prop) = | ||
Disp.renderStyle flatStyle . postprocess $ dispPackageConstraint pc2 | ||
where | ||
showFlag f True = "+" ++ unFlagName f | ||
showFlag f False = "-" ++ unFlagName f | ||
showPackageConstraint (PackageConstraintStanzas pn ss) = | ||
"stanzas " ++ display pn ++ " " ++ unwords (map showStanza ss) | ||
pc2 = case prop of | ||
PackagePropertyVersion vr -> | ||
PackageConstraint qpn $ PackagePropertyVersion (simplifyVersionRange vr) | ||
_ -> pc | ||
postprocess = case prop of | ||
PackagePropertyFlags _ -> (Disp.text "flags" <+>) | ||
PackagePropertyStanzas _ -> (Disp.text "stanzas" <+>) | ||
_ -> id |
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.
These constraints should still apply to dependencies with any qualifier. I would expand
PackageConstraint
so that it can take either a qualified or unqualifiedPackageName
, because there will probably be other situations where it is useful to constrain a package everywhere it appears as a dependency.It would also be nice to allow users to specify unqualified constraints, but I don't think that's necessary for this set of PRs. I think that
--constraint pkg==2
should always apply to the top-levelpkg
dependency, as implemented in this PR. Once the solver part is done, it will fix an issue with bootstrapping packages such astime
: #4154. (See the comment at #4154 (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.
Yes I see your point. This may require a little thought, so I'll make a new PR after this one. Would it make sense instead of expanding
PackageConstraint
to expandQualifier
by adding a new constructor? I see two obvious choices:Any
.Toplevel
.Option 1 seems somewhat confusing semantically, so maybe option 2 is better - what do you think?
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.
On second thoughts, having looked at how
Qualifier
is used in the solver, I think my last suggestion was incorrect. So, if I understand you, I should modifyPackageConstraint
to support a wildcard or 'any' qualifier as an extra alternative, but leave theQualifier
andQPN
datatypes as they are?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.
Yes, the solver still needs QPN to refer to a single instance of a package in many places. It might be worth adding a new type for the scope of the constraint, since we'll probably need other scopes later, such as "all setup dependencies". For example:
I think Toplevel is a lot clearer than the current use of Unqualified. (I'm not suggesting a change for these PRs, though.)