Skip to content

Cabal lib for nix local build - #2948

Merged
dcoutts merged 28 commits into
haskell:masterfrom
dcoutts:cabal-lib-for-nix-local-build
Dec 16, 2015
Merged

Cabal lib for nix local build#2948
dcoutts merged 28 commits into
haskell:masterfrom
dcoutts:cabal-lib-for-nix-local-build

Conversation

@dcoutts

@dcoutts dcoutts commented Dec 16, 2015

Copy link
Copy Markdown
Contributor

@23Skidoo @hvr ping

A series of patches to the Cabal lib that are needed for the nix-local-build branch of cabal-install.

There's quite a few patches here because I've tried to make each one be clear and do one thing.

Summary:

  • Misc exports of useful functions
  • Extra instances
  • Change the interface to registerPackage so we can use it in cabal-install. This allows cabal-install to register things itself, rather than always relying on Setup register. This requires that registerPackage take fewer unnecessary or big arguments (like LocalBuildInfo).
  • Extend registerPackage with a multi-instance capability
  • Add compiler-independent utils for creating, deleting and testing existence of package dbs, including requesting using dir-style, but keeping the ability for Cabal lib to use file style in preference
  • Expose enough info to be able to do file change monitoring, for package dbs and for programs. This just means reporting file locations of things, so that cabal-install can monitor those files for changes.

Most types have these already. This just adds a few more.
To be used in cabal-install. Also use it in one place in Cabal.
It's used three times already. This isn't important on it's own, but
simplifies subsequent changes, when we add yet another use of it.
UHC's version of registerPackage is the only one that makes use of the
PackageDescription and inplace :: Bool args, and it's quite wrong for
doing so. Registering a package should depend on the content of the
InstalledPackageInfo and the PackageDBStack to register into and the
Compiler to register with. It should not depend on the original source
PackageDescription, and should not need a separate inplace arg. The
location is determined by the PackageDBStack. UHC was not following
this pattern and thereby forcing the general compiler independent
registerPackage to take annoying and unnecessary arguments.

With this patch, the register location is determined by the
PackageDBStack. The source package id also comes from the
InstalledPackageInfo rather than the source PackageDescription.

This patch does not yet change the registerPackage type.
Remove the now-unused PackageDescription and inplace :: Bool args.

Not yet changed the compiler-independent registerPackage.
The main reason is to stop using the pkg and inplace args so that we
can drop them entirely. A side benefit is that we don't actually want
to emit a setupMessage for inplace registering, since that's a rather
uninteresting internal action. We only want it for the explicit
register command. So only one caller gains a call to setupMessage.
Rather, pass the individual bits we need, which is the program db
and in some cases the compiler. This is a step towards having the main
registerPackage not take the LocalBuildInfo. That is useful in contexts
like cabal-install where we do not have a full LocalBuildInfo, but we
still want to be able to register packages in a compiler-agnostic way.
Drop the now-unused PackageDescription and inplace :: Bool args. And
instead of taking the whole LocalBuildInfo, just take the bits we need:
the compiler and program db. The package db stack was already passed in
separately. Also reorder args to follow standard conventions.
The HcPkgInfo useSingleFileDb is split into two: supportsDirDbs and
requiresDirDbs. Then rather than HcPkg.init callers having to do the
writeFile [] thing, HcPkg.init does it itself automatically based on the
HcPkgInfo. In the case that supportsDirDbs is True but requiresDirDbs is
False then we have a choice, to use dir style or file style. For
compatability reasons, when using ghc/ghc-pkg for the inplace package db
we want to use the old file style, even though dir style is supported.
However in other circumstances (e.g. in places in cabal-install) we
would like to use the dir style if it's supported, and there are no
backwards compat issues. So HcPkg.init gains a new Bool arg to request
using the file style if it's still supported. Only this mode is used
within Cabal itself, but the non-compat mode is available for other
users.

