pub fn capture_git(
git: &AdmittedTool,
context: &ExecutionContext<'_>,
options: StatusOptions,
limits: OutputLimits,
) -> Result<GitObservations, GitError>Expand description
Observe HEAD, its tree and status, with per-query bounds and no retries.
Commands disable optional locks and the filesystem monitor. The complete
environment and working directory remain explicit; Git environment/config
can redirect repository selection, and callers own that admission policy.
Status is opaque porcelain-v1 -z output, checked only for NUL termination.
These separate observations cannot prove an atomic or reproducible build.
§Errors
Returns typed tool failures, malformed object IDs or unterminated status. Retains earlier captures and the failed query’s available evidence.
Examples found in repository?
examples/inspect_git.rs (lines 73-81)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 use ic_host_process::provenance::{
6 IgnoreSubmodules, StatusOptions, UntrackedFiles, capture_git,
7 };
8 use ic_host_process::tool::{AdmittedTool, ExecutionContext, OutputLimits, ToolSpec};
9
10 use std::{ffi::OsString, io, path::PathBuf, time::Duration};
11
12 let invalid = |message| io::Error::new(io::ErrorKind::InvalidInput, message);
13 let mut args = std::env::args_os().skip(1);
14 let mut required = || {
15 args.next().ok_or_else(|| invalid(
16 "usage: inspect_git TOOL SHA256 VERSION WORKDIR MAX_TOOL_BYTES MAX_STDOUT_BYTES MAX_STDERR_BYTES TIMEOUT_MS UNTRACKED SUBMODULES",
17 ))
18 };
19 let executable = PathBuf::from(required()?);
20 let digest = required()?
21 .into_string()
22 .map_err(|_| invalid("digest must be UTF-8"))?
23 .parse()?;
24 let version = required()?
25 .into_string()
26 .map_err(|_| invalid("version must be UTF-8"))?;
27 let directory = PathBuf::from(required()?);
28 let mut number = || -> Result<u64, Box<dyn std::error::Error>> {
29 Ok(required()?
30 .to_str()
31 .ok_or_else(|| invalid("limits must be UTF-8"))?
32 .parse()?)
33 };
34 let executable_bytes = number()?;
35 let limits = OutputLimits {
36 stdout: ic_host_process::tool::OutputLimit::Terminate(usize::try_from(number()?)?),
37 stderr: ic_host_process::tool::OutputLimit::Terminate(usize::try_from(number()?)?),
38 timeout: Some(Duration::from_millis(number()?)),
39 };
40 let untracked = match required()?.to_str() {
41 Some("no") => UntrackedFiles::No,
42 Some("normal") => UntrackedFiles::Normal,
43 Some("all") => UntrackedFiles::All,
44 _ => return Err(invalid("untracked must be no, normal or all").into()),
45 };
46 let ignore_submodules = match required()?.to_str() {
47 Some("none") => IgnoreSubmodules::None,
48 Some("untracked") => IgnoreSubmodules::Untracked,
49 Some("dirty") => IgnoreSubmodules::Dirty,
50 Some("all") => IgnoreSubmodules::All,
51 _ => return Err(invalid("submodules must be none, untracked, dirty or all").into()),
52 };
53 if args.next().is_some() {
54 return Err(invalid("unexpected argument").into());
55 }
56 // The example explicitly selects an empty environment; the library never
57 // chooses environment exclusions or tool/version pins for a consumer.
58 let context = ExecutionContext {
59 current_dir: &directory,
60 environment: &[],
61 };
62 let git = AdmittedTool::admit(
63 &ToolSpec {
64 executable: &executable,
65 sha256: digest,
66 executable_bytes,
67 version_arguments: &[OsString::from("--version")],
68 version_identity: &version,
69 },
70 &context,
71 limits,
72 )?;
73 let observed = capture_git(
74 &git,
75 &context,
76 StatusOptions {
77 untracked,
78 ignore_submodules,
79 },
80 limits,
81 )?;
82 println!("revision={}", observed.revision);
83 println!("tree={}", observed.tree);
84 println!("dirty={}", observed.is_dirty());
85 println!("status_bytes={}", observed.status_identity.bytes);
86 println!("status_sha256={}", observed.status_identity.sha256);
87 Ok(())
88}