Skip to content

Commit e3abce5

Browse files
author
Damien LACHAUME / PALO-IT
committed
Extract generations methods in fake aggregator build script to a dedicated crate
1 parent 6fc30f1 commit e3abce5

File tree

8 files changed

+316
-228
lines changed

8 files changed

+316
-228
lines changed

Cargo.lock

Lines changed: 5 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
@@ -8,6 +8,7 @@ members = [
88
"examples/client-mithril-stake-distribution",
99
"examples/client-snapshot",
1010
"mithril-aggregator",
11+
"mithril-build-script",
1112
"mithril-client",
1213
"mithril-client-cli",
1314
"mithril-client-wasm",

mithril-build-script/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
target/
2+
.DS_Store
3+

mithril-build-script/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "mithril-build-script"
3+
version = "0.1.0"
4+
authors = { workspace = true }
5+
edition = { workspace = true }
6+
homepage = { workspace = true }
7+
license = { workspace = true }
8+
repository = { workspace = true }
9+
10+
[dependencies]
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
use std::collections::BTreeMap;
2+
use std::collections::BTreeSet;
3+
use std::fmt::Write as _;
4+
use std::fs;
5+
use std::path::Path;
6+
7+
pub type ArtifactId = String;
8+
pub type FileContent = String;
9+
10+
/// In memory representation of a folder containing data imported using the `scripts/import.sh` script
11+
/// of the fake aggregator.
12+
///
13+
/// List items are just their corresponding file content loaded in memory.
14+
/// Individual items are btreemap with the source filename as key and the file content as value.
15+
#[derive(Debug, Default)]
16+
pub struct DataFolder {
17+
epoch_settings: FileContent,
18+
19+
certificates_list: FileContent,
20+
individual_certificates: BTreeMap<ArtifactId, FileContent>,
21+
22+
snapshots_list: FileContent,
23+
individual_snapshots: BTreeMap<ArtifactId, FileContent>,
24+
25+
msds_list: FileContent,
26+
individual_msds: BTreeMap<ArtifactId, FileContent>,
27+
28+
ctx_commitments_list: FileContent,
29+
individual_ctx_commitments: BTreeMap<ArtifactId, FileContent>,
30+
ctx_proofs: BTreeMap<ArtifactId, FileContent>,
31+
}
32+
33+
impl DataFolder {
34+
pub fn load_from_folder(folder: &Path) -> Self {
35+
fn extract_artifact_id(filename: &str, prefix: &str) -> String {
36+
let id_with_extension = filename.strip_prefix(prefix).unwrap();
37+
id_with_extension.strip_suffix(".json").unwrap().to_string()
38+
}
39+
40+
let mut data_folder = DataFolder::default();
41+
42+
for entry in list_json_files_in_folder(folder) {
43+
let filename = entry.file_name().to_string_lossy().to_string();
44+
let file_content = fs::read_to_string(&entry.path()).unwrap_or_else(|_| {
45+
panic!(
46+
"Could not read file content, file_path: {}",
47+
entry.path().display()
48+
)
49+
});
50+
51+
match filename.as_str() {
52+
"epoch-settings.json" => {
53+
data_folder.epoch_settings = file_content;
54+
}
55+
"mithril-stake-distributions.json" => {
56+
data_folder.msds_list = file_content;
57+
}
58+
"snapshots.json" => {
59+
data_folder.snapshots_list = file_content;
60+
}
61+
"certificates.json" => {
62+
data_folder.certificates_list = file_content;
63+
}
64+
"ctx-commitments.json" => {
65+
data_folder.ctx_commitments_list = file_content;
66+
}
67+
_ if filename.starts_with("mithril-stake-distribution-") => {
68+
data_folder.individual_msds.insert(
69+
extract_artifact_id(&filename, "mithril-stake-distribution-"),
70+
file_content,
71+
);
72+
}
73+
_ if filename.starts_with("snapshot-") => {
74+
data_folder
75+
.individual_snapshots
76+
.insert(extract_artifact_id(&filename, "snapshot-"), file_content);
77+
}
78+
_ if filename.starts_with("certificate-") => {
79+
data_folder
80+
.individual_certificates
81+
.insert(extract_artifact_id(&filename, "certificate-"), file_content);
82+
}
83+
_ if filename.starts_with("ctx-commitment-") => {
84+
data_folder.individual_ctx_commitments.insert(
85+
extract_artifact_id(&filename, "ctx-commitment-"),
86+
file_content,
87+
);
88+
}
89+
_ if filename.starts_with("ctx-proof-") => {
90+
data_folder
91+
.ctx_proofs
92+
.insert(extract_artifact_id(&filename, "ctx-proof-"), file_content);
93+
}
94+
// unknown file
95+
_ => {}
96+
}
97+
}
98+
99+
data_folder
100+
}
101+
102+
pub fn generate_code_for_all_data(self) -> String {
103+
format!(
104+
"use std::collections::BTreeMap;
105+
106+
{}
107+
",
108+
[
109+
generate_list_getter("epoch_settings", self.epoch_settings),
110+
generate_ids_array(
111+
"snapshot_digests",
112+
BTreeSet::from_iter(self.individual_snapshots.keys().cloned())
113+
),
114+
generate_artifact_getter("snapshots", self.individual_snapshots),
115+
generate_list_getter("snapshot_list", self.snapshots_list),
116+
generate_ids_array(
117+
"msd_hashes",
118+
BTreeSet::from_iter(self.individual_msds.keys().cloned())
119+
),
120+
generate_artifact_getter("msds", self.individual_msds),
121+
generate_list_getter("msd_list", self.msds_list),
122+
generate_ids_array(
123+
"certificate_hashes",
124+
BTreeSet::from_iter(self.individual_certificates.keys().cloned())
125+
),
126+
generate_artifact_getter("certificates", self.individual_certificates),
127+
generate_list_getter("certificate_list", self.certificates_list),
128+
generate_ids_array(
129+
"ctx_commitment_hashes",
130+
BTreeSet::from_iter(self.individual_ctx_commitments.keys().cloned())
131+
),
132+
generate_artifact_getter("ctx_commitments", self.individual_ctx_commitments),
133+
generate_list_getter("ctx_commitments_list", self.ctx_commitments_list),
134+
generate_ids_array(
135+
"proof_transaction_hashes",
136+
BTreeSet::from_iter(self.ctx_proofs.keys().cloned())
137+
),
138+
generate_artifact_getter("ctx_proofs", self.ctx_proofs),
139+
]
140+
.join(
141+
"
142+
143+
"
144+
)
145+
)
146+
}
147+
}
148+
149+
pub fn list_json_files_in_folder(folder: &Path) -> impl Iterator<Item = std::fs::DirEntry> + '_ {
150+
fs::read_dir(folder)
151+
.unwrap_or_else(|_| panic!("Could not read `{}` dir", folder.display()))
152+
.filter_map(move |e| {
153+
let entry = e.unwrap_or_else(|_| {
154+
panic!("Failed to read a file in the `{}` dir", folder.display())
155+
});
156+
match entry.file_type() {
157+
Ok(file_type) if file_type.is_file() => Some(entry),
158+
_ => None,
159+
}
160+
})
161+
.filter(|e| e.file_name().to_string_lossy().ends_with(".json"))
162+
}
163+
164+
// pub(crate) fn $fun_name()() -> BTreeMap<String, String>
165+
pub fn generate_artifact_getter(
166+
fun_name: &str,
167+
source_jsons: BTreeMap<ArtifactId, FileContent>,
168+
) -> String {
169+
let mut artifacts_list = String::new();
170+
171+
for (artifact_id, file_content) in source_jsons {
172+
write!(
173+
artifacts_list,
174+
r###"
175+
(
176+
"{}",
177+
r#"{}"#
178+
),"###,
179+
artifact_id, file_content
180+
)
181+
.unwrap();
182+
}
183+
184+
format!(
185+
r###"pub(crate) fn {}() -> BTreeMap<String, String> {{
186+
[{}
187+
]
188+
.into_iter()
189+
.map(|(k, v)| (k.to_owned(), v.to_owned()))
190+
.collect()
191+
}}"###,
192+
fun_name, artifacts_list
193+
)
194+
}
195+
196+
/// pub(crate) fn $fun_name() -> &'static str
197+
pub fn generate_list_getter(fun_name: &str, source_json: FileContent) -> String {
198+
format!(
199+
r###"pub(crate) fn {}() -> &'static str {{
200+
r#"{}"#
201+
}}"###,
202+
fun_name, source_json
203+
)
204+
}
205+
206+
/// pub(crate) fn $fun_name() -> &'static str
207+
pub fn generate_ids_array(array_name: &str, ids: BTreeSet<ArtifactId>) -> String {
208+
let mut ids_list = String::new();
209+
210+
for id in &ids {
211+
write!(
212+
ids_list,
213+
r#"
214+
"{}","#,
215+
id
216+
)
217+
.unwrap();
218+
}
219+
220+
format!(
221+
r###"pub(crate) const fn {}<'a>() -> [&'a str; {}] {{
222+
[{}
223+
]
224+
}}"###,
225+
array_name,
226+
ids.len(),
227+
ids_list,
228+
)
229+
}
230+
231+
#[cfg(test)]
232+
mod tests {
233+
use super::*;
234+
}

