canic_host/release_set/
manifest.rs1use serde::{Deserialize, Serialize};
2use std::{fs, path::Path};
3
4use crate::{
5 durable_io::write_bytes,
6 role_contract::{declared_role_manifest_path, finding_detail},
7};
8
9use super::{
10 build_release_set_entry, config_path, configured_release_roles, load_root_package_version,
11 resolve_artifact_root, root_release_set_manifest_path, workspace_manifest_path,
12};
13
14#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
19pub struct RootReleaseSetManifest {
20 pub release_version: String,
21 pub entries: Vec<ReleaseSetEntry>,
22}
23
24#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
29pub struct ReleaseSetEntry {
30 pub role: String,
31 pub template_id: String,
32 pub artifact_relative_path: String,
33 pub payload_size_bytes: u64,
34 pub payload_sha256_hex: String,
35 pub chunk_size_bytes: u64,
36 pub chunk_sha256_hex: Vec<String>,
37}
38
39pub fn emit_root_release_set_manifest(
41 workspace_root: &Path,
42 icp_root: &Path,
43 network: &str,
44) -> Result<std::path::PathBuf, Box<dyn std::error::Error>> {
45 let config_path = config_path(workspace_root);
46 emit_root_release_set_manifest_with_config(workspace_root, icp_root, network, &config_path)
47}
48
49pub fn emit_root_release_set_manifest_with_config(
51 workspace_root: &Path,
52 icp_root: &Path,
53 network: &str,
54 config_path: &Path,
55) -> Result<std::path::PathBuf, Box<dyn std::error::Error>> {
56 let artifact_root = resolve_artifact_root(icp_root, network)?;
57 let manifest_path = root_release_set_manifest_path(&artifact_root)?;
58 let root_manifest_path =
59 declared_role_manifest_path(config_path, &canic_core::ids::CanisterRole::ROOT)
60 .map_err(|finding| finding_detail(&finding))?;
61 let release_version = load_root_package_version(
62 &root_manifest_path,
63 &workspace_manifest_path(workspace_root),
64 )?;
65 let entries = configured_release_roles(config_path)?
66 .into_iter()
67 .map(|role_name| build_release_set_entry(icp_root, &artifact_root, &role_name))
68 .collect::<Result<Vec<_>, _>>()?;
69 let manifest = RootReleaseSetManifest {
70 release_version,
71 entries,
72 };
73
74 write_bytes(&manifest_path, &serde_json::to_vec_pretty(&manifest)?)?;
75 Ok(manifest_path)
76}
77
78pub fn emit_root_release_set_manifest_if_ready(
80 workspace_root: &Path,
81 icp_root: &Path,
82 network: &str,
83) -> Result<Option<std::path::PathBuf>, Box<dyn std::error::Error>> {
84 let config_path = config_path(workspace_root);
85 emit_root_release_set_manifest_if_ready_with_config(
86 workspace_root,
87 icp_root,
88 network,
89 &config_path,
90 )
91}
92
93pub fn emit_root_release_set_manifest_if_ready_with_config(
96 workspace_root: &Path,
97 icp_root: &Path,
98 network: &str,
99 config_path: &Path,
100) -> Result<Option<std::path::PathBuf>, Box<dyn std::error::Error>> {
101 let artifact_root = resolve_artifact_root(icp_root, network)?;
102 let roles = configured_release_roles(config_path)?;
103
104 for role_name in roles {
105 let artifact_path = artifact_root
106 .join(&role_name)
107 .join(format!("{role_name}.wasm.gz"));
108 if !artifact_path.is_file() {
109 return Ok(None);
110 }
111 }
112
113 emit_root_release_set_manifest_with_config(workspace_root, icp_root, network, config_path)
114 .map(Some)
115}
116
117pub fn load_root_release_set_manifest(
119 manifest_path: &Path,
120) -> Result<RootReleaseSetManifest, Box<dyn std::error::Error>> {
121 let source = fs::read(manifest_path)?;
122 Ok(serde_json::from_slice(&source)?)
123}