-
Notifications
You must be signed in to change notification settings - Fork 684
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
Rework build target handling #4179
Conversation
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 like refactors. We should merge refactors.
In general, this patchset adds some more features, but these features are not documented in the user's guide, nor are they tested. It would be really helpful if they were documented at least, esp., since it's not obvious from the code what new things were added.
-> Map UnitId [ComponentTarget] | ||
elaboratePackageTargets elaboratedPlan = | ||
Map.mapWithKey $ \pkgid targets -> | ||
let Just (InstallPlan.Configured pkg) = |
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.
Partial!
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.
(Intended invariant for this function that all the UnitIds exist?)
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.
Note that this is only an intermediate step during the refactoring. This function gets completely removed in subsequent patches. It's replaced by the combination of availableTargets
and resolveTargets
which are much more careful about error checking.
(Just [tgt], TargetActionRepl) -> elab { elabReplTarget = Just tgt } | ||
(Just _, TargetActionHaddock) -> elab { elabBuildHaddocks = True } | ||
(Just _, TargetActionRepl) -> | ||
error "pruneInstallPlanToTargets: multiple repl targets" |
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.
s/pruneInstallPlanToTargets/setRootTargets/
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 that was deliberate. pruneInstallPlanToTargets
is the only exported function that uses it.
-- | ||
-- Note that the type parameter is used to help enforce that command | ||
-- implementations can only select targets that can actually be built (by | ||
-- forcing them to return the @k@ value for the selected targets). |
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.
Is it only used for that? Or is there a legit reason to store a key? (Should we use a GADT instead?)
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 I'm missing what you're getting at exactly. The type that actually gets used in place of the 'k' is (UnitId, ComponentName)
.
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.
Add that to the comment!
-- to know about them and have enough info about them to explain why they | ||
-- cannot be selected. | ||
-- | ||
-- We refer to these reconstructed missing components as fake targets. |
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.
Why not just call them non-buildable targets?
-- to which this graph node corresponds. For graph nodes that are whole | ||
-- packages this makes perfect sense, but for nodes corresponding to | ||
-- components this sort-of amounts to taking the cross-product of the set | ||
-- of components of a package with itself. Obviously this will give rise |
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 know what you mean, but it would be clearer with an example.
"The package " ++ display (buildTargetPackage t) ++ " is in the " | ||
++ "project but it is not a locally unpacked package, so " | ||
|
||
reportBuildTargetProblem (BuildTargetOptionalStanzaDisabled _) = undefined | ||
showTargetProblem _ = undefined |
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.
Since you wibbled this line, I couldn't help but notice the pattern match was partial...
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, this bit of the error message formatting remains a TODO
|
||
--TODO: [required eventually] handle no targets case | ||
when (Map.null targets) $ | ||
fail "TODO handle no targets case" |
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.
Maybe it is work to write code to nicely explain why the error happened but surely we can do better than "TODO handle no targets case"
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.
Producing nice messages is one of the things remaining to be done.
++ "encounter problems\nplease file issues at " | ||
++ "https://github.com/haskell/cabal/issues and if you\nhave any time " | ||
++ "to get involved and help with testing, fixing bugs etc then\nthat " | ||
++ "is very much appreciated.\n" |
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.
Would be nice to not copy paste this text...
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 should move that to ProjectOrchestration
buildOutcomes <- runProjectBuildPhase verbosity buildCtx | ||
runProjectPostBuildPhase verbosity buildCtx buildOutcomes | ||
where | ||
verbosity = fromFlagOrDefault normal (configVerbosity configFlags) |
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.
A general comment that these stubs are really wordy :/
@@ -222,6 +222,8 @@ data TargetString = | |||
| TargetString2 String String | |||
| TargetString3 String String String | |||
| TargetString4 String String String String | |||
| TargetString5 String String String String String | |||
| TargetString7 String String String String String String String |
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.
...really?
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.
Really. You inspired me to have a proper unambigious form for scripts and I realised the existing forms were not necessarily unambigious and were not very consistent or sane. So these are long but they're consistent: each bit gets a qualification, the long forms are:
:pkg:foo:lib:foo
:pkg:foo:lib:foo:module:Data.Foo
:pkg:foo:exe:foo:file:Main.hs
Count them: 5 and 7 components.
Also, this patchset makes the breaking change, of making |
-- cannot be selected. | ||
-- We have a somewhat awkward problem here. We need to know /all/ the | ||
-- components from /all/ the packages because these are the things that | ||
-- users could refer to. Unfortunately at this stage the elaborated install |
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.
"Unfortunately," (missing comma)
-- We can recover the missing components but it's not exactly elegant. For | ||
-- a graph node corresponding to a component we still have the information | ||
-- about the package that it came from, and this includes the names of | ||
-- /all/ the other components in the package. So in principle this lets us |
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.
"So," (missing comma... I think?)
-- components. | ||
-- | ||
-- Consider for example a package with 3 exe components: foo, bar and baz | ||
-- where foo and bar are buildable but baz is not. So the plan contains |
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.
", but" (comma)
(I was really hoping to find actual typos and things, but it seems I've become Comma Nazi :) )
-- | ||
-- Consider for example a package with 3 exe components: foo, bar and baz | ||
-- where foo and bar are buildable but baz is not. So the plan contains | ||
-- nodes for the components foo and bar. Now we look at each of these two |
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.
"Now, " (comma)? Or do you mean this in the sense of "we used to do X, now we do Y"?
3e1eea4
to
7a3ae03
Compare
The pruneInstallPlanToTargets function had two main passes. Split the first pass into two passes. This simplifies things a bit and helps clarify the fact that setting the root targets is something we do prior to taking the dep closure.
And push compatSubComponentTargets inside nubComponentTargets. The motivation for this is we'll be exporting nubComponentTargets and using it from the ProjectOrchestration as part of revised target handling.
Previously it took the specification for the targets to build in terms of PackageTarget which is a high-ish level specification of which components to build. It is high level in the sense that it says things like BuildDefaultComponents which still have to be elaborated into the specific components. This elaboration from the higher level intention of what to build into what components to build specifically has to vary between different commands (build, repl, run, test, bench) and it can also fail. These features make it not a good fit to do within plan pruning. Instead it is better to have plan pruning take the lower level specification of what to build in terms of components and to do the conversion of high level to low level separately. That will allow us to do it differently for different commands and deal with failures better. This patch does one step: it changes pruneInstallPlanToTargets from taking [PackageTarget] to [ComponentTarget] and as an intermediate step in refactoring it converts the existing elaboratePackageTargets code to convert from the [PackageTarget] to [ComponentTarget] which is then used by the calling code in ProjectOrchestration. The next step will be to replace the elaboratePackageTargets with something more flexible and that can handle errors better.
This is one major part of a new implementation of translating from high level user intentions of what to build into the detail of what specific components to build. This part collects and summarises information on what component are available as targets. Each available target one has enough status info to determine if we can possibly select the target or if not why not. This information will be used by each command (build, repl, test etc) to select the specific targets that a user intention refers to (and to provide them enough information to be able to produce reasonable error messages). Collecting and summarising this info is unfortunately non-trivial because as part of install plan elaboration we omit components that cannot be built but these are still components that users could try to refer to, so we have to reconstruct the info about the omitted components. It's plausible that we may want to revise the elaborated install plan representation to make this easier.
Previously the resolveUserBuildTargets would return a PackageName which meant we would subsequently select all versions of that package that occur in the project during target selection (resolveAndCheckTargets). Using PackageId means we only pick one version (though in future we may still need to disambiguate multiple instances, or targets from multiple active profiles)
selectTargets would also prune to to the targets, and optionally prune to dependencies only. These aspects are now pulled out into the callers in the various Cmd{Build,Repl,etc} modules. It will make more sense to do it this way once we're doing more explicit error checking in the callers.
Instead of expressing the intention in terms of PackageTargets, it now takes helper functions that select the components to use for a package target or a component target. These helpers are given the set of AvailableTargets and they can do error checking and return failures. This allows the build,configure,haddock,repl implementations to have their own behaviour and error checking and reporting for selecting targets. The full details of error reporting are not covered yet.
The --only-dependencies it is only used in build, so we move the rendering of the errors that arise from that to that build command module so the error message text can be more context specific.
And also reject --only-dependencies for the haddock command.
It looks like CmdHaddock was based on the CmdConfigure template and so copied some bits that don't make sense for it. Change those bits to be the same as for build. In particular for printing the plan, the configure command always behaves as if it is in --dry-run mode, but that's not appropriate for the haddock command. The other change is to follow the standard pattern for the runProjectBuildPhase / runProjectPostBuildPhase and the handling of the --dry-run option, which is handled internally by those and does not need to be handled explicitly in CmdHaddock.
This is slightly tricky stuff to write since it has to be concise, clear, accurate and make sense without too much context. This and the examples should be reviewed with comparison to the user guide.
Rather than having it appear in the [other] section. I've just guessed at where it ought to go. Suggestions welcome.
So far they just build the exe bench and don't do the next steps, but they do at least select the right components to build. Also bring the existing test command into sync with the others.
The way it is currently implemented is incompatible with the new target checking code, since it really selects everything, including things that are not buildable. This leads directly to failre when we check that the things the user has asked to build are in fact buildable.
We already have the SubComponentTarget type so we can use this to better factor the BuildTarget type, and simplify conversions.
19 new patches, everything from "Change TargetSelector to remove TargetCwdPackage" onwards. So if you were happy with the last lot then you only need to start there. Again, everything is broken out into reviewable chunks. The first 57 patches are rebased but otherwise not changed. The main new things are proper integration tests covering all the cases the code checks for, and human readable error messages for these things. |
One thing I've not properly tested is if I have broken the existing test command (or at least it's CLI), so that's a TODO. |
Yaaay! Ship it when it's green. |
Would be nice to have this in 2.0 to make it easier to backport patches, as this is such a massive change. |
@ezyang I don't understand the cause of this failure in If you have a sec, would you mind taking a look? |
…to dcoutts-target-handling
In HEAD, the expected output is this:
This is not an error from the dep solver; it's from ProjectPlanning. If you merge your branch with master and then run the tests, you'll see the complete How does this test work? We do it this way:
checking if |
And indeed, this diff fixes the problem:
But there is something a bit questionable going on here, so maybe some more refactoring is in order. |
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
Two windows failures are legit. One is easy to fix but the other I'm going to have to debug properly. |
Despite being unable to repro on my Windows 10 box, I'm fairly confident that the failing test case in "Target selectors" has to do with case-insensitivity on Windows/Mac OS X. Essentially, what I think is happening is when we pass Experimentally, the only way I can get the "display" case of a file is to do something like I think there are two ways to deal:
CC @dcoutts |
I would prefer syntax like |
That'd conflict with shell's pattern expansion:
Maybe |
@23Skidoo I suppose if we want to reserve |
@grayjay you were using |
I don't see why we can't support the asterisk syntax... |
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
@Ericson2314 Qualified constraints use |
@Ericson2314 @grayjay I'm totally open to adding/adjusting the target syntax (provided it's coherent). Having multiple aliases for the same thing is also ok (though if it introduces more ambiguity then it has knock-on implications). |
@ezyang thanks for the review, fixing things and merging. I see you added a workaround for the windows case insensitivity thing. So that remains as a TODO for me. |
I just want to be consistent. I like |
Rework build target handling
This is a fairly long patch series and this is partly just request for review/comment.
It does a whole lot of refactoring in the handling of command line build targets and related code. This includes rearranging things a bit in the project planning (splitting initial project config steps out) and project orchestration.
One motivation for the reorganisation is to properly support what
test
,bench
, andrun
need from target handling, since they are slight variations on what is needed forbuild
. Another motivation is doing better detection and reporting of user mistakes in targets. And another motivation is to be able to do most error reporting prior to running the solver. This is important for usability because many user mistakes or misunderstandings will result in solver failure, when really the problem was starting from the wrong place or asking for the wrong thing.It includes:
all
build targettests
,pkgfoo:tests
,./:tests
,all:tests
It has recently been rebased against master and as part of that merge it adds a number of TODOs for places where the master branch is doing something silly. These can be cleaned up as subsequent patches within this series or later.
There are still a few bits to finish, including proper text for a number of error cases that are currently just represented by constructors with 'show'. Also missing is proper testing. There's also still a number of TODOs.