mithril-build-script/src/lib.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use std::path::PathBuf;
2+
3+
pub mod fake_aggregator;
4+
5+
pub fn get_package_path(package_name: &str) -> PathBuf {
6+
let cargo_pkgid_output = std::process::Command::new(env!("CARGO"))
7+
.args(["pkgid", "--quiet", "-p", package_name])
8+
.output()
9+
.unwrap();
10+
11+
match cargo_pkgid_output.status.success() {
12+
true => {
13+
let package_name = std::str::from_utf8(&cargo_pkgid_output.stdout)
14+
.unwrap()
15+
.trim()
16+
.strip_prefix("path+file://")
17+
.unwrap()
18+
.split('#')
19+
.collect::<Vec<_>>()[0];
20+
21+
PathBuf::from(package_name)
22+
}
23+
false => {
24+
panic!(
25+
"cargo pkgid failed: stderr: {}",
26+
std::str::from_utf8(&cargo_pkgid_output.stderr)
27+
.unwrap()
28+
.trim()
29+
)
30+
}
31+
}
32+
}
33+
34+
#[cfg(test)]
35+
mod tests {
36+
use super::*;
37+
38+
#[test]
39+
fn get_package_path_should_return_path_of_existing_package() {
40+
let expected = PathBuf::from("./../mithril-aggregator/")
41+
.canonicalize()
42+
.unwrap();
43+
44+
let package_path = get_package_path("mithril-aggregator");
45+
46+
assert_eq!(package_path, expected);
47+
}
48+
49+
#[test]
50+
#[should_panic]
51+
fn get_package_path_panic_if_valid_name_of_not_existing_package() {
52+
get_package_path("it-does-not-exist");
53+
}
54+
55+
#[test]
56+
#[should_panic]
57+
fn get_package_path_panic_if_invalid_package_name() {
58+
get_package_path("Invalid Package Name ~~~");
59+
}
60+
}

mithril-test-lab/mithril-aggregator-fake/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ reqwest = "0.11.23"
3333
warp = "0.3.6"
3434

3535
[build-dependencies]
36-
serde_json = "1.0.113"
36+
mithril-build-script = { path = "../../mithril-build-script" }

0 commit comments

Comments
 (0)