Skip to main content

canic_host/release_set/
manifest.rs

1use serde::{Deserialize, Serialize};
2use std::{fs, path::Path};
3
4use super::{
5    build_release_set_entry, config_path, configured_release_roles, load_root_package_version,
6    resolve_artifact_root, root_manifest_path, root_release_set_manifest_path,
7    workspace_manifest_path,
8};
9
10///
11/// RootReleaseSetManifest
12///
13
14#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
15pub struct RootReleaseSetManifest {
16    pub release_version: String,
17    pub entries: Vec<ReleaseSetEntry>,
18}
19
20///
21/// ReleaseSetEntry
22///
23
24#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
25pub struct ReleaseSetEntry {
26    pub role: String,
27    pub template_id: String,
28    pub artifact_relative_path: String,
29    pub payload_size_bytes: u64,
30    pub payload_sha256_hex: String,
31    pub chunk_size_bytes: u64,
32    pub chunk_sha256_hex: Vec<String>,
33}
34
35// Build and persist the current root release-set manifest from built `.wasm.gz` artifacts.
36pub fn emit_root_release_set_manifest(
37    workspace_root: &Path,
38    icp_root: &Path,
39    network: &str,
40) -> Result<std::path::PathBuf, Box<dyn std::error::Error>> {
41    let config_path = config_path(workspace_root);
42    emit_root_release_set_manifest_with_config(workspace_root, icp_root, network, &config_path)
43}
44
45// Build and persist the current root release-set manifest with an explicit config path.
46pub fn emit_root_release_set_manifest_with_config(
47    workspace_root: &Path,
48    icp_root: &Path,
49    network: &str,
50    config_path: &Path,
51) -> Result<std::path::PathBuf, Box<dyn std::error::Error>> {
52    let artifact_root = resolve_artifact_root(icp_root, network)?;
53    let manifest_path = root_release_set_manifest_path(&artifact_root)?;
54    let root_manifest_path = root_manifest_path(workspace_root)?;
55    let release_version = load_root_package_version(
56        &root_manifest_path,
57        &workspace_manifest_path(workspace_root),
58    )?;
59    let entries = configured_release_roles(config_path)?
60        .into_iter()
61        .map(|role_name| build_release_set_entry(icp_root, &artifact_root, &role_name))
62        .collect::<Result<Vec<_>, _>>()?;
63    let manifest = RootReleaseSetManifest {
64        release_version,
65        entries,
66    };
67
68    fs::write(&manifest_path, serde_json::to_vec_pretty(&manifest)?)?;
69    Ok(manifest_path)
70}
71
72// Emit the root release-set manifest only once every required ordinary artifact exists.
73pub fn emit_root_release_set_manifest_if_ready(
74    workspace_root: &Path,
75    icp_root: &Path,
76    network: &str,
77) -> Result<Option<std::path::PathBuf>, Box<dyn std::error::Error>> {
78    let artifact_root = resolve_artifact_root(icp_root, network)?;
79    let roles = configured_release_roles(&config_path(workspace_root))?;
80
81    for role_name in roles {
82        let artifact_path = artifact_root
83            .join(&role_name)
84            .join(format!("{role_name}.wasm.gz"));
85        if !artifact_path.is_file() {
86            return Ok(None);
87        }
88    }
89
90    emit_root_release_set_manifest(workspace_root, icp_root, network).map(Some)
91}
92
93// Load one previously emitted root release-set manifest from disk.
94pub fn load_root_release_set_manifest(
95    manifest_path: &Path,
96) -> Result<RootReleaseSetManifest, Box<dyn std::error::Error>> {
97    let source = fs::read(manifest_path)?;
98    Ok(serde_json::from_slice(&source)?)
99}