Skip to main content

canic_host/
lib.rs

1//! Host-side App build and desired-state Fleet reconciliation for Canic workspaces.
2
3use 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_environment;
19mod build_profile;
20pub mod build_provenance;
21pub mod build_toolchain;
22pub mod candid_endpoints;
23pub mod canic_metadata;
24pub mod canister_build;
25mod canister_protocol;
26mod canonical_root;
27mod fleet_package;
28pub use canister_protocol::{
29    CanisterProtocolError, call_with_arg as call_canister_with_arg,
30    query_with_arg as query_canister_with_arg,
31};
32pub mod canister_ready;
33mod cargo_metadata;
34pub mod component_operation;
35pub mod component_topology;
36pub mod config_discovery;
37pub mod diagnostics;
38pub mod durable_io;
39mod entropy;
40pub mod evidence_envelope;
41pub mod fleet_ensure;
42pub mod format;
43pub mod frontend;
44pub mod ic_wasm;
45pub mod icp;
46pub mod icp_config;
47#[cfg(feature = "local-fleet")]
48pub mod local_fleet;
49pub mod network;
50pub mod observability;
51pub mod observatory;
52pub mod policy_gate;
53pub mod protocol_binding;
54pub mod registry;
55pub mod release_build;
56pub mod release_set;
57pub mod replica_query;
58pub mod role_contract;
59pub mod state_manifest;
60pub mod subnet_catalog;
61pub mod table;
62pub mod terminal;
63#[cfg(test)]
64mod test_support;
65mod tool_install;
66mod workspace_discovery;
67
68pub(crate) fn cargo_command() -> Command {
69    let cargo = std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into());
70    let mut command = build_environment::command(cargo);
71
72    if let Some(toolchain) = std::env::var_os("RUSTUP_TOOLCHAIN") {
73        command.env("RUSTUP_TOOLCHAIN", toolchain);
74    }
75    command
76}
77
78fn with_executable_busy_retry<T>(mut launch: impl FnMut() -> io::Result<T>) -> io::Result<T> {
79    for attempt in 0..EXECUTABLE_BUSY_RETRY_ATTEMPTS {
80        match launch() {
81            Err(error)
82                if error.kind() == io::ErrorKind::ExecutableFileBusy
83                    && attempt + 1 < EXECUTABLE_BUSY_RETRY_ATTEMPTS =>
84            {
85                thread::sleep(EXECUTABLE_BUSY_RETRY_DELAY);
86            }
87            result => return result,
88        }
89    }
90    unreachable!("bounded executable-busy retry always returns on its final attempt")
91}
92
93pub(crate) fn output_with_executable_busy_retry(command: &mut Command) -> io::Result<Output> {
94    with_executable_busy_retry(|| command.output())
95}
96
97pub(crate) fn spawn_with_executable_busy_retry(command: &mut Command) -> io::Result<Child> {
98    with_executable_busy_retry(|| command.spawn())
99}
100
101pub(crate) fn should_embed_candid_metadata(build_network: canic_core::ids::BuildNetwork) -> bool {
102    build_network == canic_core::ids::BuildNetwork::Local
103}
104
105#[cfg(test)]
106mod tests;