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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
//! What:
//! The one resolution of the real Git that every start uses:
//! the first real Git on `PATH`,
//! otherwise the Git the commit service's unit records,
//! with a notice.
//! Why:
//! The coordinator picked,
//! under the owner's delegation and open to the owner's veto
//! (`doc/planning/cli-git-no-self-invocation.md`,
//! section "Falling back to the Git the commit service was set up
//! with"),
//! that a wrapper which is found but has no real Git after it on `PATH` uses the Git it was set up with instead
//! of stopping.
//! The search of `PATH` stays in `real_git.rs`;
//! this module adds the fallback after it and the types that
//! carry its result,
//! so no caller can take the path and drop the notice.
//!
//! In TS you'd write (pseudocode):
//! ```ts
//! const { path, notice } = resolveRealGit(inputs); // throws RealGitNotFound
//! ```
/// What:
/// `use super::...` imports the search,
/// the inputs and the failure from the module that owns them,
/// the candidate verdicts,
/// and the reader of the record.
/// Why:
/// The fallback is judged by the same `classify_candidate` that judges a `PATH` candidate.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// import { searchPathForRealGit, type RealGitNotFound } from './real-git.ts';
/// ```
use crate;
use crate;
use crateread_recorded_git;
/// `OsStr` is borrowed operating-system text (siblings:
/// `OsString` owned,
/// `&str` UTF-8 only).
use OsStr;
/// `Path` is a borrowed filesystem path;
/// `PathBuf` is the owned sibling.
use ;
/// What:
/// The real Git a unit file records,
/// with the verdict the `PATH` candidate checks gave it.
/// Why:
/// When the fallback is refused,
/// the failure names the unit and the recorded file,
/// so the person sees that the record was read and why it was not used.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// type RecordedGit = { unitFile: string; candidate: SearchedCandidate };
/// ```
/// What:
/// The real Git a resolution selected,
/// and the notice owed to the person when it was not found on `PATH`.
/// Why:
/// A caller that starts Git must also print the notice,
/// so the two travel together and a caller cannot take the path alone by accident.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// type ResolvedGit = { path: string; notice: string | undefined };
/// ```
/// What:
/// The one line a person reads when the recorded Git was used because `PATH` offered none.
/// `&OsStr` and `&Path` borrow operating-system text and a path (siblings:
/// `OsString` and `PathBuf` own them).
/// `String` is owned UTF-8 text (sibling:
/// `&str`,
/// a borrowed view).
/// Why:
/// It says what happened (no real Git after the wrapper on `PATH`,
/// and which `PATH`),
/// what was done (which file,
/// read from which unit),
/// and the one way to make it stop (put the file's directory on the `PATH` of the program that ran the command).
/// An empty `PATH` is said in words,
/// as the failure does.
/// `String` and not `&str` because the line is built here and handed on.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// function fallbackNotice(path: string, git: string, unit: string): string;
/// ```
/// What:
/// Select the real Git for every start:
/// the first `PATH` candidate that is real Git,
/// otherwise the Git the commit service's unit records when that file passes the same checks.
/// `Result<ResolvedGit, RealGitNotFound>` is the selection with its notice,
/// or the typed failure.
/// Why:
/// The coordinator picked,
/// under the owner's delegation and open to the owner's veto,
/// that a wrapper which is found but has no real Git after it on `PATH` uses the Git it was set up with,
/// instead of stopping.
/// The recorded file is judged by `classify_candidate` as a `PATH` candidate is:
/// never this executable,
/// a link or copy of it,
/// a launcher of it,
/// or a script that starts it,
/// and it must be an executable file that exists.
/// A refusal keeps the stop and adds the record to the failure.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// function resolveRealGit(inputs: ResolutionInputs): { path: string; notice?: string }; // throws RealGitNotFound
/// ```