1use std::{
4 io,
5 process::{Child, Command, Output},
6 thread,
7 time::Duration,
8};
9
10const EXECUTABLE_BUSY_RETRY_ATTEMPTS: usize = 8;
11const EXECUTABLE_BUSY_RETRY_DELAY: Duration = Duration::from_millis(10);
12
13mod artifact_io;
14pub mod binaryen;
15mod bootstrap_candid;
16mod bootstrap_coordinator;
17mod bootstrap_store;
18mod build_profile;
19pub mod build_provenance;
20pub mod build_toolchain;
21pub mod candid_endpoints;
22pub mod canic_metadata;
23pub mod canister_build;
24mod canister_protocol;
25mod canonical_root;
26mod fleet_package;
27pub use canister_protocol::{
28 CanisterProtocolError, call_with_arg as call_canister_with_arg,
29 query_with_arg as query_canister_with_arg,
30};
31pub mod canister_ready;
32mod cargo_metadata;
33pub mod component_topology;
34pub mod config_discovery;
35pub mod diagnostics;
36pub mod durable_io;
37mod entropy;
38pub mod evidence_envelope;
39pub mod fleet_ensure;
40pub mod format;
41pub mod ic_wasm;
42pub mod icp;
43pub mod icp_config;
44pub mod network;
45pub mod observability;
46pub mod policy_gate;
47pub mod protocol_binding;
48pub mod registry;
49pub mod release_build;
50pub mod release_set;
51pub mod replica_query;
52pub mod role_contract;
53pub mod state_manifest;
54pub mod subnet_catalog;
55pub mod table;
56pub mod terminal;
57#[cfg(test)]
58mod test_support;
59mod workspace_discovery;
60
61pub(crate) fn cargo_command() -> Command {
62 let cargo = std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into());
63 let mut command = Command::new(cargo);
64
65 if let Some(toolchain) = std::env::var_os("RUSTUP_TOOLCHAIN") {
66 command.env("RUSTUP_TOOLCHAIN", toolchain);
67 }
68 command
69}
70
71fn with_executable_busy_retry<T>(mut launch: impl FnMut() -> io::Result<T>) -> io::Result<T> {
72 for attempt in 0..EXECUTABLE_BUSY_RETRY_ATTEMPTS {
73 match launch() {
74 Err(error)
75 if error.kind() == io::ErrorKind::ExecutableFileBusy
76 && attempt + 1 < EXECUTABLE_BUSY_RETRY_ATTEMPTS =>
77 {
78 thread::sleep(EXECUTABLE_BUSY_RETRY_DELAY);
79 }
80 result => return result,
81 }
82 }
83 unreachable!("bounded executable-busy retry always returns on its final attempt")
84}
85
86pub(crate) fn output_with_executable_busy_retry(command: &mut Command) -> io::Result<Output> {
87 with_executable_busy_retry(|| command.output())
88}
89
90pub(crate) fn spawn_with_executable_busy_retry(command: &mut Command) -> io::Result<Child> {
91 with_executable_busy_retry(|| command.spawn())
92}
93
94pub(crate) fn should_embed_candid_metadata(build_network: canic_core::ids::BuildNetwork) -> bool {
95 build_network == canic_core::ids::BuildNetwork::Local
96}
97
98#[cfg(test)]
99mod tests;