Skip to main content

git_policy_cli/
action.rs

1//! What:
2//!  The decision one wrapper invocation ends in.
3//! Why:
4//!  Forwarding replaces the process and cannot run inside a unit test;
5//!  returning
6//!      the decision as data lets every path be checked directly.
7//!
8//! In TS you'd write (pseudocode):
9//! ```ts
10//! // type Action = { kind: 'forward'; ... } | { kind: 'exit'; code: number; stdout: string; stderr: string };
11//! ```
12
13/// What:
14///  `OsString` is owned operating-system text of raw OS bytes (sibling `String`
15///       must be UTF-8).
16/// Why:
17///   Environment additions are passed to Git without decoding.
18///
19/// In TS you'd write (pseudocode):
20/// ```ts
21/// // [string, string][] environment pairs, but byte-preserving.
22/// ```
23use std::ffi::OsString;
24/// `PathBuf` is an owned filesystem path of raw OS bytes.
25use super::index_writer_forward::CoordinatedForward;
26use super::worktree_copy_forward::CopyFacts;
27use std::path::PathBuf;
28
29/// What:
30///  Exit code for a usage,
31///  configuration or wrapper failure that kept Git from running.
32///       `i32` is a signed 32-bit integer,
33///  the type of process exit codes.
34/// Why:
35///   The wrapper's contract reserves 2 for these,
36///  distinct from 1 for policy findings.
37///
38/// In TS you'd write (pseudocode):
39/// ```ts
40/// const ENGINE_FAILURE_EXIT_CODE = 2;
41/// ```
42pub const ENGINE_FAILURE_EXIT_CODE: i32 = 2;
43
44/// What:
45///  What the executable must do for one invocation.
46///       `Vec<OsString>` is an owned argument list;
47///  `Vec<(OsString, OsString)>` is an
48///       owned list of name/value pairs;
49///  `String` is owned UTF-8 text.
50/// Why:
51///   The executable performs exactly one of these:
52///  become Git,
53///  or print and exit.
54///
55/// In TS you'd write (pseudocode):
56/// ```ts
57/// type Action = { kind: 'forward'; realGit: string; args: string[]; overlay: [string, string][]; stderr: string }
58///   | { kind: 'exit'; code: number; stdout: string; stderr: string };
59/// ```
60#[derive(Clone, Debug, Eq, PartialEq)]
61pub enum Action {
62    /// Become real Git.
63    Forward {
64        /// The selected real Git executable.
65        real_git: PathBuf,
66        /// The arguments Git receives:
67        ///  no wrapper control,
68        ///  fixed transforms applied.
69        arguments: Vec<OsString>,
70        /// Variables added to the inherited environment.
71        overlay: Vec<(OsString, OsString)>,
72        /// Complete warning event lines,
73        ///  written to standard error before Git starts.
74        stderr: String,
75    },
76    /// Forward an index writer under its landing lock:
77    ///  coordinate,
78    ///  run Git as a child,
79    ///  release.
80    ForwardCoordinated {
81        /// What the coordinated run needs.
82        forward: Box<CoordinatedForward>,
83        /// Warning events written to standard error before the coordination starts.
84        stderr: String,
85    },
86    /// Forward a command that the linked-worktree copy settles:
87    ///  run Git as a child that carries the settlement lease,
88    ///  recover an interrupted copy first,
89    ///  copy the ignored state into the worktrees the command created.
90    ForwardSettled {
91        /// The selected real Git executable.
92        real_git: PathBuf,
93        /// The arguments Git receives.
94        arguments: Vec<OsString>,
95        /// Variables added to the inherited environment.
96        overlay: Vec<(OsString, OsString)>,
97        /// What the copy needs to know about the invocation.
98        copy: Box<CopyFacts>,
99        /// Warning events written to standard error before Git starts.
100        stderr: String,
101    },
102    /// Stop without running the caller's command.
103    Exit {
104        /// Process exit code.
105        code: i32,
106        /// Complete text for standard output,
107        ///  already line-terminated.
108        stdout: String,
109        /// Complete text for standard error,
110        ///  already line-terminated.
111        stderr: String,
112    },
113}
114
115/// What:
116///  Build the stop action for a wrapper failure described in prose.
117///       `&str` borrows the message;
118///  the action owns its formatted copy.
119/// Why:
120///   These failures (no real Git,
121///  a forwarding loop,
122///  an unreadable repository)
123///       print one prefixed,
124///  line-terminated diagnostic on standard error and exit 2.
125///
126/// In TS you'd write (pseudocode):
127/// ```ts
128/// function failure(message: string): Action;
129/// ```
130pub fn failure(message: &str) -> Action {
131    return Action::Exit {
132        code: ENGINE_FAILURE_EXIT_CODE,
133        // `String::new()` is empty owned text: nothing goes to standard output.
134        stdout: String::new(),
135        // `format!` builds the owned, line-terminated text.
136        stderr: format!("cli-git: {message}\n"),
137    };
138}