Skip to content
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

Merged
7 commits merged into from Jan 9, 2017
Merged

Qualified constraints (issue #3502) #4219

7 commits merged into from Jan 9, 2017

Conversation

ghost
Copy link

@ghost ghost commented Jan 7, 2017

The main changes are:

  1. Updated the syntax of qualifiers in PackagePath.hs to use colon as a separator rather than hyphen.
  2. Changed PackageName to QPN in PackageConstraint.
  3. Added 'UserQualifier' into UserConstraint.

The only difference to the overall behaviour of cabal due to this patch is that qualified constraints will be parsed on the command line. Currently the solver etc. just ignores these qualifiers, however everything should be all set now to make the solver act on them.

One last thing: I'm going to add some new unit tests for the UserConstraint parser, but if it's okay I'll leave that till the next submission to stop this one getting too big.

Robert Henderson added 5 commits January 7, 2017 11:13
I modified the pretty-printing code so that it uses the
'Text.PrettyPrint' system rather than raw strings.

I updated the syntax of pretty-printed qualifiers to use colons
as separators rather than hyphens to fix an ambiguity problem
(since hyphens can occur in package names). See issue 3502.
Refactored PackageConstraint in two ways:
 1) split it into a package name and a 'PackageProperty' to make
    the code a bit cleaner;
 2) changed PackageName to 'Qualified PackageName'.

Added a Binary instance for Qualifier in PackagePath.hs (needed
for PackageConstraint).

Added pretty-printing code for PackageConstraint.

For now, all the code that creates a PackageConstraint just sets
the qualifier to 'unqualified', so this commit will not change
the external behaviour of cabal-install.
Changed PackageConstraint to PackageProperty in both cases, since
the name in the PackageConstraint was redundant.
This eliminates some boilerplate code.
Amended parsing and pretty-printing code of UserConstraint to
handle qualifiers.

Qualified constraints are now accepted on the command line, but
the solver and other subsystems currently just ignore the
qualifiers and don't do anything differently from before.
@mention-bot
Copy link

@robjhen, thanks for your PR! By analyzing the history of the files in this pull request, we identified @dcoutts, @grayjay and @23Skidoo to be potential reviewers.

@23Skidoo
Copy link
Member

23Skidoo commented Jan 7, 2017

/cc @kosmikus

@23Skidoo
Copy link
Member

23Skidoo commented Jan 7, 2017

AppVeyor failure seems to be genuine:

tests\UnitTests\Distribution\Client\ProjectConfig.hs:567:10: error:
    Duplicate instance declarations:
      instance Arbitrary UserConstraint
        -- Defined at tests\UnitTests\Distribution\Client\ProjectConfig.hs:567:10
      instance Arbitrary UserConstraint
        -- Defined at tests\UnitTests\Distribution\Client\ProjectConfig.hs:577:10

@grayjay grayjay self-assigned this Jan 8, 2017
Copy link
Collaborator

@grayjay grayjay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great! Thanks for working on this feature and refactoring the surrounding code. Is there anything else that needs to be done, besides enforcing the constraints in Distribution.Solver.Modular.Preference?

