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

Track cabal.project provenance for error reporting #3844

Merged
merged 1 commit into from
Sep 19, 2016
Merged

Track cabal.project provenance for error reporting #3844

merged 1 commit into from
Sep 19, 2016

Conversation

brendanhay
Copy link
Contributor

This changes the error when a cabal.project is missing from:

% cabal new-build
The package location glob 'foo./*.cabal' does not match any files or directories.

To (Implicit):

% cabal new-build
When using an implicit cabal.project configuration, the following errors were encountered:
The package location glob './*.cabal' does not match any files or directories.

Or (Explicit):

% cabal new-build
When using the configuration located at /home/bren/proj/cabal/cabal.project, the following errors were encountered:
The package location glob './*.cabal' does not match any files or directories.

This is done by tracking the provenance of the cabal.project file in readProjectLocalConfig, otherwise it defaults to Implicit.

The ProjectConfig is now also passed to BadPackageLocations and can be utilised in renderBadPackageLocation, although only the provenance is used currently to formulate a title specifying what configuration was used. This will hopefully allow individual calls to renderBadPackageLocation to be much more informative.

Note: I'm not certain the Semigroup and Monoid instances make sense for ProjectConfigProvenance.

Fixes #3636

@mention-bot
Copy link

@brendanhay, thanks for your PR! By analyzing the annotation information on this pull request, we identified @dcoutts, @hvr and @ezyang to be potential reviewers

@brendanhay
Copy link
Contributor Author

I notice a couple of the ProjectConfig properties are failing, I'll look into it shortly.

@dcoutts
Copy link
Contributor

dcoutts commented Sep 15, 2016

Great!

I think we can probably improve the wording further, especially in the implicit case. In the implicit case we can match on the common kinds of errors and give a specific message.

@ezyang
Copy link
Contributor

ezyang commented Sep 15, 2016

Thank you @brendanhay, provenance tracking is a great idea and will help our error messages.

You comment that you are not sure the Semigroup/Monoid instances make sense. I think this is indicative of deeper problems with the representation you have chosen. The big problem is that two ProjectConfigs can be merged together and now your provenance information is a bit scrambled. Provenance should not be a single ProjectConfigProvenance; it should be a set, tracking all of the ProjectConfigs that were inputs to the merge. Now you don't need a Semigroup/Monoid instance for ProjectConfigProvenance.

This also points out that your provenance tracking might be too coarse. When we renderBadPackageLocations, we don't care about the provenance of the config file as a whole; we just want to know which config file contributed the bad one. So really BadPackageLocation should be annotated with a location.

If we follow this line of reasoning to its logical conclusion, it would seem that we should refactor many of the types in cabal-install to be located, in the same way that GHC associates every Haskell-level expression with a line and column number. That would be a big refactor, but a worthwhile one, in my opinion. But let us not let perfect be the enemy of good. If there's a bad package location, giving the user a list of config files to look at to find the offending one is better than nothing at all.

To summarize: EITHER change ProjectConfigProvenance into Set ProjectConfigProvenance and drop the bogus Monoid/Semigroup instances, OR refactor ProjectConfig and the data types it refers to so that everything is located. (But not the Cabal library types, because that would be BC-breaking.)

@brendanhay
Copy link
Contributor Author

@ezyang Yes, that makes much more sense.

I interpret your comment as meaning your long-term preference is to have the location information, In which case one suggestion I have is to implement the Set ProjectConfigProvenance as a resolution to this PR, and then to work on adding location information as a separate PR which will then possibly supersede some of these changes.

@ezyang
Copy link
Contributor

ezyang commented Sep 15, 2016

Yes. I wanted to mention the long term refactor because, as you say, it does supersede the easier version. But in this case the easy fix is pretty easy, so it shouldn't be too bad to throw out later.

P.S., the test failure is because provenance isn't preserved if you print out a config, and then read it back in. I'm not sure if this means you should print out the provenance, or just ignore provenance when testing if it was roundtripped. Given the long term plan, probably the latter?

@brendanhay
Copy link
Contributor Author

