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