The compiler-independent initPackageDB is left with the same old
behaviour, but a new createPackageDB has the extra compat argument
(which is only passed to hc-pkg for ghc-pkg).
Add doesPackageDBExist and deletePackageDB, and export the new
createPackageDB. This gives a more complete compiler-independent API for
package db manipulation.
And fix up the db path for UHC. UHC cannot just register anywhere, like
compilers that have a hc-pkg can. It has to be special locations. Now
that registerPackage no longer takes the inplace :: Bool arg, UHC's impl
of registerPackage has to get the dir from the PackageDbStack without
knowing if it's implace or not. So the correct inplace location has to
be set earlier for the inplace package db, which is what this does.
Prior to further extension. Just share the common args calculation.
Part 1: just add the fields and fill them in for each HcPkg user.
This supports the feature of newer ghc-pkg version which have the
register --enable-multi-instance flag. This allows registering multiple
instances of the same version of a package into a single database.

In addition, to support the same feature on some older ghc-pkg versions,
the HcPkgInfo has a recacheMultiInstance capability, which tells us if
the trick of registering multiple instances by running ghc-pkg recache
works. This is known to work for all versions of ghc-pkg that support
the recache command at all.

Then HcPkg.registerMultiInstance will use one of the two methods
depending on which is supported, or fail if neither is. Currently only
registering into specific package dbs is supported, not global or user.

This new multi-instance feature is needed for cabal-install.
With support for GHC and GHCJS. All Cabal lib internal uses remain
traditional single instance, so there's no change of behaviour.
It provides a way to find out what files need to be monitored to detect
changes in a compiler's package database.

This is not used within the Cabal lib.
The findProgramOnSearchPath function is what we use in most places to
implement the Program abstraction's programFindLocation method.
Re-export it via Program module.

The only place that was still using the old findProgramLocation
instead was in HaskellSuite. Deprecate findProgramLocation which
is now no longer used.

This is in preparation for changing the return type of
findProgramOnSearchPath.
But in this patch, don't actually return them yet, so not yet changing
the resturn type.

The purpose here is change monitoring. In cabal-install we want to be
able to automatically re-run various actions when the build environment
changes, including when programs have changed (e.g. due to a $PATH
change, finding the compiler in a different location). The basic
information required for such change monitoring is not only the location
where a program was ultimately found, but all the locations where it was
looked for and not found. Otherwise one will miss the case where having
previously found the program in one location, later on the program
appears earlier in the search path. In this case a build system should
notice and react, but if it only monitors the ultimate location where
the program was found then this is impossible. The build system also
needs to monitor the locations where the program was not found, to make
sure it is still not there. This principle actually applies anytime we
have a file search (e.g. hs-source-dirs), programs are just one example.
This is to allow monitoring programs for changes. The combination of the
location where the program was found, and all the other locations where
the program was looked for gives the full set of files to monitor for
changes in that program.

The Program programFindLocation method is extended to return the
locations looked at but where the prog was not found. The default
implementation of programFindLocation, findProgramOnSearchPath, is
extended to return those locations.

Other places have to change, mostly just the type. In a couple places in
GHC & GHCJS where there is additional searching done, the not-found
locations have to be collected and returned.
The ProgramDb Binary instance is a bit odd by leaving out the Programs,
only including the ConfiguredPrograms. Of course this is because the
Programs contain functions. But the ProgramSearchPath is concrete and
should be included.
@23Skidoo

Copy link
Copy Markdown
Member

@dcoutts Thanks, will take a look later today. Can you fix the Travis failure?

For some reason my cpp does not fail with #if THING_NOT_DEFINED
but the travis one does, so use #ifdef instead.
For supporting multi instance registrations on older GHC versions.
@ezyang

ezyang commented Dec 16, 2015

Copy link
Copy Markdown
Contributor

Let's ship it!

@dcoutts

dcoutts commented Dec 16, 2015

Copy link
Copy Markdown
Contributor Author

So I think I've addressed everything except for tests for getUserPackageDB, and adding an impl of getInstalledPackagesMonitorFiles for GHCJS. I hope neither of these are blockers however.

@ezyang

ezyang commented Dec 16, 2015

Copy link
Copy Markdown
Contributor

I wouldn't block on it!

@23Skidoo

Copy link
Copy Markdown
Member

LGTM as well, let's merge!

@hvr

hvr commented Dec 16, 2015

Copy link
Copy Markdown
Member

👍

@dcoutts

dcoutts commented Dec 16, 2015

Copy link
Copy Markdown
Contributor Author

Woo!

dcoutts added a commit that referenced this pull request Dec 16, 2015
@dcoutts
dcoutts merged commit d71de1d into haskell:master Dec 16, 2015
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