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_pool_ledger_recovery;
18
19pub use bootstrap_pool_ledger_recovery::prepare_pool_ledger_recovery_build;
20mod bootstrap_store;
21mod build_profile;
22pub mod build_provenance;
23pub mod candid_endpoints;
24pub mod canic_metadata;
25pub mod canister_build;
26mod canister_protocol;
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 cycle_balance;
36pub mod diagnostics;
37pub mod durable_io;
38mod entropy;
39pub mod evidence_envelope;
40pub mod fleet_catalog;
41pub mod fleet_ensure;
42pub mod format;
43pub mod icp;
44pub mod icp_config;
45pub mod network;
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;