git_policy_cli/shadow/replay_shadow.rs
1//! What:
2//! Running real Git against the shadow repository for replay:
3//! the shadow selection, an optional private index, bytes on standard input,
4//! and the caller's kept global options when a signed rebuild needs them.
5//! Why:
6//! Every replay step runs in `git --git-dir=<shadow>` so its objects stay in the shadow store
7//! until the next migration;
8//! one runner keeps the selection in one place.
9//!
10//! In TS you'd write (pseudocode):
11//! ```ts
12//! runShadowGit({ gitPath, shadowPath, args, input, environment });
13//! ```
14
15/// Shadow selection and the transaction Git runner.
16use crate::shadow_git::shadow_request;
17use crate::transaction_git::{GitContext, GitFailure, GitOutput, GitRequest, run_git_checked};
18/// `OsString` names environment entries and arguments.
19use std::ffi::OsString;
20/// `Path`/`PathBuf` are borrowed/owned filesystem paths.
21use std::path::{Path, PathBuf};
22
23/// What:
24/// Runs one shadow Git command and requires success.
25/// Why:
26/// Replay cannot continue after a failed `merge-base`, `hash-object` or `read-tree`;
27/// the caller maps the failure to `transaction-failed`.
28///
29/// In TS you'd write (pseudocode):
30/// ```ts
31/// await runShadowGit({ gitPath, shadowPath, args, input, environment });
32/// ```
33pub fn run_shadow_checked(
34 context: &GitContext,
35 shadow: &Path,
36 cwd: &Path,
37 arguments: &[&str],
38 input: Option<&[u8]>,
39 index: Option<&Path>,
40 environment: &[(OsString, OsString)],
41) -> Result<GitOutput, GitFailure> {
42 let mut request: GitRequest = shadow_request(shadow, cwd, arguments);
43 request.input = input.map(|bytes| { return bytes.to_vec(); });
44 request.index = index.map(|path| { return path.to_path_buf(); });
45 request.environment = environment.to_vec();
46 return run_git_checked(context, &request);
47}
48
49/// What:
50/// The private index file a replay step edits, named by the replay number.
51/// Why:
52/// Each replay keeps its own index under the transaction directory, so a later replay never reads an earlier one.
53///
54/// In TS you'd write (pseudocode):
55/// ```ts
56/// join(directory, `replay-base-${replay}.index`)
57/// ```
58pub fn replay_base_index(directory: &Path, replay: u64) -> PathBuf {
59 return directory.join(format!("replay-base-{replay}.index"));
60}
61
62#[cfg(test)]
63#[path = "replay_shadow_tests.rs"]
64mod tests;