🌿 Foliage is a tool to create custom Haskell package repositories, in a fully reproducible way.
Go to file
Andrea Bedini 080197e9e2
Big rewrite
1. Foliage takes as input a complete description of the index, where
   source distributions and revisions come with a timestamp. This allows
   us to recreate the entire index in a reproducible way.

2. Added a experimental command to import an index from a Hackage (as
   downloaded with Cabal). This was originally a testing/development
   need but there might be different use cases.
2022-03-28 17:18:27 +08:00
.github/workflows Strip release artifacts 2022-03-11 14:15:49 +08:00
app Big rewrite 2022-03-28 17:18:27 +08:00
.gitignore Initial commit 2022-03-09 21:29:23 +08:00
foliage.cabal Big rewrite 2022-03-28 17:18:27 +08:00
NOTES-HRT.md Big rewrite 2022-03-28 17:18:27 +08:00
NOTES.md Initial commit 2022-03-09 21:29:23 +08:00
README.md Big rewrite 2022-03-28 17:18:27 +08:00

foliage

A hash-friendly Haskell Package Repository.

Foliage is a tool to create custom or private Haskell package repositories, in a fully reproducible way.

Main idea

Like GitHub Pages but for Haskell Packages

A "Hackage repository" is collection of source distributions and cabal files. In addition, Hackage has implemented The Update Framework (TUF) and the repository also includes cryptographic metadata (public keys and signatures).

These files are commonly served by Hackage proper, that is the central deployment of hackage-server.

Foliage explores the idea of creaating and serving this content as a static website, generated programmatically from textual input files.

Example

Foliage expects a folder _sources with a subfolder per package name and version.

E.g.

_sources
└── typed-protocols
    └── 0.1.0.0
        └── meta.toml

The file meta.toml describes a package and looks like this

timestamp = 2022-03-28T07:57:10Z
url = 'https://github.com/input-output-hk/ouroboros-network/tarball/d2d219a86cda42787325bb8c20539a75c2667132'
subdir = 'typed-protocols' # optional

Foliage will download the source url for each package (assumed to be a tarball), decompress it, make a source distribution and take the cabal file.

After all packages have been processed, foliage will create a repository, including the index and the TUF metadata. With the input above foliage will produce the following:

_repo
├── 01-index.tar
├── 01-index.tar.gz
├── index
│   └── typed-protocols
│       └── 0.1.0.0
│           ├── package.json
│           └── typed-protocols.cabal
├── mirrors.json
├── package
│   └── typed-protocols-0.1.0.0.tar.gz
├── root.json
├── snapshot.json
└── timestamp.json
  • typed-protocols-0.1.0.0.tar.gz is obtained by running cabal sdist of the repository (and, optionally, subfolder) specified in meta.toml.
  • type-protocols.cabal is extracted from the repository.
  • 01-index.tar will include the cabal files and signed target file, using the timestamp in meta.toml.
    $ TZ=UTC tar tvf _repo/01-index.tar
    -rw-r--r-- foliage/foliage 1627 2022-03-28 07:57 typed-protocols/0.1.0.0/typed-protocols.cabal
    -rw-r--r-- foliage/foliage  833 2022-03-28 07:57 typed-protocols/0.1.0.0/package.json
    
  • The TUF files (mirrors.json, root.json, snapshot.json, timestamp.json) are signed and contains reasonable defaults.

Revisions

Foliage supports cabal file revisions. Adding the following snippet to a package's meta.toml, will make foliage look for a cabal file in <pkgName>/<pkgVersion>/revisions/1.cabal.

[[revisions]]
  number = 1
  timestamp = 2022-03-22T14:15:00+00:00

The revised cabal file will enter the index with the timestamp provided in meta.toml.

Using the repository with cabal

The resulting repository can then be server through HTTPS and used with cabal, e.g. in a cabal.project:

repository packages.example.org
  url: https://packages.example.org/
  secure: True

Alternatively, cabal can read the repository directly off disk:

repository packages.example.org
  url: file:///path/to/_repo
  secure: True

Note: Hackage implements The Update Framework which requires a set of public and private keys. Foliage can either generate a new set of keys or reuse a pre-existing one. Cabal can either trust a repository at first use or verify signatures against public keys obtained separately.

Author

  • Andrea Bedini (@andreabedini)