@@ -346,7 +348,7 @@ dontUpgradeNonUpgradeablePackages params =
where
extraConstraints =
[ LabeledPackageConstraint
(PackageConstraintInstalled pkgname)
(PackageConstraint (unqualified pkgname) PackagePropertyInstalled)
Copy link
Collaborator

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 unqualified PackageName, 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-level pkg dependency, as implemented in this PR. Once the solver part is done, it will fix an issue with bootstrapping packages such as time: #4154. (See the comment at #4154 (comment).)

Copy link
Author

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 expand Qualifier by adding a new constructor? I see two obvious choices:

  1. Let 'Unqualified' mean top-level dependency and add a new constructor called e.g. Any.
  2. Let 'Unqualified' mean applies everywhere and add a new constructor Toplevel.

Option 1 seems somewhat confusing semantically, so maybe option 2 is better - what do you think?

Copy link
Author

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 modify PackageConstraint to support a wildcard or 'any' qualifier as an extra alternative, but leave the Qualifier and QPN datatypes as they are?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, if I understand you, I should modify PackageConstraint to support a wildcard or 'any' qualifier as an extra alternative, but leave the Qualifier and QPN datatypes as they are?

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:

data PackageConstraint = PackageConstraint ConstraintScope PackageProperty

data ConstraintScope =
  Qualified QPN
  | AnyQualifier PackageName
  | AnySetupQualifier PackageName

Let 'Unqualified' mean applies everywhere and add a new constructor Toplevel.

I think Toplevel is a lot clearer than the current use of Unqualified. (I'm not suggesting a change for these PRs, though.)

--
NamedPackage PackageName [PackageConstraint]
NamedPackage PackageName [PackageProperty]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!


-- | 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that your changes to PackageSpecifier removed the need for this instance and most of the new Binary instances.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think you're right - I'll look into that.

instance Binary Namespace

-- | Pretty-prints a namespace. The result is either empty or
-- ends in a period, so it can be prepended onto a package name.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this say "qualifier" instead of "package name"?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed

@@ -744,35 +733,42 @@ readUserConstraint str =
++ "either a version range, 'installed', 'source' or flags"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message should probably mention that the package name is qualified.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed

@ghost
Copy link
Author

ghost commented Jan 9, 2017

Thanks very much! I'm going to merge this PR now, and then I'll create a new PR addressing the points you've made.

Regarding your question is there anything else that needs to be done, I think the top priority is to add in the ability to distinguish between 'any' and 'toplevel' qualifiers, as you pointed out. Probably best not to modify the solver until the any vs. toplevel distinction is done. After that I'll see if I can think of anything else that we may have missed.

@ghost ghost merged commit 2a8e853 into haskell:master Jan 9, 2017
@ghost ghost deleted the issue-3502-part2 branch January 9, 2017 11:09
@23Skidoo
Copy link
Member

23Skidoo commented Jan 9, 2017

Do we need any documentation for this or is this purely an internal thing?

@ezyang
Copy link
Contributor

ezyang commented Jan 9, 2017

Documentation for the new syntax would be very helpful. I am a little worried that it will look similar but be subtly different from the current component qualification syntax in new-build.

@23Skidoo
Copy link
Member

23Skidoo commented Jan 9, 2017

We can still change the syntax, the feature is not in any released version.

@ghost
Copy link
Author

ghost commented Jan 9, 2017

@23Skidoo @ezyang Would you mind giving me a link to the code or info concerning the component qualification syntax, as I am not familiar with that feature. I'd like to compare it with the UserConstraint syntax. Yes you are right, once this is finalized we will need documentation for qualified constraints on the command line.

@ezyang
Copy link
Contributor

ezyang commented Jan 9, 2017

@ghost
Copy link
Author

ghost commented Jan 9, 2017

Thanks.

Also, just a quick question to check I've understood the semantics of Exe qualifiers. Consider the following qualified package name:

Q (PackagePath DefaultNamespace
               (Exe (mkPackageName "foo") (mkPackageName "happy")))
  (mkPackageName "containers")

In the current provisional syntax this is pretty-printed as:

foo:happy:exe.containers

As I understand it, this means the following:

  • I want to build some package foo.
  • The happy build tool is needed to build foo.
  • The containers library is a dependency of happy.

So, for example, specifying the following constraint:

foo:happy:exe.containers ==0.4

means that when building foo, you must use a happy executable that has been linked against version 0.4 of the containers package.

My question is: have I understood this correctly?

@ezyang
Copy link
Contributor

ezyang commented Jan 9, 2017

Yep.

@grayjay
Copy link
Collaborator

grayjay commented Jan 10, 2017

Do we need any documentation for this or is this purely an internal thing?

The changelog should also mention that the meaning of constraints that use the old syntax has changed. They applied to all dependencies in 1.24, but now they only apply to top-level dependencies.

@ghost
Copy link
Author

ghost commented Jan 12, 2017

See PR #4228.

@grayjay I've added a 'ConstraintScope' data type as you suggested. I've also renamed 'Unqualified' to 'Toplevel'.

@hvr
Copy link
Member

hvr commented Jan 16, 2017

Looking at #4219 (comment), can somebody explain to me the meaning of the .s and :s symbols in the path

foo:happy:exe.containers ==0.4

?

Is happy the executable name or is it the package name? In the former case it looks a bit confusing to me that :exe is postfixed to the executable name, as in the goal syntax it's the other way round (i.e. happy:exe:happy denotes the executable component; and the first happy occurence before the :exe is the package name there)

When do I use : delimiter, and when do I use a . delimiter?

@ezyang
Copy link
Contributor

ezyang commented Jan 16, 2017

@hvr We are having discussion about this in #4236. I think the syntax definitely needs to change.

grayjay added a commit to grayjay/cabal that referenced this pull request Jan 21, 2017
…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.
grayjay added a commit to grayjay/cabal that referenced this pull request Jan 21, 2017
…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.
ezyang pushed a commit that referenced this pull request Jan 22, 2017
…ifiers.

This commit comments out the part of #4219 that parses build tool dependency
qualifiers, to disable the feature until we finalize the syntax. It also comments
out the part of #4236 that tests the parsing.
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants