-
Notifications
You must be signed in to change notification settings - Fork 843
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
Stack init and solver overhaul #1583
Conversation
Changes in this commit: 1) When figuring out a build plan, track the dependency errors for each snapshot to figure out which snapshot is the best even if there are dependency errors. 2) Use the same strategy even when finding out the best set of flags. Find out the combination of flags producing least number of dependency errors. 3) Modularise the interfaces to make the code components more reusable if needed. This change is supposed to be used for later enhancements to use the dependency solver on the best matching snapshot in absence of an error free match.
This commit adds ability to track and distinguish build plan dependency errors related to the packages which are wired in GHC. This interface will be used to detect whether a snapshot can be used at all for building a given package. If GHC wired in packages are incompatible we cannot use the snapshot even with extra dependencies. This is not being used yet but will be used in future commits.
Provides more informative but concise error messages during stack init build plan selection process.
Currently stack init --solver cannot be used with a specific resolver. It just uses the GHC on your path and provides a compiler resolver corresponding to that GHC and all deps are extra deps. Instead, we want to be able to use a specific snapshot and only deps not matching the snapshot should be extra deps. This commit is a step towards that goal. 1) '--solver' is now a switch which can be used along with a resolver. 'stack init --resolver lts-2.22 --solver' will now be a valid init command. 2) Snapshot selector now returns the snapshot with least number of dependency errors as a partial match. This snapshot is to be used by the solver. Note that the solver is not yet changed to work on an existing snapshot. That will come in a future commit. 3) We now report an explicit error when the specified resolver does not have a compiler compatible with the package dependencies. 4) Note a behavior change for the 'stack init --resolver' command. Earlier it used to write the stack.yaml file even if it did not successully resolve all packages. Now it will fail in that case and suggest '--solver' to resolve the extra dependencies. 5) Separate the snapshot selection interface from the snapshot dependency check interface. 6) Some error message reporting changes.
Need to import Stack.Setup in Stack.Solver to be able to use ensureCompiler which creates a dependency cycle. The cycle can be fixed by making Init depend on Config instead of the opposite. This commit only includes the code movement due to the above. There are no functionality changes.
This commit introduces the following enahncements: 1) Support --install-ghc for stack new/init/solver commands 2) init or solver will now use the correct compiler specified in the resolver on command line during init or in stack.yaml when using the solver command. Before this change solver used the compiler found on path disregarding any configuration settings (for stack solver) or the snapshot chosen (for stack init) or the resolver specified on command line. Note that even with this change stack init --solver still returns a compiler resolver with all deps as extra-deps. Using a snapshot resolver with minimal extra-deps is a matter of a future commit. Fixes commercialhaskell#1529
Changes include: 1) For 'init --solver' use the best selected snapshot (having minumum number of dep errors) with minimum extra deps on top of the snapshot. Also use the auto selected flags producing minimal snapshot dep errors for solving. Before this change, solver always used a compiler resolver and everything as extra-deps. 2) Fix a bug in solver. When determining new extra-deps take version number into account, not just the name. If the version is different from the previous or in-snapshot version then its a new dependency.
With a recent commit solver was made to use packages in the snapshot as contraints when solving. Within those constraints it tries to figure what external packages are needed to build the package. But this strategy may not always work. The package dependencies may want to use a package which is already in the snapshot but requires a version different than in the snapshot. To take care of this we first try with the snapshot packages as hard constraints and if that fails we try solving with those packages as soft constraints i.e. merely preferences. This commit implements this fallback strategy. With this in place we should be able to solve and init any package which can be solved by cabal. If any package is not solved then either the package is broken or we have a bug in stack solver. This commit also added useful information in the status logs and suggestions for next steps or resolutions in case solver fails.
There is code in place to ignore .git .stack-work etc. But it did not work due to a trailing path separator mismatch in the logic. Fixed.
With recent changes we perform compiler compatibilty check when choosing snapshots for stack init. We need similar checks for stack solver as well. This change uses the same code to do compiler compatibility check when using the solver command. If the resolver specified in the stack.yaml does not have a compiler which can work with the package we emit an appropriate messages instead of going ahead and then showing difficult to understand cabal errors.
1) Share the same error checking code across init and solver commands 2) Use relative paths in error messages to make it easier to understand 3) Massaged some error messages
When there are duplicate cabal packages in the directory tree or specified in the config file we should detect the case and provide an appropriate error message.
Remove the warnings about not providing a good build plan. Now we either provide a successful plan or we fail and provide suggestions. We no longer write an inconsistent stack.yaml. Report relative filenames in error/status messages.
In addition to adding new flags and dependencies solver now also reports and deletes any dependencies and flags which are no longer needed.
Wow, this is great stuff, thanks a bunch for working on it! Along with my commit comments, I noticed the following things that could be enhanced / fixed:
|
Can't reproduce this, code too looks fine. Maybe you really had a file in the curdir and you thought you didn't?
Looking at the solver output for lens, it seems there is a conflict between the base package of the snapshot and the constraints of gloss required by lens-examples. We need a snapshot with the correct base package - in other words we need a different GHC. The compiler compatibility check that I have put in is pretty naive as it only works for the packages we are building, it cannot check whether the dependencies of the package are compiler compatible. We will have to parse the cabal error messages for that (yucky!) - or cabal itself can provide a distinctive error.
|
Also, always use the user specified flags as constraint.
When a package being built has a version in snapshot as well then the solver constraints should always use the local version.
Ah, I'm not sure how much the parent stack.yaml affects things (other than potentially overriding some non-project options). However, here's a repro where if you have an invalid parent stack.yaml, things don't work: https://gist.github.com/mgsloan/2beeac1531b2ef07c651 |
Right, that's after it falls back to using preferred versions. When using hard constraints, it yields I found this issue by running I ran into a couple miscellaneous issue while looking into this: If I delete the
How about always using hard constraints for wired in packages?
Cool, I do get different behavior - more flags now ( |
This warrants a separate issue. Perhaps we should avoid loading project config for init. Currently it uses |
Other minor cosmetic changes as well.
Also, made the post failure recommendations more concise and a few other minor error message tweaks.
I've opened #1604 . Yeah, I think we should be able to avoid using
No problem, that's what CI is for! Pushing another commit is fine, we have lots of "Fix build on GHC 7.8" commits.. Many thanks for spending time on implementing this! The next steps you've described sound good. |
Instead of using mapM_ on a Map moved the assert deeper where it can be applied on a single Map entry.
When solver is called with --resolver and resolver changes from what is there in stack.yaml already then show changed resolver in output and also update it in config when called with --modify-stack-yaml Also, reformatted the output so as to distinguish regular messages a bit from yaml formatted messages.
The solver option --modify-stack-yaml is changed to --update-config
Solver issues fixed with this commit are: When solver returns flag changes for packages which are in snapshot, we update the flags in stack.yaml but we do not put those packages in extra dependencies. When we run stack build it complains about it. We are not comparing the snapshot package flags (we compare only the version) when determining extra dependencies. If the snapshot flags are different than those the solver arrived at then we need to put those packages in extra dependencies. Otherwise the plan will not build because the status of flags can change dependencies.
It now gives a workable plan for stack itself using lts-2.22 and solver. Can you try it again now and see if you encounter any issues? |
We will have to update the documentation as well. I guess I can do that via a separate PR? |
Looks good! Feel free to do documentation in this PR, or a different one. I suppose I'd prefer including it with this one, but it's no big deal. I'm still running into the issue where there are hard constraints which disagree with local package versions. Could you please try this repro?
(NOTE: I haven't actually tried these steps, but this is what I did. There may be typos) |
Also with that repro, I get all the local packages having entries in
It'd be best to leave these out! |
I will try the diagrams-ci test. For documentation, I was only worried about merge conflicts if this PR stays longer. I will assess how many changes are needed and then we can decide to postpone or not. I thought I filtered out the empty flags but might have missed something, will check. |
The empty flags were getting through only in case of The solver errors are due to conflicting requirements of source packages in the diagrams suite. Here is the output I am getting:
Here source packages active, diagrams-input and diagrams-lib have a conflict on linear. Among themselves the dependencies are So maybe a future enhancement can be to automatically suggest which user packages can be removed to get a working plan. |
Filter out any empty flag values so that we do not end up having lots of package flags set to empty values in stack.yaml.
The build plan checks show dependency errors about packages when a particular build plan does not match. But flags can affect dependencies and are therefore needed to verify the errors. This commit adds code to print the flags as well in debug mode. Avoid in normal mode for the sake of brevity of info.
When only selected packages are added in stack.yaml solver will now print a message about which packages are available under the current dir subtree which are not found in the config.
The resolver build plan may return source package flags set to their default values. If so remove any flags set to default values before writing them to stack.yaml.
A very clean stack.yaml is generated now. I have added logic to remove flags with default values as well. I might push one more commit to report compiler incompatibility errors for each individual source package rather than once for the whole set. That way the user can easily identify exactly which package has problems. |
Specify clear steps to help out the user when a 'stack init' or solver fails. Make the help output more clear, concise and complete.
This is a great set of changes, thanks for all your excellent work! I fixed a warning that cropped up due to now reporting more warnings. |
RE the diagrams-haddock thing, you're probably right, I was just getting confused by the wording of cabal-install's output. |
Great. Thanks! I will try to fix the user guide in the next couple of days. |
Looks like there's a syntax error in the haddocks:
|
Can we include haddock in CI? |
Sure! Added in 92da37a |
Unfortunately, it doesn't work: #1623 |
I see you already fixed the haddock issues. Thanks! |
These commits are part of a series of commits to enhance the
stack init
andsolver
functionality. The goal is to be able to automatically init any project which has a working cabal file. Similarly thestack solver
command should be able to verify and fix the configuration in an optimal manner. Also, to provide a better user experience by providing informative error messages and next steps at every failure. In other words, init should just work and be smooth and painless and always work unless the package is really broken.See also #1529 and #1533.
The commit messages have more details about the problems and fixes. I will be adding more commits to the branch very soon. I am pushing these out for an early review. The changes are logically self contained, add incremental functionality and should not break any existing functionality.
Please review individual commits in order and see the commit messages for an overview of each commit.