ic_build/artifacts/mod.rs
1//! Host-side artifact discovery, freshness, and Wasm build helpers.
2//!
3//! These functions keep integration-test artifacts in caller-selected target
4//! directories and contain no application-specific package or profile policy.
5//! Independent Wasm batches remain sequential; [`WasmBuildSession`] adds
6//! explicit cross-call resolution reuse, while [`WasmBuildInputSnapshot`]
7//! prepares a fixed specification set for concurrent readers. Both require a
8//! caller-held source lease.
9//!
10//! Successful Wasm and generic artifact records retain their read-only exact
11//! paths against cache replacement and pruning. Retain the record (or a clone)
12//! through consumption; paths and artifact descriptors alone carry no ownership.
13//! Batch reports own their successful records even when later entries fail.
14//!
15//! ```no_run
16//! use ic_build::artifacts::{
17//! ArtifactCacheOutcome, ArtifactCachePreparation, ArtifactCacheSpec,
18//! WasmBuildSpec, build_wasm_canisters_cached, prepare_artifact_cache,
19//! resolve_cargo_build_inputs,
20//! };
21//! use ic_host_artifacts::artifact::hash_reader;
22//! use ic_host_process::tool::{AdmittedTool, ExecutionContext, OutputLimits};
23//! use std::path::Path;
24//!
25//! // The caller holds its source lease and configures the Cargo shim and actual
26//! // compiler identity on spec. The admitted optimizer accepts INPUT -o OUTPUT.
27//! fn build_deployable(
28//! spec: &WasmBuildSpec, post_cache: &Path, destination: &Path,
29//! optimizer: &AdmittedTool, context: &ExecutionContext<'_>, limits: OutputLimits,
30//! max_output_bytes: usize,
31//! ) -> Result<Vec<u8>, Box<dyn std::error::Error>>
32//! {
33//! let resolved = resolve_cargo_build_inputs(spec)?;
34//! let wasm = build_wasm_canisters_cached(spec)?;
35//! let input = &wasm.record().artifacts()[0];
36//! let post_spec = ArtifactCacheSpec::new(post_cache, "deploy", "optimizer/v1")
37//! .with_cargo_build_inputs("cargo", spec, &resolved)
38//! .with_input("wasm", input)
39//! .with_tool("optimizer", optimizer.path())
40//! .with_arguments(["<input>", "-o", "<output>"])
41//! .with_environment(context.environment.iter().cloned())
42//! .with_identity_bytes("optimizer-cwd", context.current_dir.as_os_str().as_encoded_bytes())
43//! .with_output("deploy", destination);
44//! let deploy = match prepare_artifact_cache(&post_spec)? {
45//! ArtifactCachePreparation::Reused(record) => ArtifactCacheOutcome::Reused(record),
46//! ArtifactCachePreparation::Build(transaction) => {
47//! let output = transaction.output_path("deploy")?;
48//! optimizer.run(&[input.into(), "-o".into(), output.clone().into()], context, limits)?.require_success()?;
49//! hash_reader(std::fs::File::open(&output)?, max_output_bytes as u64)?;
50//! transaction.commit()?
51//! }
52//! };
53//! drop(wasm); // The post-link transaction has finished consuming the input.
54//! let bytes = ic_host_fs::read::read_file(
55//! deploy.record().artifacts()[0].path(), max_output_bytes)?;
56//! drop(deploy); // Reading is complete; maintenance may now reclaim it.
57//! Ok(bytes)
58//! }
59//! ```
60
61mod cache_fs;
62mod digest;
63mod icp;
64mod inputs;
65mod staging;
66mod transaction;
67mod transaction_batch;
68mod wasm;
69mod wasm_batch;
70mod wasm_cache;
71mod workspace;
72
73#[cfg(test)]
74pub(crate) mod test_support;
75
76#[cfg(all(test, unix))]
77mod host_tests;
78
79pub use cache_fs::{ArtifactCacheMaintenance, ArtifactCachePrunePolicy, ArtifactCachePruneReport};
80pub use digest::InputDigest;
81pub use icp::{
82 WatchedInputSnapshot, icp_artifact_ready_for_build, icp_artifact_ready_with_snapshot,
83};
84pub use inputs::{
85 InputEvidence, InputEvidenceError, InputEvidenceSpec, InputEvidenceValue,
86 discover_cargo_depfile_inputs, parse_cargo_depfile,
87};
88pub use staging::{ArtifactStagingDirectory, CapturedArtifact};
89pub use transaction::{
90 ArtifactBuildTransaction, ArtifactCacheArtifact, ArtifactCacheError, ArtifactCacheOutcome,
91 ArtifactCachePreparation, ArtifactCacheRecord, ArtifactCacheSpec, ArtifactCacheTimings,
92 ArtifactOutputValidation, prepare_artifact_cache, prune_artifact_cache,
93};
94pub use transaction_batch::{
95 ArtifactCacheBatchContractError, ArtifactCacheBatchEntry, ArtifactCacheBatchFailedEntry,
96 ArtifactCacheBatchFailure, ArtifactCacheBatchFailurePhase, ArtifactCacheBatchFailureTimings,
97 ArtifactCacheBatchMetrics, ArtifactCacheBatchOutcomeEntry, ArtifactCacheBatchReport,
98 LabeledArtifactCacheSpec, build_artifact_caches_batch,
99};
100pub use wasm::{wasm_artifacts_ready, wasm_path};
101pub use wasm_batch::{
102 LabeledWasmBuildSpec, WasmBuildBatchConfig, WasmBuildBatchContractError, WasmBuildBatchEntry,
103 WasmBuildBatchFailure, WasmBuildBatchMaintenanceEntry, WasmBuildBatchMetrics,
104 WasmBuildBatchOutcomeEntry, WasmBuildBatchProgressEvent, WasmBuildBatchReport,
105 WasmBuildInputSnapshot, WasmBuildInputSnapshotMetrics, WasmBuildSession,
106 WasmBuildSessionMetrics, build_wasm_canisters_cached_batch,
107 build_wasm_canisters_cached_batch_with_config,
108 build_wasm_canisters_cached_batch_with_config_and_progress,
109 build_wasm_canisters_cached_batch_with_progress,
110};
111pub use wasm_cache::{
112 CargoBuildInput, ResolvedCargoBuildInputs, SharedIncrementalTargetInspection,
113 SharedIncrementalTargetMaintenance, SharedIncrementalTargetMaintenanceConfig,
114 SharedIncrementalTargetMaintenanceFailureMode, SharedIncrementalTargetMaintenanceOutcome,
115 SharedIncrementalTargetPrunePolicy, WasmBuildCacheMode, WasmBuildError,
116 WasmBuildFailureDetails, WasmBuildFailurePhase, WasmBuildFailureTimings, WasmBuildOutcome,
117 WasmBuildOutputStream, WasmBuildPhase, WasmBuildProgressConfig, WasmBuildProgressEvent,
118 WasmBuildProgressOutcome, WasmBuildProgressPhase, WasmBuildRecord, WasmBuildSpec,
119 WasmBuildTimings, WasmInputResolutionTimings, build_wasm_canisters_cached,
120 build_wasm_canisters_cached_with_progress, inspect_shared_incremental_target,
121 maintain_shared_incremental_target, maintain_shared_incremental_target_at_most_every,
122 prune_wasm_build_cache, resolve_cargo_build_inputs,
123};
124pub use workspace::{test_target_dir, workspace_root_for};