As mentioned above, the foremost user interface for this system will be a Haskell program to be executed by the default Haskell Implementation. This Haskell program, Setup.lhs, will perform the tasks of building the package (where necessary), installing the package, and making the package available to the system.
I propose a set of modules based on these three major tasks:
Distribution.Build
: For tasks of preparing the package for
installation, including tasking compilers and creating packages for
systems like Debian (Section 4.1).
Distribution.Install
: For moving the distribution files
into place (Section 4.2).
Distribution.Package
: For
accessing the database of installed packages, versions, etc. Might
also be responsible for removing packages (Section 4.3).
Distribution.Config
: For discovering details about the
configuration of the target system not covered by the database of
installed packages. These are tasks typically performed by tools
such as autoconf (Section 4.6).
Distribution
: For general
purpose elements that don't fit into any of the above
categories.
It is very appropriate that this solution be implemented in Haskell:
Haskell runs on all the systems of interest.
Haskell's standard libraries should include a rich set of operating system operations needed for the task. These can abstract-away the differences between systems in a way that is not possible for Make-based tools.
Haskell is a great language for many things, including tasks typically relegated to languages like Python. Building, installing, and managing packages is a perfect proving ground for these tasks, and can help us to discover weaknesses in Haskell or its libraries that prevent it from breaking into this "market". A positive side-effect of this project might be to make Haskell more suitable for "scripting" tasks.
Likewise, each piece of the project (Building, Installing, and Packaging) can be leveraged elsewhere if we make them into libraries.
Make is not particularly good for parsing, processing, and sharing meta-information about packages. The availability of this information to Haskell systems (including compilers, interpreters, and other tools) is useful. Unlike Make, Haskell can also reuse unrelated algorithms, parsers, and other libraries that have been developed in the past.
Dogfooding, the act of using the tools you develop, is a healthy policy.
The purpose of the Setup script is to provide a standard
interface to end users and layered tools. For any particular
application, the script may be implemented in a variety of ways:
For pure Haskell applications, the Distribution
module should perform all
of the heavy lifting, requiring only a few lines of code from the
developer. For applications that feel they need a complete and
robust make-based system, the Setup script can wrap such a
system.
One of the early design tasks of this project should be to decide on a format for the command-line interface of the Setup script, but here is an example of how it might behave:
Table 1. Setup.lhs interface
./Setup.lhs info | Output package configuration information |
./Setup.lhs build all | Compile / prepare this package for all installed Haskell Implementations |
./Setup.lhs build default | Compile / prepare this package for the default Haskell Implementation |
./Setup.lhs build {NHC,GHC,Hugs, ...} | Compile / prepare this package for the given Haskell Implementation |
./Setup.lhs install {all,default,NHC,GHC,Hugs,...} | Install this package. |
./Setup.lhs register {all,default,NHC,GHC,Hugs,...} | Register this package with the package management system (making it available to the given Haskell Implementation.) |
./Setup.lhs bdist_{deb,rpm,...} | Create a binary distribution package for Debian, RPM, etc. |
./Setup.lhs sdist | Create a source distribution archive. |
./Setup.lhs test | Run the package's test suite. |
Other commands may be available, and it is important to anticipate commands that may some day be desirable.
Here's what the setup script might look like for HUnit, which has no complex dependencies.
#!/usr/bin/env haskell import Distribution.Core import Distribution.Package toolInfo = (defaultPackage "HUnit" (NumberedVersion 1 0 0)) {haskellSources=[ "HUnitLang98.lhs","HUnitLangExc.lhs", "Info.lhs", "Terminal.lhs", "HUnitTest98.lhs", "TerminalTest.lhs", "HUnit.lhs", "HUnitTestBase.lhs", "HUnitBase.lhs", "HUnitTestExc.lhs", "HUnitLang.lhs", "HUnitText.lhs", "Setup.lhs"], docs = ["Example.hs", "Guide.html", "License", "README"]} main = defaultMain toolInfo id id -- Those last to parameters might be pre-install and post-install functions
defaultMain
would implement all of the
standard command-line flags, and defaultPackage is a template with
sane default values for most fields.