Both SavedConfig and LegacyProjectConfig would be represented by mempty :: Set ProjectConfigProvenance, but what about defaultImplicitProjectConfig? Is it explicitly Set.singleton Implicit (drumroll) or can that also be considered to be equivalent to an empty Set?

In which case, would it make more sense to use a type such as Set FilePath to track provenance with the empty set denoting both legacy configuration, mempty / default configuration, or anything excluding a configuration that was explicitly read from a FilePath location?

An alternative would be to track with even more granularity things such as default configuration created via mempty vs defaultImplicitProjectConfig and so on. Although it seems that way has escher-esque potential and should really be left to more general/pervasive type location annotations.

@ezyang
Copy link
Contributor

ezyang commented Sep 15, 2016

In situations like this, I find it is useful to remember that mempty has a very specific meaning: it must be that mappend mempty e is e. So mempty MUST be the empty set.

On the other hand, it's fine for the implicit config to come with a provenance. It actually would be quite useful, because the implicit config is NOT used when there's an explicit config. So if there was an error related to implicit config, we could give an appropriate message in that case.

Copy link
Contributor

@ezyang ezyang left a comment

Choose a reason for hiding this comment

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

See discussion.

}

setExplicitProjectConfig :: ProjectConfig -> ProjectConfig
setExplicitProjectConfig config =
Copy link
Contributor

Choose a reason for hiding this comment

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

Are you sure you don't want to make a helper function for this operation? The helper could be more robust: instead of obliterating the old provenance it would just add to it (unless obliterating it is what you want here? Hard to tell.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When you say 'helper function' I'm going to assume you mean moving it to the top-level, which since it's not being used elsewhere it's nice (IMO) to have that apparent by its location in a where clause.

The old provenance should indeed be preserved via Set.insert.

-- | Render bad package location error information for the implicit
-- @cabal.project@ configuration.
--
-- TODO: This is currently a placeholder with the intention to supply
Copy link
Contributor

Choose a reason for hiding this comment

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

OK, well, let's not forget about the todo :)

-- used or if the configuration was read from an explicit file path.
data ProjectConfigProvenance

-- | The project configuration was implied.
Copy link
Contributor

Choose a reason for hiding this comment

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

Implied by what? If I read this, I would have no idea where to look to find out more. Crossref please.

@ezyang
Copy link
Contributor

ezyang commented Sep 16, 2016

@brendanhay For future reference, participants don't get emails when you push new commits to the branch, you'll have to make a comment to notice it.

@brendanhay
Copy link
Contributor Author

Yeah, was aware my sneaky commits wouldn't be noticed. Still want to add some actual nice errors where the TODO is first. I'll incorporate the other changes you suggested too.

++ "Please create a package description file <pkgname>.cabal "
++ "or a cabal.project file referencing the packages you "
++ "want to build."
_ -> renderBadPackageLocation bpl
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No cabal.project or cabal file matching the glob './*.cabal' was found.
Please create a package description file <pkgname>.cabal or a cabal.project
file referencing the packages you want to build.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Regarding the other cases, I'm not convinced I actually understand well enough under what situations these errors are raised to correctly word the implicit error message.

Copy link
Contributor

@ezyang ezyang left a comment

Choose a reason for hiding this comment

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

Still looking good.

-- per package error.
| otherwise =
"When using configuration(s) from "
++ intercalate ", " (mapMaybe getExplicit provenance)
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe this should also mention if the implicit is used? (I think this case is impossible, so outputting something in that case could help debugging in the future. Or maybe even an error.)

renderImplicitBadPackageLocation :: BadPackageLocation -> String
renderImplicitBadPackageLocation bpl = case bpl of
BadLocGlobEmptyMatch pkglocstr ->
"No cabal.project or cabal file matching the glob '"
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps say "default glob" rather than "glob"? Because it doesn't actually exist anywhere.

- Excludes provenance from all roundtrip tests
- Inserting explicit provenance when read from file
- Special cases for bad package errors arising from
  implicit project configuration
@brendanhay brendanhay merged commit d1d9737 into haskell:master Sep 19, 2016
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.

4 participants