| Version 6 (modified by duncan, 13 months ago) |
|---|
This page is for trying to clarify some ideas and design for cabal handling sets of packages people want to build.
Goal
Recently people have written various cabal extension/wrapper tools to address use cases that the main Cabal/cabal-install tool does not handle very well. These tools are each designed to address a few use cases, and the different tools overlap somewhat in what they cover.
The goal here is:
- to see if we can identify some more unified idea and explain what the various existing tools are trying to do in terms of that idea;
- then to come up with a design (mechanisms) that implements that idea; and
- a user interface that covers the main use cases in a reasonably simple way, but hopefully sufficiently flexible to expose what the design can do
Example use cases
Developer working on a single package
The developer is actively developing a package. The package is in some intermediate state i.e. it doesn't make sense for other, not-in-development projects to depend on it (e.g. it might be buggy, have an unstable API at the moment.) The developer might want, in addition to building the package, to run tests and/or benchmarks.
Current workflow (assuming that cabal repl exists): cabal configure --enable-tests --enable-benchmarks cabal install --only-dependencies # does this pull in test/benchmark deps? cabal build -or cabal build && cabal test -or- cabal build && cabal benchmark -or- cabal repl
Problems with current workflow:
- Dependencies might be added/removed during development, forcing the developer to re-run configure --enable-tests --enable-benchmarks, cabal install --only-dependencies.
- It's not possible to build the package without configuring it and install its dependencies, thus those should be implied by build.
- It's not possible to run tests/benchmarks without first building the package, so building should be implied by running cabal test/bench.
Ideal workflow:
cabal build -or- cabal test -or- cabal bench -or- cabal repl
Developer working on multiple local packages
Like "Developer working on a single package", except the developer also has to change one or more dependencies in order to make the current package work e.g. perhaps he/she needs to add a new function to one of the dependencies and use it in the package under development. The dependencies might not be owner by the developer so he/she can't simply change them and make a new release. He/she needs to use the modified version until the changes have been accepted upstream.
Current workflow:
cd dep cabal configure && cabal build cd pkg cabal configure --package-db=../dep/dist/package.conf.inplace # Like previous use case when it comes to running tests, install other dependencies, etc.
Problems with current workflow:
- Every time the package depended upon needs to be changed, the four steps above have to be repeated.
- Otherwise the same as in "Developer working on a single package"
Ideal workflow (UI up for discussion):
cabal build --package-root=$HOME/src # Looks for additional packages here
Similar for cabal test, cabal bench, and cabal repl
In-house developer team working on multiple packages with local hackage server
This is similar to the above "Developer working on multiple local packages" case but there is a team of programmers producing and consuming packages. Development versions of packages are shared using source control, and developers can publish versions of packages to the local hackage server. Developers work using a combination of packages from hackage.haskell.org, the local hackage server (which has some bug fix versions of 3rd party packages as well as packages published by the team), and packages checked out from source control. There are also testing servers which build from the local hackage server rather than from source repos.
Existing tools
cabal-dev
- http://hackage.haskell.org/package/cabal-dev
- https://github.com/creswick/cabal-dev/blob/master/README.md
cabal-dev provides what it calls a sandbox for source packages and installed packages. cabal-dev has a command line interface that is very similar to that of cabal, so that it can be used as a drop-in replacement. It is implemented as a wrapper around the cabal-install command.
For source packages, the sandboxing mean providing a local source package set that overrides the global package index. Tarballs can be added to this index. It provides a command cabal-dev add-source /path/to/source/code which generate an sdist snapshot of the given package and adds that tarball to the local source index.
For installed packages, the sandboxing means that packages are not registered into the user or global ghc package database. The global package db is used, so it is recommended that the global package db is only used for the ghc core libraries. This approach conflicts with using distribution packages for non-core libraries, because they are installed into the global db.
The user interface provides two ways to install a package into a sandbox, either to add the source package into the sandbox, or to install a package into the sandbox. In the latter case the source is not available if something needed to be rebuilt (e.g. needed profiling version later).
Note that when source packages are added to the sandbox, it is a snapshot of the package, not a live link to another build tree. This is probably not by design, but a limitation of cabal that cabal-dev cannot easily fix.
The default install location for cabal-dev is the sandbox. This means it only works with packages that are prefix independent. Libraries or programs that use the Paths_pkgname module, e.g. to find data files would expect to find those files also in the sandbox. This is ok for running inplace but not if applications will be installed to some system location in the end. This would be better if we had a reliable way to build prefix-independent packages (or fail for ones that are not prefix-independent).
When you do cabal-dev add-source to add a source package to the sandbox, we think that just makes that version available, and it does not mask all other versions of that package. One has to rely on the added source package having a higher version, and rely on the solver to pick the highest version (which is will if possible, but will fall back to older versions if necessary).
cabal-src
- http://hackage.haskell.org/package/cabal-src
- https://github.com/yesodweb/cabal-src/blob/master/README.md
cabal-meta
cab
virthualenv
- http://hackage.haskell.org/package/virthualenv
- https://github.com/Paczesiowa/virthualenv/blob/master/README.md
Package environments ideas
Roles: The package author and package builder are distinct roles (though in many use cases the same individual may fill both roles):
- The package author specifies information in the package .cabal file.
- The package environment is controlled by the person/agent doing the build.
A package environment consists of:
- source package set
- installed package store
- constraints for package versions and flags
- other build configuration (profiling, optimisation, C lib locations etc)
The source package set is a finite mapping of source package id to a location where we can find a source package. This includes references to source tarballs (remotely or locally) and references to local build trees.
The installed package store is a location where packages are installed, plus a package database where installed packages are registered.
The constraints include:
- package version constraints, like "foo == 1.0"
- configuration flags for particular packages (that is the "flags" stuff in .cabal files)
- enabling/disabling of test suites or benchmarks
These constraints influence which source packages can be used and the configuration influence what the dependencies of those packagea are.
Other build configuration includes most of the other command line flags that package builders can currently specify when they do cabal configure:
- enable/disable profiling
- dynamic or static linking
- where to look for C libraries
- optimisation settings
- etc
Mechanisms for an implementation
The existing hackage index format gives us a source package set but has the limitation that it cannot refer to local build trees. It is relatively straightfoward to generalise the existing hackage index format to make it possible to refer to local tarballs or directories.
TODO: what about references to repositories (darcs, git etc) ?
