canic_host/canister_build/
context.rs1use std::{fs, path::PathBuf, process::Command};
2
3use canic_core::ids::BuildNetwork;
4
5use crate::icp::LocalReplicaTarget;
6
7use super::{
8 CanisterBuildProfile,
9 process::{icp_ancestor_process_id, parent_process_id},
10};
11
12#[derive(Clone, Debug, Eq, PartialEq)]
16pub struct WorkspaceBuildContext {
17 pub role: String,
18 pub profile: CanisterBuildProfile,
19 pub environment: String,
20 pub build_network: BuildNetwork,
21 pub workspace_root: PathBuf,
22 pub icp_root: PathBuf,
23 pub config_path: PathBuf,
24 pub local_replica: Option<LocalReplicaTarget>,
25 pub refresh_canonical_wasm_store_did: bool,
26}
27
28impl WorkspaceBuildContext {
29 #[must_use]
30 pub fn lines(&self) -> Vec<String> {
31 let mut lines = vec![
32 "Canic build:".to_string(),
33 format!("role: {}", self.role),
34 format!("profile: {}", self.profile.target_dir_name()),
35 format!("environment: {}", self.environment),
36 format!("build network: {}", self.build_network),
37 format!("workspace: {}", self.workspace_root.display()),
38 ];
39
40 if self.icp_root != self.workspace_root {
41 lines.push(format!("icp root: {}", self.icp_root.display()));
42 }
43
44 lines
45 }
46
47 #[must_use]
49 pub fn with_profile(&self, profile: CanisterBuildProfile) -> Self {
50 let mut context = self.clone();
51 context.profile = profile;
52 context
53 }
54
55 #[must_use]
57 pub fn with_role(&self, role: impl Into<String>) -> Self {
58 let mut context = self.clone();
59 context.role = role.into();
60 context
61 }
62
63 pub fn apply_to_command(&self, command: &mut Command) {
65 command
66 .env("ICP_ENVIRONMENT", self.build_network.as_str())
67 .env(
68 canic_core::role_contract::CANONICAL_BUILD_ICP_ROOT_ENV,
69 &self.icp_root,
70 )
71 .env(
72 canic_core::role_contract::CANONICAL_BUILD_CONFIG_PATH_ENV,
73 &self.config_path,
74 );
75 }
76}
77
78pub fn print_workspace_build_context_once(
81 context: &WorkspaceBuildContext,
82) -> Result<(), Box<dyn std::error::Error>> {
83 if workspace_build_context_once(context)? {
84 eprintln!("{}", context.lines().join("\n"));
85 }
86
87 Ok(())
88}
89
90pub fn workspace_build_context_once(
92 context: &WorkspaceBuildContext,
93) -> Result<bool, Box<dyn std::error::Error>> {
94 let marker_dir = context.icp_root.join(".icp");
95 fs::create_dir_all(&marker_dir)?;
96
97 let marker_key = icp_ancestor_process_id()
98 .or_else(parent_process_id)
99 .unwrap_or_else(std::process::id)
100 .to_string();
101 let marker_file = marker_dir.join(format!(".canic-build-context-{marker_key}"));
102
103 if marker_file.exists() {
104 return Ok(false);
105 }
106
107 fs::write(&marker_file, [])?;
108 Ok(true)
109}