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 inputs;
64mod staging;
65mod transaction;
66mod transaction_batch;
67mod wasm;
68mod wasm_batch;
69mod wasm_cache;
70mod workspace;
71
72#[cfg(test)]
73pub(crate) mod test_support;
74
75#[cfg(all(test, unix))]
76mod host_tests;
77
78pub use cache_fs::{ArtifactCacheMaintenance, ArtifactCachePrunePolicy, ArtifactCachePruneReport};
79pub use digest::InputDigest;
80pub use inputs::{
81 InputEvidence, InputEvidenceError, InputEvidenceSpec, InputEvidenceValue,
82 discover_cargo_depfile_inputs, parse_cargo_depfile, read_cargo_depfile_inputs,
83};
84pub use staging::{ArtifactStagingDirectory, CapturedArtifact};
85pub use transaction::{
86 ArtifactBuildTransaction, ArtifactCacheArtifact, ArtifactCacheError, ArtifactCacheOutcome,
87 ArtifactCachePreparation, ArtifactCacheRecord, ArtifactCacheSpec, ArtifactCacheTimings,
88 ArtifactOutputValidation, prepare_artifact_cache, prune_artifact_cache,
89};
90pub use transaction_batch::{
91 ArtifactCacheBatchContractError, ArtifactCacheBatchEntry, ArtifactCacheBatchFailedEntry,
92 ArtifactCacheBatchFailure, ArtifactCacheBatchFailurePhase, ArtifactCacheBatchFailureTimings,
93 ArtifactCacheBatchMetrics, ArtifactCacheBatchOutcomeEntry, ArtifactCacheBatchReport,
94 LabeledArtifactCacheSpec, build_artifact_caches_batch,
95};
96pub use wasm::{wasm_artifacts_ready, wasm_path};
97pub use wasm_batch::{
98 LabeledWasmBuildSpec, WasmBuildBatchConfig, WasmBuildBatchContractError, WasmBuildBatchEntry,
99 WasmBuildBatchFailure, WasmBuildBatchMaintenanceEntry, WasmBuildBatchMetrics,
100 WasmBuildBatchOutcomeEntry, WasmBuildBatchProgressEvent, WasmBuildBatchReport,
101 WasmBuildInputSnapshot, WasmBuildInputSnapshotMetrics, WasmBuildSession,
102 WasmBuildSessionMetrics, build_wasm_canisters_cached_batch,
103 build_wasm_canisters_cached_batch_with_config,
104 build_wasm_canisters_cached_batch_with_config_and_progress,
105 build_wasm_canisters_cached_batch_with_progress,
106};
107pub use wasm_cache::{
108 CargoBuildInput, CargoInputProbePolicy, ResolvedCargoBuildInputs,
109 SharedIncrementalTargetInspection, SharedIncrementalTargetMaintenance,
110 SharedIncrementalTargetMaintenanceConfig, SharedIncrementalTargetMaintenanceFailureMode,
111 SharedIncrementalTargetMaintenanceOutcome, SharedIncrementalTargetPrunePolicy,
112 WasmBuildCacheMode, WasmBuildError, WasmBuildFailureDetails, WasmBuildFailurePhase,
113 WasmBuildFailureTimings, WasmBuildOutcome, WasmBuildOutputStream, WasmBuildPhase,
114 WasmBuildProgressConfig, WasmBuildProgressEvent, WasmBuildProgressOutcome,
115 WasmBuildProgressPhase, WasmBuildRecord, WasmBuildSpec, WasmBuildTimings,
116 WasmInputResolutionTimings, build_wasm_canisters_cached,
117 build_wasm_canisters_cached_with_progress, inspect_shared_incremental_target,
118 maintain_shared_incremental_target, maintain_shared_incremental_target_at_most_every,
119 prune_wasm_build_cache, resolve_cargo_build_inputs,
120 resolve_cargo_build_inputs_with_probe_policy,
121};
122pub use workspace::{test_target_dir, workspace_root_for};