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