Skip to content
This repository was archived by the owner on Oct 28, 2024. It is now read-only.

Commit 576fd2a

Browse files
authored
Handler-centric HIPPPOFACTS file (#15)
1 parent 44be7a9 commit 576fd2a

31 files changed

+681
-62
lines changed

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ clap = { version = "3.0.0-beta.2" }
1414
dunce = "1.0"
1515
futures = "0.3.14"
1616
glob = "0.3.0"
17+
itertools = "0.10.0"
1718
mime_guess = { version = "2.0" }
1819
semver = { version = "0.11", features = ["serde"] }
1920
serde = {version = "1.0", features = ["derive"]}

README.md

Lines changed: 181 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,188 @@
11
# hippofactory
22

33
The `hippofactory` tool processes an application's `HIPPOFACTS` (Hippo
4-
artifacts) file and generates a standalone Bindle that can be uploaded
5-
using `bindle push`.
4+
artifacts) file and generates a bindle that it can either push directly
5+
or can later be uploaded using `bindle push`.
66

7+
## The HIPPOFACTS file
8+
9+
HIPPOFACTS is a TOML file with the following structure:
10+
11+
```toml
12+
[bindle]
13+
name = "birdsondemand"
14+
version = "1.2.3"
15+
description = "provides birds as a service" # optional
16+
authors = ["Joan Q Programmer"] # optional
17+
18+
[[handler]]
19+
route = "/birds/flightless"
20+
name = "bin/penguin.wasm"
21+
files = ["photo/adelie.png", "photo/rockhopper.png", "stock/*.jpg"]
22+
23+
[[handler]]
24+
route = "/birds/irritable/fighty"
25+
name = "bin/cassowary.wasm"
26+
# files key is optional
27+
28+
[[handler]]
29+
route = "/birds/naughty"
30+
name = "bin/kea.wasm"
31+
files = ["stock/kea.jpg", "stock/wipers.jpg"]
32+
```
33+
34+
The `bindle` section is copied directly to `invoice.toml`, _except_ that in development
35+
mode a prerelease segment is appended to the version to make it unique.
36+
37+
Each `handler` table is processed as follows:
38+
39+
* A group for the handler is added to the invoice
40+
* The `name` value is looked up in the file system, and a parcel is entered into the invoice
41+
for the corresponding file. The parcel's `conditions.requires` is set to the handler group.
42+
* If the handler has a `files` key, all patterns in that array are matched against the file
43+
system, and a parcel is entered into the invoice for the corresponding file. The parcel
44+
`label.name` is the relative path of the file to the `HIPPOFACTS` file.The parcel's
45+
`conditions.memberOf` is set to a list of _all_ handler groups that contained patterns that
46+
the file matched - this may be more than one if multiple handler file patterns matched the
47+
same file.
48+
49+
For example, given the following file structure:
50+
51+
```
52+
|- HIPPOFACTS
53+
|- src
54+
| |- main.rs
55+
| |- utils.rs
56+
|- bin
57+
| |- cassowary.wasm
58+
| |- kea.wasm
59+
| |- kokako.wasm
60+
| |- penguin.wasm
61+
|- photo
62+
| |- adelie.png
63+
| |- emperor.png
64+
| |- rockhopper.png
65+
|- stock
66+
|- kea.jpg
67+
|- little-blue.jpg
68+
|- little-blue.png
69+
|- wipers.jpg
70+
```
71+
72+
the previous `HIPPOFACTS` would create the following invoice (omitting some details
73+
and adding comments):
74+
75+
```toml
76+
bindleVersion = '1.0.0'
77+
78+
[bindle]
79+
name = 'birdsondemand'
80+
version = '1.2.3-ivan-2021.05.18.10.51.09.084'
81+
description = 'provides birds as a service'
82+
authors = ['Joan Q Programmer']
83+
84+
# Parcels representing handler WASM modules have a `requires` attribute
85+
86+
[[parcel]]
87+
[parcel.label]
88+
sha256 = '0a4346f806b28b3ce94905c3ac56fcd5ee2337d8613161696aba52eb0c3551cc'
89+
name = 'bin/penguin.wasm'
90+
[parcel.conditions]
91+
requires = ['bin/penguin.wasm-files']
92+
93+
[[parcel]]
94+
[parcel.label]
95+
sha256 = '1f71511371129511321c45be058c60e23cf9ba898d8a3f3309555985b5027490'
96+
name = 'bin/cassowary.wasm'
97+
[parcel.conditions]
98+
requires = ['bin/cassowary.wasm-files']
99+
100+
[[parcel]]
101+
[parcel.label]
102+
sha256 = 'bab02c178882085bf20defd15c0e8971edd95488a1ecb4a6273e6afcfb3c4030'
103+
name = 'bin/kea.wasm'
104+
[parcel.conditions]
105+
requires = ['bin/kea.wasm-files']
106+
107+
# Parcels derived from `files` patterns have a `memberOf` attribute
108+
109+
[[parcel]]
110+
[parcel.label]
111+
sha256 = 'e99f19705a23cbeeeade5d2b4f8b83fff09beb093552e82073cdb302ee10eb76'
112+
name = 'photo/adelie.png'
113+
[parcel.conditions]
114+
memberOf = ['bin/penguin.wasm-files']
115+
116+
[[parcel]]
117+
[parcel.label]
118+
sha256 = 'e8f7b60dfe5ee560edd1ac616463a0682a0e7c57a5ce2a8fe5c0990e500d0ac5'
119+
name = 'photo/rockhopper.png'
120+
[parcel.conditions]
121+
memberOf = ['bin/penguin.wasm-files']
122+
123+
[[parcel]]
124+
[parcel.label]
125+
sha256 = '843baaf5a63cbc38d4d4c00036b95e435254eece7480fb717c8a17dcdc2aeefc'
126+
name = 'stock/little-blue.jpg'
127+
[parcel.conditions]
128+
memberOf = ['bin/penguin.wasm-files']
129+
130+
# Some files are matched by more than one handler's patterns
131+
132+
[[parcel]]
133+
[parcel.label]
134+
sha256 = '6451ab5be799a6aa52ce8b8a084a12066bb2dd8e1a73a692627bb96b4b9a72f0'
135+
name = 'stock/wipers.jpg'
136+
[parcel.conditions]
137+
memberOf = [
138+
'bin/penguin.wasm-files',
139+
'bin/kea.wasm-files',
140+
]
141+
142+
[[parcel]]
143+
[parcel.label]
144+
sha256 = '93c3a391d842e3b8032d560db4870b5426c5c05a9f2a60b187e567ae69d8e658'
145+
name = 'stock/kea.jpg'
146+
[parcel.conditions]
147+
memberOf = [
148+
'bin/penguin.wasm-files',
149+
'bin/kea.wasm-files',
150+
]
151+
152+
# Group per handler
153+
154+
[[group]]
155+
name = 'bin/penguin.wasm-files'
156+
157+
[[group]]
158+
name = 'bin/cassowary.wasm-files'
159+
160+
[[group]]
161+
name = 'bin/kea.wasm-files'
162+
```
163+
164+
`hippofactory` does not currently support Bindle's `parcel.label.feature`
165+
or `signature` features. It does not yet support push options other than the server URL (e.g. auth).
166+
167+
## Running hippofactory
168+
169+
As a developer you can run `hippofactory .` in your `HIPPOFACTS` directory to assemble all matching
170+
files and push them to the Bindle server specified in the `BINDLE_SERVER_URL` environment variable.
171+
(If you don't want to set the environment variable, pass the `-s` argument with the URL.)
172+
173+
In this mode, `hippofactory`:
174+
175+
* Mangles the version with a prerelease segment
176+
* Stages to a temporary directory
177+
* Pushes to the Bindle server
178+
179+
If you want to review the proposed bindle rather than pushing it, pass `--prepare -d <staging_dir>`.
180+
This will stage the bindle to the specified directory but _not_ push it. (If you later want
181+
to push it, you can do so using the separate `bindle` tool.)
182+
183+
In a CI environment you can supply the `-v production` option to suppress version mangling.
184+
This will create and upload the bindle with the version from `HIPPOFACTS`, without the
185+
prerelease segment.
7186
## Building from source
8187

9188
* Known link failure on WSL: workaround is to build once with `RUSTFLAGS='-C opt-level=0' cargo build`

src/bindle_pusher.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ use std::path::Path;
22

33
use bindle::standalone::StandaloneRead;
44

5-
pub async fn push_all(path: impl AsRef<Path>, bindle_id: &bindle::Id, base_url: &str) -> anyhow::Result<()> {
5+
pub async fn push_all(
6+
path: impl AsRef<Path>,
7+
bindle_id: &bindle::Id,
8+
base_url: &str,
9+
) -> anyhow::Result<()> {
610
let reader = StandaloneRead::new(&path, bindle_id).await?;
711
let client = bindle::client::Client::new(base_url)?;
812
reader.push(&client).await?;

src/bindle_writer.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,34 @@ impl BindleWriter {
2727
Ok(())
2828
}
2929

30-
async fn write_invoice_file(&self, invoice: &Invoice, bindle_dir: &PathBuf) -> anyhow::Result<()> {
30+
async fn write_invoice_file(
31+
&self,
32+
invoice: &Invoice,
33+
bindle_dir: &PathBuf,
34+
) -> anyhow::Result<()> {
3135
let invoice_text = toml::to_string_pretty(&invoice)?;
3236
let invoice_file = bindle_dir.join("invoice.toml");
3337
tokio::fs::write(&invoice_file, &invoice_text).await?;
3438
Ok(())
3539
}
3640

37-
async fn write_parcel_files(&self, invoice: &Invoice, parcels_dir: &PathBuf) -> anyhow::Result<()> {
41+
async fn write_parcel_files(
42+
&self,
43+
invoice: &Invoice,
44+
parcels_dir: &PathBuf,
45+
) -> anyhow::Result<()> {
3846
let parcels = match &invoice.parcel {
3947
Some(p) => p,
4048
None => return Ok(()),
4149
};
4250

43-
let parcel_writes = parcels.iter().map(|parcel| self.write_one_parcel(parcels_dir, &parcel));
44-
futures::future::join_all(parcel_writes).await.into_iter().collect::<anyhow::Result<Vec<_>>>()?;
51+
let parcel_writes = parcels
52+
.iter()
53+
.map(|parcel| self.write_one_parcel(parcels_dir, &parcel));
54+
futures::future::join_all(parcel_writes)
55+
.await
56+
.into_iter()
57+
.collect::<anyhow::Result<Vec<_>>>()?;
4558
Ok(())
4659
}
4760

0 commit comments

Comments
 (0)