@procedures/git 0.8.1 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +13 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +40 -10
- package/dist/module.js.map +1 -1
- package/dist/procedures/git/clone.d.ts.map +1 -1
- package/dist/procedures/git/clone.js +4 -0
- package/dist/procedures/git/clone.js.map +1 -1
- package/dist/procedures/git/remote.d.ts.map +1 -1
- package/dist/procedures/git/remote.js +3 -0
- package/dist/procedures/git/remote.js.map +1 -1
- package/dist/procedures/git/root.d.ts +116 -0
- package/dist/procedures/git/root.d.ts.map +1 -0
- package/dist/procedures/git/root.js +443 -0
- package/dist/procedures/git/root.js.map +1 -0
- package/dist/procedures/git/run.d.ts +2 -1
- package/dist/procedures/git/run.d.ts.map +1 -1
- package/dist/procedures/git/run.js +8 -4
- package/dist/procedures/git/run.js.map +1 -1
- package/package.json +4 -4
- package/src/module.ts +43 -11
- package/src/procedures/git/clone.ts +4 -0
- package/src/procedures/git/remote.ts +3 -0
- package/src/procedures/git/root.ts +488 -0
- package/src/procedures/git/run.ts +8 -4
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git under the root of the files of a host (roadmap R33, tracker item O35).
|
|
3
|
+
*
|
|
4
|
+
* A host with a root (`confineToRoot()` of `@procedures/fs`) examines the path inputs of each
|
|
5
|
+
* `git.*` procedure, and it gives the handler the root in `ctx.fsRoot`. The handler then runs in
|
|
6
|
+
* `underGitRoot()`, and each `git()` call of the handler gets these changes:
|
|
7
|
+
*
|
|
8
|
+
* - The working folder must be in the root. `GIT_CEILING_DIRECTORIES` is the parent of the root, so
|
|
9
|
+
* git does not look for a repository above the root.
|
|
10
|
+
* - The configuration of the system does not apply (`GIT_CONFIG_NOSYSTEM`). The global
|
|
11
|
+
* configuration is a file of this process with only the identity of the user of the host
|
|
12
|
+
* (`GIT_CONFIG_GLOBAL`). The variables that move the repository (`GIT_DIR`, `GIT_WORK_TREE` and
|
|
13
|
+
* the others) do not apply.
|
|
14
|
+
* - The options of `SAFE_CONFIG` turn off the hooks, `core.fsmonitor`, the transports `file` and
|
|
15
|
+
* `ext` (and each transport other than https, http, ssh and git), and the recursion into
|
|
16
|
+
* submodules.
|
|
17
|
+
* - Before the first git command in a folder, `examineRepository()` examines the repository: its
|
|
18
|
+
* folders must be in the root, and its configuration must not start a program
|
|
19
|
+
* (`refusedConfigKeys()`). A repository with submodules is refused.
|
|
20
|
+
*
|
|
21
|
+
* A refusal is `FORBIDDEN` with the reason `outside-root`. Without a root, nothing changes.
|
|
22
|
+
*/
|
|
23
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
24
|
+
import { rmSync } from "node:fs";
|
|
25
|
+
import { access, mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
|
|
26
|
+
import { tmpdir } from "node:os";
|
|
27
|
+
import { delimiter, dirname, join, resolve } from "node:path";
|
|
28
|
+
import { inRoot, isInside, outsideRoot, realPathOf, resolveRoot } from "@procedures/fs/root";
|
|
29
|
+
import { runCommand } from "@procedures/shell/command";
|
|
30
|
+
const roots = new AsyncLocalStorage();
|
|
31
|
+
/**
|
|
32
|
+
* This function runs the handler of a git procedure. With a root, each `git()` call of the handler
|
|
33
|
+
* stays in the root. Without a root, it only runs the handler.
|
|
34
|
+
*/
|
|
35
|
+
export async function underGitRoot(folder, procedure, handler) {
|
|
36
|
+
if (folder === undefined)
|
|
37
|
+
return handler();
|
|
38
|
+
const root = await resolveRoot(folder, "the git procedures");
|
|
39
|
+
return roots.run({ root, procedure, examined: new Map() }, handler);
|
|
40
|
+
}
|
|
41
|
+
/** This function gives the root of the current call, or undefined without a root. */
|
|
42
|
+
export function currentGitRoot() {
|
|
43
|
+
return roots.getStore();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* This function gives the absolute path of a path that a git procedure makes from its input, for
|
|
47
|
+
* example the folder of a clone. Under a root, a path outside the root is refused.
|
|
48
|
+
*/
|
|
49
|
+
export async function pathInGitRoot(path) {
|
|
50
|
+
const current = currentGitRoot();
|
|
51
|
+
if (current === undefined)
|
|
52
|
+
return resolve(path);
|
|
53
|
+
return inRoot(current.root, path, current.procedure);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* This function refuses, under a root, the URL of a remote that starts a program: the form
|
|
57
|
+
* `<transport>::<address>` starts the remote helper `git-remote-<transport>`, and `ext::` starts
|
|
58
|
+
* a command.
|
|
59
|
+
*/
|
|
60
|
+
export function remoteUrlInGitRoot(url) {
|
|
61
|
+
const current = currentGitRoot();
|
|
62
|
+
if (current !== undefined && url.includes("::")) {
|
|
63
|
+
throw outsideRoot(current.procedure, `under the root ${current.root.folder}, a remote URL with "::" is refused, because it starts a program: ${url}`);
|
|
64
|
+
}
|
|
65
|
+
return url;
|
|
66
|
+
}
|
|
67
|
+
// =============================================================================
|
|
68
|
+
// The command line and the environment of git under a root
|
|
69
|
+
// =============================================================================
|
|
70
|
+
/**
|
|
71
|
+
* The configuration of each git command under a root, as `-c` options. A `-c` option overrides each
|
|
72
|
+
* configuration file. Git gives these options to the git commands that it starts.
|
|
73
|
+
*/
|
|
74
|
+
export function safeConfig(hooks) {
|
|
75
|
+
return [
|
|
76
|
+
// No hook runs: the folder is empty
|
|
77
|
+
`core.hooksPath=${hooks}`,
|
|
78
|
+
"core.fsmonitor=false",
|
|
79
|
+
// Only the network transports: no local path, no file://, no ext:: and no remote helper. The
|
|
80
|
+
// rule of a transport overrides protocol.allow, so file and ext get their own rule.
|
|
81
|
+
"protocol.allow=never",
|
|
82
|
+
"protocol.file.allow=never",
|
|
83
|
+
"protocol.ext.allow=never",
|
|
84
|
+
"protocol.https.allow=always",
|
|
85
|
+
"protocol.http.allow=always",
|
|
86
|
+
"protocol.ssh.allow=always",
|
|
87
|
+
"protocol.git.allow=always",
|
|
88
|
+
// Git does not start git in a submodule
|
|
89
|
+
"diff.ignoreSubmodules=all",
|
|
90
|
+
"submodule.recurse=false",
|
|
91
|
+
"fetch.recurseSubmodules=false",
|
|
92
|
+
"push.recurseSubmodules=no",
|
|
93
|
+
"status.submoduleSummary=false",
|
|
94
|
+
].flatMap((option) => ["-c", option]);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The variables of the environment that move the repository, add configuration or allow a
|
|
98
|
+
* transport. Under a root, git does not get them.
|
|
99
|
+
*/
|
|
100
|
+
const REMOVED_VARIABLES = [
|
|
101
|
+
"GIT_DIR",
|
|
102
|
+
"GIT_WORK_TREE",
|
|
103
|
+
"GIT_COMMON_DIR",
|
|
104
|
+
"GIT_INDEX_FILE",
|
|
105
|
+
"GIT_OBJECT_DIRECTORY",
|
|
106
|
+
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
107
|
+
"GIT_NAMESPACE",
|
|
108
|
+
"GIT_IMPLICIT_WORK_TREE",
|
|
109
|
+
"GIT_PREFIX",
|
|
110
|
+
"GIT_GRAFT_FILE",
|
|
111
|
+
"GIT_SHALLOW_FILE",
|
|
112
|
+
"GIT_CONFIG",
|
|
113
|
+
"GIT_CONFIG_SYSTEM",
|
|
114
|
+
"GIT_CONFIG_PARAMETERS",
|
|
115
|
+
"GIT_CONFIG_COUNT",
|
|
116
|
+
"GIT_EXTERNAL_DIFF",
|
|
117
|
+
"GIT_TEMPLATE_DIR",
|
|
118
|
+
"GIT_ATTR_SOURCE",
|
|
119
|
+
"GIT_ALLOW_PROTOCOL",
|
|
120
|
+
];
|
|
121
|
+
/** The folders of `GIT_CEILING_DIRECTORIES` for a root: the parent of the root, as given and as its real path. */
|
|
122
|
+
export function ceilingOf(root) {
|
|
123
|
+
const parents = new Set();
|
|
124
|
+
for (const folder of [root.folder, root.real]) {
|
|
125
|
+
const parent = dirname(folder);
|
|
126
|
+
// A root at the top of a drive has no parent
|
|
127
|
+
if (parent !== folder)
|
|
128
|
+
parents.add(parent);
|
|
129
|
+
}
|
|
130
|
+
return [...parents].join(delimiter);
|
|
131
|
+
}
|
|
132
|
+
/** This function gives the environment of git under a root. */
|
|
133
|
+
export function rootEnvironment(root, setup) {
|
|
134
|
+
const env = {};
|
|
135
|
+
for (const name of REMOVED_VARIABLES)
|
|
136
|
+
env[name] = undefined;
|
|
137
|
+
env["GIT_CEILING_DIRECTORIES"] = ceilingOf(root);
|
|
138
|
+
env["GIT_CONFIG_NOSYSTEM"] = "1";
|
|
139
|
+
env["GIT_CONFIG_GLOBAL"] = setup.globalConfig;
|
|
140
|
+
// No prompt for a password: the call has no terminal
|
|
141
|
+
env["GIT_TERMINAL_PROMPT"] = "0";
|
|
142
|
+
return env;
|
|
143
|
+
}
|
|
144
|
+
/** The keys of the global configuration that git under a root keeps. They start no program. */
|
|
145
|
+
const KEPT_GLOBAL_KEYS = ["user.name", "user.email", "init.defaultBranch"];
|
|
146
|
+
let setup;
|
|
147
|
+
/** The folder of the files of git under a root, when they exist. */
|
|
148
|
+
let setupFolder;
|
|
149
|
+
/**
|
|
150
|
+
* This function makes the files of git under a root one time for each process: a new folder in
|
|
151
|
+
* the temporary folder, with an empty hooks folder and a global configuration. The configuration
|
|
152
|
+
* has only the identity of the user from the global configuration of the host, so a commit works.
|
|
153
|
+
* The process deletes the folder at its end (`removeGitRootSetup()`).
|
|
154
|
+
*/
|
|
155
|
+
export function gitRootSetup() {
|
|
156
|
+
setup ??= makeSetup();
|
|
157
|
+
return setup;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* This function deletes the files of git under a root. The process starts it at its end. The next
|
|
161
|
+
* git command under a root makes the files again.
|
|
162
|
+
*/
|
|
163
|
+
export function removeGitRootSetup() {
|
|
164
|
+
if (setupFolder !== undefined)
|
|
165
|
+
rmSync(setupFolder, { recursive: true, force: true });
|
|
166
|
+
setupFolder = undefined;
|
|
167
|
+
setup = undefined;
|
|
168
|
+
}
|
|
169
|
+
async function makeSetup() {
|
|
170
|
+
try {
|
|
171
|
+
const folder = await mkdtemp(join(tmpdir(), "procedures-git-root-"));
|
|
172
|
+
setupFolder = folder;
|
|
173
|
+
process.once("exit", removeGitRootSetup);
|
|
174
|
+
const hooks = join(folder, "hooks");
|
|
175
|
+
await mkdir(hooks);
|
|
176
|
+
const globalConfig = join(folder, "global.gitconfig");
|
|
177
|
+
await writeFile(globalConfig, "");
|
|
178
|
+
for (const key of KEPT_GLOBAL_KEYS) {
|
|
179
|
+
const value = await runCommand("git", { args: ["config", "--global", "--get", key], cwd: folder });
|
|
180
|
+
if (!value.success)
|
|
181
|
+
continue;
|
|
182
|
+
// Git writes the value, so a special character of the value stays correct
|
|
183
|
+
await runCommand("git", { args: ["config", "--file", globalConfig, key, value.stdout.replace(/\r?\n$/, "")], cwd: folder });
|
|
184
|
+
}
|
|
185
|
+
return { hooks, globalConfig };
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
// The next call tries again
|
|
189
|
+
setup = undefined;
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// =============================================================================
|
|
194
|
+
// The configuration of a repository
|
|
195
|
+
// =============================================================================
|
|
196
|
+
/** The keys (section.name, or section.subsection.name as section.*.name) that start a program or name a file outside the repository. */
|
|
197
|
+
const REFUSED_KEYS = new Set([
|
|
198
|
+
// Programs
|
|
199
|
+
"core.sshcommand",
|
|
200
|
+
"core.gitproxy",
|
|
201
|
+
"core.askpass",
|
|
202
|
+
"core.editor",
|
|
203
|
+
"core.pager",
|
|
204
|
+
"core.alternaterefscommand",
|
|
205
|
+
"sequence.editor",
|
|
206
|
+
"diff.external",
|
|
207
|
+
"diff.tool",
|
|
208
|
+
"diff.guitool",
|
|
209
|
+
"merge.tool",
|
|
210
|
+
"merge.guitool",
|
|
211
|
+
"credential.helper",
|
|
212
|
+
"credential.*.helper",
|
|
213
|
+
"gpg.program",
|
|
214
|
+
"gpg.*.program",
|
|
215
|
+
"gpg.ssh.defaultkeycommand",
|
|
216
|
+
"filter.*.clean",
|
|
217
|
+
"filter.*.smudge",
|
|
218
|
+
"filter.*.process",
|
|
219
|
+
"diff.*.command",
|
|
220
|
+
"diff.*.textconv",
|
|
221
|
+
"merge.*.driver",
|
|
222
|
+
"difftool.*.cmd",
|
|
223
|
+
"difftool.*.path",
|
|
224
|
+
"mergetool.*.cmd",
|
|
225
|
+
"mergetool.*.path",
|
|
226
|
+
"remote.*.uploadpack",
|
|
227
|
+
"remote.*.receivepack",
|
|
228
|
+
"remote.*.vcs",
|
|
229
|
+
"uploadpack.packobjectshook",
|
|
230
|
+
"trailer.*.command",
|
|
231
|
+
"trailer.*.cmd",
|
|
232
|
+
// Files outside the repository
|
|
233
|
+
"core.worktree",
|
|
234
|
+
"core.excludesfile",
|
|
235
|
+
"core.attributesfile",
|
|
236
|
+
"commit.template",
|
|
237
|
+
"include.path",
|
|
238
|
+
"includeif.*.path",
|
|
239
|
+
"init.templatedir",
|
|
240
|
+
"mailmap.file",
|
|
241
|
+
"blame.ignorerevsfile",
|
|
242
|
+
"diff.orderfile",
|
|
243
|
+
"gpg.ssh.allowedsignersfile",
|
|
244
|
+
// A bundle URI can be a local file
|
|
245
|
+
"fetch.bundleuri",
|
|
246
|
+
"transfer.bundleuri",
|
|
247
|
+
...["sslcert", "sslkey", "sslcainfo", "sslcapath", "cookiefile", "proxysslcert", "proxysslkey", "proxysslcainfo"].flatMap((name) => [
|
|
248
|
+
`http.${name}`,
|
|
249
|
+
`http.*.${name}`,
|
|
250
|
+
]),
|
|
251
|
+
]);
|
|
252
|
+
/**
|
|
253
|
+
* The sections that a root refuses as a whole: `pager.<command>` and the hooks of the
|
|
254
|
+
* configuration start a program, `protocol.*` allows a transport again, and a bundle URI can be
|
|
255
|
+
* a local file.
|
|
256
|
+
*/
|
|
257
|
+
const REFUSED_SECTIONS = new Set(["pager", "hook", "protocol", "bundle"]);
|
|
258
|
+
/** The keys that start the signing program when they are not false. */
|
|
259
|
+
const SIGNING_KEYS = new Set(["commit.gpgsign", "tag.gpgsign", "tag.forcesignannotated", "push.gpgsign"]);
|
|
260
|
+
/** The values that turn off a boolean key. */
|
|
261
|
+
const FALSE_VALUES = new Set(["false", "no", "off", "0"]);
|
|
262
|
+
/** The parts of a configuration key: the section and the name in lower case, and the subsection. */
|
|
263
|
+
function partsOf(key) {
|
|
264
|
+
const first = key.indexOf(".");
|
|
265
|
+
const last = key.lastIndexOf(".");
|
|
266
|
+
if (first === -1)
|
|
267
|
+
return { section: key.toLowerCase(), subsection: undefined, name: "" };
|
|
268
|
+
return {
|
|
269
|
+
section: key.slice(0, first).toLowerCase(),
|
|
270
|
+
subsection: first === last ? undefined : key.slice(first + 1, last),
|
|
271
|
+
name: key.slice(last + 1).toLowerCase(),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/** True when a key of the configuration of a repository starts a program or names a file outside it. */
|
|
275
|
+
export function isRefusedConfigKey(key, value) {
|
|
276
|
+
const { section, subsection, name } = partsOf(key);
|
|
277
|
+
if (REFUSED_SECTIONS.has(section))
|
|
278
|
+
return true;
|
|
279
|
+
const pattern = subsection === undefined ? `${section}.${name}` : `${section}.*.${name}`;
|
|
280
|
+
if (REFUSED_KEYS.has(pattern))
|
|
281
|
+
return true;
|
|
282
|
+
// gpg.ssh.defaultKeyCommand and gpg.ssh.allowedSignersFile have a fixed subsection
|
|
283
|
+
if (subsection !== undefined && REFUSED_KEYS.has(`${section}.${subsection.toLowerCase()}.${name}`))
|
|
284
|
+
return true;
|
|
285
|
+
if (SIGNING_KEYS.has(pattern))
|
|
286
|
+
return !FALSE_VALUES.has((value ?? "true").trim().toLowerCase());
|
|
287
|
+
// A remote helper: `<transport>::<address>`, also as the base of url.<base>.insteadOf
|
|
288
|
+
if (section === "remote" && (name === "url" || name === "pushurl"))
|
|
289
|
+
return (value ?? "").includes("::");
|
|
290
|
+
if (section === "url" && (subsection ?? "").includes("::"))
|
|
291
|
+
return true;
|
|
292
|
+
// `!command` as the update of a submodule
|
|
293
|
+
if (section === "submodule" && name === "update")
|
|
294
|
+
return (value ?? "").trim().startsWith("!");
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
/** This function reads the output of `git config --list --show-scope -z`: the scope, then the key and the value. */
|
|
298
|
+
export function parseConfigList(output) {
|
|
299
|
+
const fields = output.split("\0");
|
|
300
|
+
const entries = [];
|
|
301
|
+
for (let i = 0; i + 1 < fields.length; i += 2) {
|
|
302
|
+
const scope = fields[i];
|
|
303
|
+
const entry = fields[i + 1];
|
|
304
|
+
const newline = entry.indexOf("\n");
|
|
305
|
+
entries.push(newline === -1 ? { scope, key: entry, value: undefined } : { scope, key: entry.slice(0, newline), value: entry.slice(newline + 1) });
|
|
306
|
+
}
|
|
307
|
+
return entries;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* This function gives the keys of the configuration of a repository that a root refuses. It
|
|
311
|
+
* examines the files of the repository (the scopes `local` and `worktree`), not the global
|
|
312
|
+
* configuration of this process and not the `-c` options.
|
|
313
|
+
*/
|
|
314
|
+
export function refusedConfigKeys(entries) {
|
|
315
|
+
const refused = new Set();
|
|
316
|
+
for (const entry of entries) {
|
|
317
|
+
if (entry.scope === "global" || entry.scope === "command")
|
|
318
|
+
continue;
|
|
319
|
+
if (isRefusedConfigKey(entry.key, entry.value))
|
|
320
|
+
refused.add(entry.key);
|
|
321
|
+
}
|
|
322
|
+
return [...refused];
|
|
323
|
+
}
|
|
324
|
+
// =============================================================================
|
|
325
|
+
// The examination of a repository
|
|
326
|
+
// =============================================================================
|
|
327
|
+
/** This function runs git for an examination, with the environment of the root. */
|
|
328
|
+
async function examine(args, cwd, env, hooks, input) {
|
|
329
|
+
return runCommand("git", { args: [...safeConfig(hooks), ...args], cwd, env, input });
|
|
330
|
+
}
|
|
331
|
+
/** True when the real path of a path is in the root. */
|
|
332
|
+
async function isInRoot(root, path) {
|
|
333
|
+
return isInside(root.real, await realPathOf(path));
|
|
334
|
+
}
|
|
335
|
+
/** True when a file or a folder exists. */
|
|
336
|
+
async function exists(path) {
|
|
337
|
+
return access(path).then(() => true, () => false);
|
|
338
|
+
}
|
|
339
|
+
/** True when a folder has the files of a git folder: `HEAD`, `objects` and `refs`, as a bare repository has. */
|
|
340
|
+
async function isGitFolder(folder) {
|
|
341
|
+
for (const name of ["HEAD", "objects", "refs"])
|
|
342
|
+
if (!(await exists(join(folder, name))))
|
|
343
|
+
return false;
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* True when a folder from the working folder up to the root has `.git`, or is a git folder. Git
|
|
348
|
+
* then found a repository that it could not examine.
|
|
349
|
+
*/
|
|
350
|
+
async function looksLikeRepository(cwd, root) {
|
|
351
|
+
let folder = cwd;
|
|
352
|
+
for (;;) {
|
|
353
|
+
if ((await exists(join(folder, ".git"))) || (await isGitFolder(folder)))
|
|
354
|
+
return true;
|
|
355
|
+
const parent = dirname(folder);
|
|
356
|
+
if (!isInside(root, parent) || parent === folder)
|
|
357
|
+
return false;
|
|
358
|
+
folder = parent;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* This function examines the repository of a working folder under a root. It refuses:
|
|
363
|
+
* - a repository whose folders are outside the root (a `.git` file can name another folder);
|
|
364
|
+
* - an alternate object folder outside the root;
|
|
365
|
+
* - a configuration with a key that starts a program or names a file outside the repository;
|
|
366
|
+
* - a repository with submodules: git starts git in each submodule, with its configuration.
|
|
367
|
+
*
|
|
368
|
+
* A folder that is not in a repository passes: the command makes one (`git init`, `git clone`),
|
|
369
|
+
* or it fails.
|
|
370
|
+
*/
|
|
371
|
+
export async function examineRepository(current, cwd, env, hooks) {
|
|
372
|
+
const { root, procedure } = current;
|
|
373
|
+
const refuse = (message) => outsideRoot(procedure, `under the root ${root.folder}, ${message}`);
|
|
374
|
+
const located = await examine(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir", "--is-bare-repository"], cwd, env, hooks);
|
|
375
|
+
const [gitDir, commonDir, bare] = located.success ? located.stdout.split(/\r?\n/) : [];
|
|
376
|
+
if (!gitDir || !commonDir) {
|
|
377
|
+
// The text of the error of git depends on the language, so the folders decide
|
|
378
|
+
if (await looksLikeRepository(cwd, root.folder)) {
|
|
379
|
+
throw refuse(`git cannot examine the repository of ${cwd}: ${located.stderr.trim()}`);
|
|
380
|
+
}
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
for (const path of [gitDir, commonDir, join(commonDir, "objects"), join(commonDir, "refs"), join(commonDir, "config"), join(gitDir, "index")]) {
|
|
384
|
+
if (!(await isInRoot(root, path)))
|
|
385
|
+
throw refuse(`the repository of ${cwd} is outside the root: ${path}`);
|
|
386
|
+
}
|
|
387
|
+
const alternates = await readFile(join(commonDir, "objects", "info", "alternates"), "utf8").catch(() => "");
|
|
388
|
+
for (const line of alternates.split(/\r?\n/)) {
|
|
389
|
+
const entry = line.trim();
|
|
390
|
+
if (entry === "" || entry.startsWith("#"))
|
|
391
|
+
continue;
|
|
392
|
+
if (!(await isInRoot(root, resolve(commonDir, "objects", entry))))
|
|
393
|
+
throw refuse(`the repository ${gitDir} reads objects outside the root: ${entry}`);
|
|
394
|
+
}
|
|
395
|
+
const config = await examine(["config", "--list", "--no-includes", "--show-scope", "-z"], cwd, env, hooks);
|
|
396
|
+
if (!config.success)
|
|
397
|
+
throw refuse(`git cannot read the configuration of the repository ${gitDir}: ${config.stderr.trim()}`);
|
|
398
|
+
const keys = refusedConfigKeys(parseConfigList(config.stdout));
|
|
399
|
+
if (keys.length > 0) {
|
|
400
|
+
throw refuse(`the configuration of the repository ${gitDir} can start a program or read a file outside the root: ${keys.join(", ")}`);
|
|
401
|
+
}
|
|
402
|
+
// A submodule: .gitmodules in the working tree, in the index or at HEAD
|
|
403
|
+
let modules = false;
|
|
404
|
+
if (bare !== "true") {
|
|
405
|
+
const top = await examine(["rev-parse", "--show-toplevel"], cwd, env, hooks);
|
|
406
|
+
if (top.success && (await exists(join(top.stdout.trim(), ".gitmodules"))))
|
|
407
|
+
modules = true;
|
|
408
|
+
}
|
|
409
|
+
if (!modules) {
|
|
410
|
+
const objects = await examine(["cat-file", "--batch-check"], cwd, env, hooks, ":.gitmodules\nHEAD:.gitmodules\n");
|
|
411
|
+
if (!objects.success)
|
|
412
|
+
throw refuse(`git cannot examine the repository ${gitDir}: ${objects.stderr.trim()}`);
|
|
413
|
+
modules = objects.stdout.split(/\r?\n/).some((line) => line !== "" && !line.endsWith(" missing"));
|
|
414
|
+
}
|
|
415
|
+
if (modules) {
|
|
416
|
+
throw refuse(`the repository ${gitDir} has submodules (.gitmodules), and git starts git in each submodule with the configuration of the submodule`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/** The subcommands that recurse into submodules without `--no-recurse-submodules`. */
|
|
420
|
+
const RECURSING = new Set(["fetch", "pull"]);
|
|
421
|
+
/**
|
|
422
|
+
* This function gives the arguments, the working folder and the environment of one git command
|
|
423
|
+
* under a root. It examines the repository of the working folder before the first command there.
|
|
424
|
+
*/
|
|
425
|
+
export async function confinedGitCommand(current, args, cwd, env) {
|
|
426
|
+
const folder = await inRoot(current.root, cwd ?? current.root.folder, current.procedure);
|
|
427
|
+
const files = await gitRootSetup();
|
|
428
|
+
const rootEnv = rootEnvironment(current.root, files);
|
|
429
|
+
let examined = current.examined.get(folder);
|
|
430
|
+
if (examined === undefined) {
|
|
431
|
+
examined = examineRepository(current, folder, rootEnv, files.hooks);
|
|
432
|
+
current.examined.set(folder, examined);
|
|
433
|
+
}
|
|
434
|
+
await examined;
|
|
435
|
+
const command = [...args];
|
|
436
|
+
// The checkout shows the changes of the working tree, also of a submodule that it brings: quiet, it does not
|
|
437
|
+
if (command[0] === "checkout")
|
|
438
|
+
command.splice(1, 0, "--quiet");
|
|
439
|
+
if (RECURSING.has(command[0] ?? ""))
|
|
440
|
+
command.splice(1, 0, "--no-recurse-submodules");
|
|
441
|
+
return { args: [...safeConfig(files.hooks), ...command], cwd: folder, env: { ...rootEnv, ...env } };
|
|
442
|
+
}
|
|
443
|
+
//# sourceMappingURL=root.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root.js","sourceRoot":"","sources":["../../../src/procedures/git/root.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE9D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAqB,MAAM,qBAAqB,CAAC;AAChH,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAYvD,MAAM,KAAK,GAAG,IAAI,iBAAiB,EAAW,CAAC;AAE/C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAI,MAA0B,EAAE,SAAwB,EAAE,OAAyB;IACnH,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,OAAO,EAAE,CAAC;IAC3C,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAC7D,OAAO,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;AACtE,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,cAAc;IAC5B,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY;IAC9C,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IACjC,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IACjC,IAAI,OAAO,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,MAAM,WAAW,CAAC,OAAO,CAAC,SAAS,EAAE,kBAAkB,OAAO,CAAC,IAAI,CAAC,MAAM,qEAAqE,GAAG,EAAE,CAAC,CAAC;IACxJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,2DAA2D;AAC3D,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO;QACL,oCAAoC;QACpC,kBAAkB,KAAK,EAAE;QACzB,sBAAsB;QACtB,6FAA6F;QAC7F,oFAAoF;QACpF,sBAAsB;QACtB,2BAA2B;QAC3B,0BAA0B;QAC1B,6BAA6B;QAC7B,4BAA4B;QAC5B,2BAA2B;QAC3B,2BAA2B;QAC3B,wCAAwC;QACxC,2BAA2B;QAC3B,yBAAyB;QACzB,+BAA+B;QAC/B,2BAA2B;QAC3B,+BAA+B;KAChC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,iBAAiB,GAAG;IACxB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,gBAAgB;IAChB,sBAAsB;IACtB,kCAAkC;IAClC,eAAe;IACf,wBAAwB;IACxB,YAAY;IACZ,gBAAgB;IAChB,kBAAkB;IAClB,YAAY;IACZ,mBAAmB;IACnB,uBAAuB;IACvB,kBAAkB;IAClB,mBAAmB;IACnB,kBAAkB;IAClB,iBAAiB;IACjB,oBAAoB;CACZ,CAAC;AAEX,kHAAkH;AAClH,MAAM,UAAU,SAAS,CAAC,IAAkB;IAC1C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/B,6CAA6C;QAC7C,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACtC,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,eAAe,CAAC,IAAkB,EAAE,KAAmB;IACrE,MAAM,GAAG,GAAuC,EAAE,CAAC;IACnD,KAAK,MAAM,IAAI,IAAI,iBAAiB;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;IAC5D,GAAG,CAAC,yBAAyB,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IACjD,GAAG,CAAC,qBAAqB,CAAC,GAAG,GAAG,CAAC;IACjC,GAAG,CAAC,mBAAmB,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC;IAC9C,qDAAqD;IACrD,GAAG,CAAC,qBAAqB,CAAC,GAAG,GAAG,CAAC;IACjC,OAAO,GAAG,CAAC;AACb,CAAC;AAUD,+FAA+F;AAC/F,MAAM,gBAAgB,GAAG,CAAC,WAAW,EAAE,YAAY,EAAE,oBAAoB,CAAU,CAAC;AAEpF,IAAI,KAAwC,CAAC;AAE7C,oEAAoE;AACpE,IAAI,WAA+B,CAAC;AAEpC;;;;;GAKG;AACH,MAAM,UAAU,YAAY;IAC1B,KAAK,KAAK,SAAS,EAAE,CAAC;IACtB,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,IAAI,WAAW,KAAK,SAAS;QAAE,MAAM,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACrF,WAAW,GAAG,SAAS,CAAC;IACxB,KAAK,GAAG,SAAS,CAAC;AACpB,CAAC;AAED,KAAK,UAAU,SAAS;IACtB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC;QACrE,WAAW,GAAG,MAAM,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QACnB,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QACtD,MAAM,SAAS,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAClC,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;YACnG,IAAI,CAAC,KAAK,CAAC,OAAO;gBAAE,SAAS;YAC7B,0EAA0E;YAC1E,MAAM,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9H,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,4BAA4B;QAC5B,KAAK,GAAG,SAAS,CAAC;QAClB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,oCAAoC;AACpC,gFAAgF;AAEhF,wIAAwI;AACxI,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC;IAChD,WAAW;IACX,iBAAiB;IACjB,eAAe;IACf,cAAc;IACd,aAAa;IACb,YAAY;IACZ,2BAA2B;IAC3B,iBAAiB;IACjB,eAAe;IACf,WAAW;IACX,cAAc;IACd,YAAY;IACZ,eAAe;IACf,mBAAmB;IACnB,qBAAqB;IACrB,aAAa;IACb,eAAe;IACf,2BAA2B;IAC3B,gBAAgB;IAChB,iBAAiB;IACjB,kBAAkB;IAClB,gBAAgB;IAChB,iBAAiB;IACjB,gBAAgB;IAChB,gBAAgB;IAChB,iBAAiB;IACjB,iBAAiB;IACjB,kBAAkB;IAClB,qBAAqB;IACrB,sBAAsB;IACtB,cAAc;IACd,4BAA4B;IAC5B,mBAAmB;IACnB,eAAe;IACf,+BAA+B;IAC/B,eAAe;IACf,mBAAmB;IACnB,qBAAqB;IACrB,iBAAiB;IACjB,cAAc;IACd,kBAAkB;IAClB,kBAAkB;IAClB,cAAc;IACd,sBAAsB;IACtB,gBAAgB;IAChB,4BAA4B;IAC5B,mCAAmC;IACnC,iBAAiB;IACjB,oBAAoB;IACpB,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAClI,QAAQ,IAAI,EAAE;QACd,UAAU,IAAI,EAAE;KACjB,CAAC;CACH,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,gBAAgB,GAAwB,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;AAE/F,uEAAuE;AACvE,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC,CAAC,gBAAgB,EAAE,aAAa,EAAE,wBAAwB,EAAE,cAAc,CAAC,CAAC,CAAC;AAE/H,8CAA8C;AAC9C,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;AAE/E,oGAAoG;AACpG,SAAS,OAAO,CAAC,GAAW;IAC1B,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,WAAW,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACzF,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE;QAC1C,UAAU,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC;QACnE,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE;KACxC,CAAC;AACJ,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,KAAyB;IACvE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACnD,IAAI,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,MAAM,OAAO,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,MAAM,IAAI,EAAE,CAAC;IACzF,IAAI,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,mFAAmF;IACnF,IAAI,UAAU,KAAK,SAAS,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,UAAU,CAAC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAChH,IAAI,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAChG,sFAAsF;IACtF,IAAI,OAAO,KAAK,QAAQ,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,SAAS,CAAC;QAAE,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxG,IAAI,OAAO,KAAK,KAAK,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACxE,0CAA0C;IAC1C,IAAI,OAAO,KAAK,WAAW,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC9F,OAAO,KAAK,CAAC;AACf,CAAC;AASD,oHAAoH;AACpH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IACpJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAA+B;IAC/D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;YAAE,SAAS;QACpE,IAAI,kBAAkB,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AACtB,CAAC;AAED,gFAAgF;AAChF,kCAAkC;AAClC,gFAAgF;AAEhF,mFAAmF;AACnF,KAAK,UAAU,OAAO,CAAC,IAAc,EAAE,GAAW,EAAE,GAAuC,EAAE,KAAa,EAAE,KAAc;IACxH,OAAO,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;AACvF,CAAC;AAED,wDAAwD;AACxD,KAAK,UAAU,QAAQ,CAAC,IAAkB,EAAE,IAAY;IACtD,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,2CAA2C;AAC3C,KAAK,UAAU,MAAM,CAAC,IAAY;IAChC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CACtB,GAAG,EAAE,CAAC,IAAI,EACV,GAAG,EAAE,CAAC,KAAK,CACZ,CAAC;AACJ,CAAC;AAED,gHAAgH;AAChH,KAAK,UAAU,WAAW,CAAC,MAAc;IACvC,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC;QAAE,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IACtG,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,mBAAmB,CAAC,GAAW,EAAE,IAAY;IAC1D,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,SAAS,CAAC;QACR,IAAI,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACrF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,KAAK,CAAC;QAC/D,MAAM,GAAG,MAAM,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAgB,EAAE,GAAW,EAAE,GAAuC,EAAE,KAAa;IAC3H,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IACpC,MAAM,MAAM,GAAG,CAAC,OAAe,EAAE,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,kBAAkB,IAAI,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC,CAAC;IAExG,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,CAAC,WAAW,EAAE,wBAAwB,EAAE,WAAW,EAAE,kBAAkB,EAAE,sBAAsB,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACjJ,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvF,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAC1B,8EAA8E;QAC9E,IAAI,MAAM,mBAAmB,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAChD,MAAM,MAAM,CAAC,wCAAwC,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACxF,CAAC;QACD,OAAO;IACT,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;QAC9I,IAAI,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAAE,MAAM,MAAM,CAAC,qBAAqB,GAAG,yBAAyB,IAAI,EAAE,CAAC,CAAC;IAC3G,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5G,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1B,IAAI,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QACpD,IAAI,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;YAAE,MAAM,MAAM,CAAC,kBAAkB,MAAM,oCAAoC,KAAK,EAAE,CAAC,CAAC;IACvJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC3G,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,MAAM,MAAM,CAAC,uDAAuD,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC5H,MAAM,IAAI,GAAG,iBAAiB,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/D,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,MAAM,MAAM,CAAC,uCAAuC,MAAM,yDAAyD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxI,CAAC;IAED,wEAAwE;IACxE,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7E,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC;YAAE,OAAO,GAAG,IAAI,CAAC;IAC5F,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,CAAC,UAAU,EAAE,eAAe,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,kCAAkC,CAAC,CAAC;QAClH,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,MAAM,MAAM,CAAC,qCAAqC,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC5G,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;IACpG,CAAC;IACD,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,MAAM,CAAC,kBAAkB,MAAM,6GAA6G,CAAC,CAAC;IACtJ,CAAC;AACH,CAAC;AAED,sFAAsF;AACtF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAE7C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAgB,EAChB,IAAuB,EACvB,GAAuB,EACvB,GAAmD;IAEnD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACzF,MAAM,KAAK,GAAG,MAAM,YAAY,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACrD,IAAI,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,QAAQ,GAAG,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACpE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,QAAQ,CAAC;IAEf,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1B,6GAA6G;IAC7G,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,UAAU;QAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;IAC/D,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,yBAAyB,CAAC,CAAC;IACrF,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,GAAG,EAAE,EAAE,CAAC;AACtG,CAAC"}
|
|
@@ -26,7 +26,8 @@ export declare class GitError extends Error {
|
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
28
|
* This function runs `git <args>` and gives its stdout. It throws a `GitError` when git fails,
|
|
29
|
-
* and an `AbortError` when the signal aborts.
|
|
29
|
+
* and an `AbortError` when the signal aborts. In the handler of a git procedure under a root
|
|
30
|
+
* (`underGitRoot()`), git stays in the root: `confinedGitCommand()` of `root.ts`.
|
|
30
31
|
*/
|
|
31
32
|
export declare function git(args: string[], options?: GitRunOptions): Promise<string>;
|
|
32
33
|
/** This function splits output that git wrote with `-z` into its fields. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/procedures/git/run.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/procedures/git/run.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;CAC1C;AAED,+DAA+D;AAC/D,qBAAa,QAAS,SAAQ,KAAK;IAE/B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM;IAJzB,YACW,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EAIxB;CACF;AAED;;;;GAIG;AACH,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BtF;AAED,4EAA4E;AAC5E,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhD"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { runCommand } from "@procedures/shell/command";
|
|
9
9
|
import { GIT_MAX_BUFFER } from "./args.js";
|
|
10
|
+
import { confinedGitCommand, currentGitRoot } from "./root.js";
|
|
10
11
|
/** A git command that ended with an exit code other than 0. */
|
|
11
12
|
export class GitError extends Error {
|
|
12
13
|
args;
|
|
@@ -24,15 +25,18 @@ export class GitError extends Error {
|
|
|
24
25
|
}
|
|
25
26
|
/**
|
|
26
27
|
* This function runs `git <args>` and gives its stdout. It throws a `GitError` when git fails,
|
|
27
|
-
* and an `AbortError` when the signal aborts.
|
|
28
|
+
* and an `AbortError` when the signal aborts. In the handler of a git procedure under a root
|
|
29
|
+
* (`underGitRoot()`), git stays in the root: `confinedGitCommand()` of `root.ts`.
|
|
28
30
|
*/
|
|
29
31
|
export async function git(args, options = {}) {
|
|
32
|
+
const root = currentGitRoot();
|
|
33
|
+
const command = root === undefined ? { args, cwd: options.cwd, env: options.env } : await confinedGitCommand(root, args, options.cwd, options.env);
|
|
30
34
|
const result = await runCommand("git", {
|
|
31
|
-
args,
|
|
32
|
-
cwd:
|
|
35
|
+
args: command.args,
|
|
36
|
+
cwd: command.cwd,
|
|
33
37
|
signal: options.signal,
|
|
34
38
|
input: options.input,
|
|
35
|
-
env:
|
|
39
|
+
env: command.env,
|
|
36
40
|
maxOutputBytes: GIT_MAX_BUFFER,
|
|
37
41
|
});
|
|
38
42
|
if (result.aborted) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/procedures/git/run.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/procedures/git/run.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAe/D,+DAA+D;AAC/D,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEtB,IAAI;IACJ,QAAQ;IACR,MAAM;IACN,MAAM;IAJjB,YACW,IAAuB,EACvB,QAAgB,EAChB,MAAc,EACd,MAAc;QAEvB,KAAK,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,QAAQ,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;oBAL9E,IAAI;wBACJ,QAAQ;sBACR,MAAM;sBACN,MAAM;QAGf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc,EAAE,OAAO,GAAkB,EAAE;IACnE,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACnJ,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE;QACrC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,cAAc,EAAE,cAAc;KAC/B,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;QACtD,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC;QAC1B,MAAM,KAAK,CAAC;IACd,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,CAAC,CAAC,CAAC,mBAAmB,cAAc,QAAQ,CAAC,CAAC;IACzF,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,OAAO,CAAC,MAAc;IACpC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;QAAE,MAAM,CAAC,GAAG,EAAE,CAAC;IACvC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@procedures/git",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.1",
|
|
5
5
|
"description": "Git as 45 typed procedures: status, diff, log, show, blame, commit, push, pull, branch, tag, merge, rebase, worktree, stash and more, run with argv, async and abortable.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"git",
|
|
@@ -60,13 +60,13 @@
|
|
|
60
60
|
"procedures": "./dist/register.js"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@procedures/client": "0.
|
|
64
|
-
"@procedures/
|
|
63
|
+
"@procedures/client": "0.9.1",
|
|
64
|
+
"@procedures/fs": "0.9.1",
|
|
65
|
+
"@procedures/shell": "0.9.1",
|
|
65
66
|
"zod": "^4.6.5"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
68
69
|
"@mark1russell7/cue": "^1.0.0",
|
|
69
|
-
"@procedures/fs": "0.8.1",
|
|
70
70
|
"@types/node": "^22.0.0",
|
|
71
71
|
"typescript": "^7.0.2",
|
|
72
72
|
"vitest": "^5.0.3"
|
package/src/module.ts
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* This file is referenced by package.json's client.procedures field.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { createProcedure, zodAdapter, defineModule, type AnyProcedure, type Effects, type FsRootRules, type ProcedureModule, PROCEDURE_REGISTRY, registerModules, type ProcedureRegistry } from "@procedures/client";
|
|
10
|
+
import { createProcedure, zodAdapter, defineModule, type AnyProcedure, type Effects, type FsRootRules, type ProcedureContext, type ProcedureModule, PROCEDURE_REGISTRY, registerModules, type ProcedureRegistry } from "@procedures/client";
|
|
11
|
+
import { underGitRoot } from "./procedures/git/root.js";
|
|
11
12
|
import { gitStatus } from "./procedures/git/status.js";
|
|
12
13
|
import { gitAdd } from "./procedures/git/add.js";
|
|
13
14
|
import { gitCommit } from "./procedures/git/commit.js";
|
|
@@ -245,20 +246,51 @@ const CHANGES_REPOSITORY: Effects = { reads: ["fs"], writes: ["fs"] };
|
|
|
245
246
|
const RUNS_HOOKS: Effects = { reads: ["fs"], writes: ["fs", "process"] };
|
|
246
247
|
|
|
247
248
|
/**
|
|
248
|
-
* The
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
* - The
|
|
253
|
-
*
|
|
249
|
+
* The rules of the git procedures under a root of the files (roadmap R33, tracker item O35). Each
|
|
250
|
+
* git procedure is confined: the working folder `cwd` is in the root, and its default is the root.
|
|
251
|
+
* The handler runs in `underGitRoot()`, so git stays in the root (`procedures/git/root.ts`):
|
|
252
|
+
* - `GIT_CEILING_DIRECTORIES` stops git at the root, so git finds no repository above the root.
|
|
253
|
+
* - The `-c` options turn off the hooks, `core.fsmonitor`, the local transports and the
|
|
254
|
+
* submodules. The configuration of the system and the global configuration do not apply.
|
|
255
|
+
* - Before the first command in a folder, git examines the repository: a configuration key that
|
|
256
|
+
* starts a program, a folder outside the root or a submodule is refused.
|
|
254
257
|
*/
|
|
255
|
-
const
|
|
256
|
-
|
|
258
|
+
const IN_A_ROOT: FsRootRules = { cwd: "cwd" };
|
|
259
|
+
|
|
260
|
+
/** A procedure whose `paths` are pathspecs from the working folder. */
|
|
261
|
+
const WITH_PATHSPECS: FsRootRules = { cwd: "cwd", names: ["paths"] };
|
|
262
|
+
|
|
263
|
+
/** The rules of the procedures that name more than the working folder. The others get `IN_A_ROOT`. */
|
|
264
|
+
const ROOT_RULES: Readonly<Record<string, FsRootRules>> = {
|
|
265
|
+
"git.status": WITH_PATHSPECS,
|
|
266
|
+
"git.add": WITH_PATHSPECS,
|
|
267
|
+
"git.commit": WITH_PATHSPECS,
|
|
268
|
+
"git.checkout": WITH_PATHSPECS,
|
|
269
|
+
"git.diff": WITH_PATHSPECS,
|
|
270
|
+
"git.stash.push": WITH_PATHSPECS,
|
|
271
|
+
"git.reset": WITH_PATHSPECS,
|
|
272
|
+
"git.restore": WITH_PATHSPECS,
|
|
273
|
+
"git.blame": { cwd: "cwd", names: ["path"] },
|
|
274
|
+
// The URL goes to the network only: the transports file and ext are off under a root
|
|
275
|
+
"git.clone": { cwd: "cwd", names: ["dest"] },
|
|
276
|
+
"git.worktree.add": { cwd: "cwd", names: ["path"] },
|
|
277
|
+
"git.worktree.remove": { cwd: "cwd", names: ["path"] },
|
|
257
278
|
};
|
|
258
279
|
|
|
259
|
-
/**
|
|
280
|
+
/**
|
|
281
|
+
* The procedure with its rules under a root. Its handler runs in `underGitRoot()` with the root of
|
|
282
|
+
* the call (`ctx.fsRoot`). Without a root, the handler runs as before.
|
|
283
|
+
*/
|
|
260
284
|
function underARoot(procedure: AnyProcedure): AnyProcedure {
|
|
261
|
-
|
|
285
|
+
const handler = procedure.handler as ((input: unknown, ctx: ProcedureContext) => Promise<unknown>) | undefined;
|
|
286
|
+
const fsRoot = ROOT_RULES[procedure.path.join(".")] ?? IN_A_ROOT;
|
|
287
|
+
return {
|
|
288
|
+
...procedure,
|
|
289
|
+
metadata: { ...procedure.metadata, fsRoot },
|
|
290
|
+
...(handler === undefined
|
|
291
|
+
? {}
|
|
292
|
+
: { handler: ((input: unknown, ctx: ProcedureContext) => underGitRoot(ctx?.fsRoot, procedure.path, () => handler(input, ctx))) as AnyProcedure["handler"] }),
|
|
293
|
+
};
|
|
262
294
|
}
|
|
263
295
|
|
|
264
296
|
// =============================================================================
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { join, basename } from "node:path";
|
|
8
8
|
import { gitArg } from "./args.js";
|
|
9
9
|
import { git, type GitContext } from "./run.js";
|
|
10
|
+
import { pathInGitRoot, remoteUrlInGitRoot } from "./root.js";
|
|
10
11
|
import type { GitCloneInput, GitCloneOutput } from "../../types.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -18,6 +19,9 @@ export async function gitClone(input: GitCloneInput, ctx: GitContext = {}): Prom
|
|
|
18
19
|
// Determine destination directory
|
|
19
20
|
const destDir = dest || basename(url, ".git").replace(/\.git$/, "");
|
|
20
21
|
const fullPath = cwd ? join(cwd, destDir) : destDir;
|
|
22
|
+
// Under a root, the folder of the clone is in the root, also when it comes from the URL ("..")
|
|
23
|
+
await pathInGitRoot(fullPath);
|
|
24
|
+
remoteUrlInGitRoot(url);
|
|
21
25
|
|
|
22
26
|
const args: string[] = ["clone"];
|
|
23
27
|
if (branch) args.push("-b", branch);
|