Skip to content

Commit 080197e

Browse files
committed
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.
1 parent 5ce3fc0 commit 080197e

30 files changed

+1022
-1785
lines changed

NOTES-HRT.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Hackage Repo Tool
2+
3+
It looks like the update re-adds cabal files to the index based on
4+
timestamp but package.json on content?

README.md

Lines changed: 77 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -5,141 +5,122 @@ A hash-friendly Haskell Package Repository.
55
Foliage is a tool to create custom or private Haskell package repositories,
66
in a fully reproducible way.
77

8-
## Background
9-
10-
The problem of build reproducibility in the Haskell ecosystem has discussed
11-
many times. Hackage does not natively offer a way to pin down the files it
12-
serves.
13-
14-
Although there are workarounds to obtain a fixed repository (e.g. by
15-
truncating the index file, which is append only) I think we can solve this
16-
at the root.
17-
188
## Main idea
199

2010
_Like GitHub Pages but for Haskell Packages_
2111

22-
A "Hackage repository" is collection of files (source distributions, cabal
23-
files, public keys and signatures).
12+
A "Hackage repository" is collection of source distributions and cabal
13+
files. In addition, Hackage has implemented [The Update
14+
Framework (TUF)](https://theupdateframework.com) and the repository also
15+
includes cryptographic metadata (public keys and signatures).
2416

2517
These files are commonly served by Hackage proper, that is the central
2618
deployment of [hackage-server](https://github.com/haskell/hackage-server/).
2719

28-
Foliage explores the idea of serving this content as a static website,
29-
which is generated programmatically from a small set of input files.
20+
Foliage explores the idea of creaating and serving this content as a static
21+
website, generated programmatically from textual input files.
3022

31-
Both the input files and the generated repository can be stored in a git
32-
repository and referred to via stable URL corresponding to commit hashes.
23+
## Example
3324

25+
Foliage expects a folder `_sources` with a subfolder per package name and
26+
version.
3427

35-
## Example
28+
E.g.
3629

37-
An input file could look like the following
30+
```
31+
_sources
32+
└── typed-protocols
33+
   └── 0.1.0.0
34+
   └── meta.toml
35+
```
36+
37+
The file `meta.toml` describes a package and looks like this
3838

3939
```toml
40-
[[sources]]
41-
url = "https://.../source1.tar.gz"
42-
43-
[[sources]]
44-
url = "https://.../source2.tar.gz"
45-
subdirs = [
46-
"a",
47-
"b",
48-
"c"
49-
]
40+
timestamp = 2022-03-28T07:57:10Z
41+
url = 'https://github.com/input-output-hk/ouroboros-network/tarball/d2d219a86cda42787325bb8c20539a75c2667132'
42+
subdir = 'typed-protocols' # optional
5043
```
5144

52-
This file basically mirrors the functionality of
53-
[`source-repository-package`](https://cabal.readthedocs.io/en/3.6/cabal-project.html#specifying-packages-from-remote-version-control-locations)
54-
in Cabal.
45+
Foliage will download the source url for each package (assumed to be a
46+
tarball), decompress it, make a source distribution and take the cabal
47+
file.
5548

56-
For each source (and each subdir, if any is specified), foliage will
57-
download the tarball and make a sdist. Foliage will then use the
58-
hackage-repo-tool to create an on-disk repository (e.g. in `_repo`) from
59-
the collected packages. Additionally, one can specify revisions to each
60-
package version.
49+
After all packages have been processed, foliage will create a repository,
50+
including the index and the TUF metadata. With the input above foliage will
51+
produce the following:
52+
53+
```
54+
_repo
55+
├── 01-index.tar
56+
├── 01-index.tar.gz
57+
├── index
58+
│   └── typed-protocols
59+
│   └── 0.1.0.0
60+
│   ├── package.json
61+
│   └── typed-protocols.cabal
62+
├── mirrors.json
63+
├── package
64+
│   └── typed-protocols-0.1.0.0.tar.gz
65+
├── root.json
66+
├── snapshot.json
67+
└── timestamp.json
68+
```
69+
70+
* `typed-protocols-0.1.0.0.tar.gz` is obtained by running
71+
`cabal sdist` of the repository (and, optionally, subfolder) specified in
72+
`meta.toml`.
73+
* `type-protocols.cabal` is extracted from the repository.
74+
* `01-index.tar` will include the cabal files and signed target file, using
75+
the timestamp in `meta.toml`.
76+
```bash
77+
$ TZ=UTC tar tvf _repo/01-index.tar
78+
-rw-r--r-- foliage/foliage 1627 2022-03-28 07:57 typed-protocols/0.1.0.0/typed-protocols.cabal
79+
-rw-r--r-- foliage/foliage 833 2022-03-28 07:57 typed-protocols/0.1.0.0/package.json
80+
```
81+
* The TUF files (`mirrors.json`, `root.json`, `snapshot.json`,
82+
`timestamp.json`) are signed and contains reasonable defaults.
83+
84+
## Revisions
85+
86+
Foliage supports cabal file revisions. Adding the following snippet to a
87+
package's `meta.toml`, will make foliage look for a cabal file in
88+
`<pkgName>/<pkgVersion>/revisions/1.cabal`.
89+
90+
```
91+
[[revisions]]
92+
number = 1
93+
timestamp = 2022-03-22T14:15:00+00:00
94+
```
95+
96+
The revised cabal file will enter the index with the timestamp provided in
97+
`meta.toml`.
98+
99+
## Using the repository with cabal
61100

62101
The resulting repository can then be server through HTTPS and used with
63-
cabal, e.g. in a `cabal.project`
102+
cabal, e.g. in a `cabal.project`:
64103

65104
```
66105
repository packages.example.org
67106
url: https://packages.example.org/
68107
secure: True
69108
```
70109

71-
Alternatively, cabal can read the repository directly off disk
110+
Alternatively, cabal can read the repository directly off disk:
72111

73112
```
74113
repository packages.example.org
75114
url: file:///path/to/_repo
76115
secure: True
77116
```
78117

79-
**Note:** The package id (package name + package version) is unknown at
80-
download time and only known after looking at the cabal file. This is the
81-
reason package names and versions do not show in the input file. Foliage
82-
ensures two sources do not provide colliding package ids.
83-
84118
**Note:** Hackage implements [The Update
85119
Framework](https://theupdateframework.io) which requires a set of public
86120
and private keys. Foliage can either generate a new set of keys or reuse a
87121
pre-existing one. Cabal can either trust a repository at first use or
88122
verify signatures against public keys obtained separately.
89123

90-
## GitHub
91-
92-
Foliage can make use of three features supported by GitHub, to further advance automation.
93-
94-
1. GitHub has long suppored accessing git repositories via HTTPS. E.g. one can access a blob in a git repo through the following URL.
95-
96-
https://raw.githubusercontent.com/{owner}/{repo}/{ref}/path
97-
98-
where `ref` can either be a commit hash or a branch name.
99-
100-
2. GitHub also offer URLs of tarballs for repos at given commit, e.g.
101-
102-
https://github.com/Quid2/flat/tarball/ee59880f47ab835dbd73bea0847dab7869fc20d8
103-
104-
Afaik, these tarballs might not be entirely immutable (TODO)
105-
106-
3. GitHub offers URLs for tagged releases (these tarballs are supposed to be immutable).
107-
108-
4. GitHub Actions can be used to automate the generation
109-
110-
5. (Perhaps optional) GitHub Pages supports publishing a git branch over HTTP.
111-
112-
This means we automatically have a stable url for any package whose source is available on GitHub.
113-
Also the generated repository can be committed to a git branch and be immediately available through HTTPS to cabal.
114-
115-
E.g.
116-
117-
This configuration
118-
119-
https://github.com/andreabedini/byo-hackage/blob/933760117a3800366b420b07c8c887c1313e2b22/packages.tsv
120-
121-
(warning old TSV format)
122-
123-
Generated this repo https://github.com/andreabedini/byo-hackage/tree/1e8c5184836acb05972dfff00ac8edca575e1df1
124-
125-
Which can be give to cabal like this
126-
127-
```
128-
repository my-hackage-repo
129-
url: https://raw.githubusercontent.com/andreabedini/byo-hackage/1e8c5184836acb05972dfff00ac8edca575e1df1
130-
secure: True
131-
```
132-
133-
## To infinity and Beyond
134-
135-
One can think of more features
136-
137-
- A pretty website could be automatically generated along with the
138-
repository. With a list of packages, their versions, metadata, etc
139-
- The input file itself could be automatically generated, e.g. from all
140-
tagged releases in a GitHub organisation. Making it a turn-key Hackage
141-
repository for any GitHub Organisation.
142-
143124
## Author
144125

145126
- Andrea Bedini (@andreabedini)

0 commit comments

Comments
 (0)