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
//! What:
//! Read the real Git that the wrapper's commit service was set up with,
//! from the unit file the wrapper wrote for it.
//! Why:
//! Nothing the wrapper installs records the real Git it shadows.
//! The one file that names a real Git is the unit of the
//! commit service (`service_provision.rs`):
//! its `ExecStart` line holds `--git <path>`,
//! the Git the wrapper resolved
//! when it last provisioned the service.
//! When no real Git follows the wrapper on `PATH`,
//! that path is the only
//! recorded one,
//! so the resolver (`real_git.rs`) falls back to it,
//! after the same checks a `PATH` candidate passes.
//! This is the coordinator's pick under the owner's delegation,
//! 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").
//! The file lives in the runtime directory,
//! so it is gone after the account's last logout,
//! and no record then
//! means no fallback.
//!
//! In TS you'd write (pseudocode):
//! ```ts
//! const unitText = readFileSync(join(runtimeDir, 'systemd/user/cli-git@.service'), 'utf8');
//! const recordedGit = unitText.match(/^ExecStart=.*\s--git\s+(\S+)/m)?.[1]; // undefined: no record
//! ```
/// What:
/// `use super::...` imports the names of the sibling modules that own the unit file's location and name,
/// and the bound on how much of a record is read.
/// Why:
/// The unit's directory and file name are decided once,
/// where the wrapper writes the unit;
/// this module only reads what that writer produced.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// import { runtimeUnitDir, SERVICE_UNIT_NAME } from './service-provision.ts';
/// ```
use crateMAX_SCRIPT_INSPECTION_BYTES;
use crate;
/// `Read` supplies `read_to_end` and `take`,
/// the bounded read below.
use Read;
/// `Path` is a borrowed filesystem path;
/// `PathBuf` is the owned sibling a function returns.
use ;
/// The option of the service program that names the Git it starts.
const GIT_OPTION: &str = "--git";
/// The key of the unit line that holds the service program and its options.
const EXEC_START_KEY: &str = "ExecStart=";
/// What:
/// The unit file of the commit service below a runtime directory.
/// `&Path` borrows a path (sibling:
/// `PathBuf` owns one),
/// and `PathBuf` is returned because the result is built here.
/// Why:
/// The wrapper writes the service unit there,
/// and nowhere else is searched:
/// a record found by looking through other places would be a guess.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// function serviceUnitFile(runtimeDir: string): string { return join(runtimeDir, 'systemd/user/cli-git@.service'); }
/// ```
/// What:
/// Whether one word of a line is the Git option.
/// `&&str` is a borrow of a borrowed word,
/// which is the shape `.position(...)` hands its predicate.
/// Why:
/// A named predicate keeps the search below a plain call.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// const isGitOption = (word: string) => word === '--git';
/// ```
/// What:
/// The absolute path after `--git` on the `ExecStart` line of a unit's text.
/// `Option<PathBuf>` is the path or nothing (`PathBuf | undefined`).
/// Why:
/// The wrapper writes the path unquoted,
/// so whitespace cuts the line into words and the word after `--git` is the path.
/// A relative path is no record,
/// because it would mean a different file for each directory the wrapper runs in.
/// A path with a space in it is cut short and then fails the checks of the resolver,
/// which is the safe outcome.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// function recordedGitPath(unitText: string): string | undefined;
/// ```
/// What:
/// The Git a unit file records,
/// read with the bound a launcher record is read with.
/// Why:
/// The unit is a few hundred bytes,
/// so a file past the bound is not the wrapper's unit and names nothing.
/// An unreadable or missing file names nothing either,
/// and the caller keeps its stop.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// function readRecordedGit(unitFile: string): string | undefined;
/// ```
/// Controls for the unit text,
/// the file read and the bounds.