@zukhruf/git-hooks 0.3.41 → 0.3.42

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.
Files changed (66) hide show
  1. package/README.md +157 -3
  2. package/dist/build.d.ts +15 -0
  3. package/dist/build.d.ts.map +1 -0
  4. package/dist/build.js +163 -0
  5. package/dist/build.js.map +1 -0
  6. package/dist/codegen.d.ts +1 -1
  7. package/dist/codegen.d.ts.map +1 -1
  8. package/dist/codegen.js.map +1 -1
  9. package/dist/commit.d.ts.map +1 -1
  10. package/dist/commit.js +2 -1
  11. package/dist/commit.js.map +1 -1
  12. package/dist/format.d.ts +1 -1
  13. package/dist/format.d.ts.map +1 -1
  14. package/dist/format.js +5 -2
  15. package/dist/format.js.map +1 -1
  16. package/dist/index.d.ts +4 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +3 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/push.d.ts +29 -0
  21. package/dist/push.d.ts.map +1 -0
  22. package/dist/push.js +108 -0
  23. package/dist/push.js.map +1 -0
  24. package/dist/ref-update.d.ts +17 -0
  25. package/dist/ref-update.d.ts.map +1 -0
  26. package/dist/ref-update.js +43 -0
  27. package/dist/ref-update.js.map +1 -0
  28. package/dist/scripts/pre-commit.d.ts +2 -1
  29. package/dist/scripts/pre-commit.d.ts.map +1 -1
  30. package/dist/scripts/pre-commit.js.map +1 -1
  31. package/dist/scripts/pre-push.d.ts +4 -0
  32. package/dist/scripts/pre-push.d.ts.map +1 -0
  33. package/dist/scripts/pre-push.js +35 -0
  34. package/dist/scripts/pre-push.js.map +1 -0
  35. package/dist/snapshot/commit-files.d.ts +5 -0
  36. package/dist/snapshot/commit-files.d.ts.map +1 -0
  37. package/dist/snapshot/commit-files.js +101 -0
  38. package/dist/snapshot/commit-files.js.map +1 -0
  39. package/dist/snapshot/drift.d.ts +3 -0
  40. package/dist/snapshot/drift.d.ts.map +1 -0
  41. package/dist/snapshot/drift.js +72 -0
  42. package/dist/snapshot/drift.js.map +1 -0
  43. package/dist/snapshot/installs.d.ts +2 -0
  44. package/dist/snapshot/installs.d.ts.map +1 -0
  45. package/dist/snapshot/installs.js +83 -0
  46. package/dist/snapshot/installs.js.map +1 -0
  47. package/dist/snapshot/nx.d.ts +7 -0
  48. package/dist/snapshot/nx.d.ts.map +1 -0
  49. package/dist/snapshot/nx.js +20 -0
  50. package/dist/snapshot/nx.js.map +1 -0
  51. package/dist/snapshot/packages.d.ts +2 -0
  52. package/dist/snapshot/packages.d.ts.map +1 -0
  53. package/dist/snapshot/packages.js +72 -0
  54. package/dist/snapshot/packages.js.map +1 -0
  55. package/dist/snapshot/workspaces.d.ts +2 -0
  56. package/dist/snapshot/workspaces.d.ts.map +1 -0
  57. package/dist/snapshot/workspaces.js +26 -0
  58. package/dist/snapshot/workspaces.js.map +1 -0
  59. package/dist/step.d.ts +2 -3
  60. package/dist/step.d.ts.map +1 -1
  61. package/dist/step.js +2 -2
  62. package/dist/step.js.map +1 -1
  63. package/dist/sync.d.ts +1 -1
  64. package/dist/sync.d.ts.map +1 -1
  65. package/dist/sync.js.map +1 -1
  66. package/package.json +4 -1
package/dist/push.js ADDED
@@ -0,0 +1,108 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { mkdir, mkdtempDisposable, realpath } from 'node:fs/promises';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { setTimeout as delay } from 'node:timers/promises';
7
+ import { promisify } from 'node:util';
8
+ import { FileLock } from '@zukhruf/fs';
9
+ import { readRefUpdates } from "./ref-update.js";
10
+ import { writeCommitFiles } from "./snapshot/commit-files.js";
11
+ import { hasInstallDrift } from "./snapshot/drift.js";
12
+ import { installFor } from "./snapshot/installs.js";
13
+ import { runNx } from "./snapshot/nx.js";
14
+ import { linkPackages } from "./snapshot/packages.js";
15
+ const execFileAsync = promisify(execFile);
16
+ export class MissingLockfileError extends Error {
17
+ sha;
18
+ constructor(sha) {
19
+ super(`${sha.slice(0, 7)} has no package-lock.json`);
20
+ this.name = 'MissingLockfileError';
21
+ this.sha = sha;
22
+ }
23
+ }
24
+ // What `git push` is about to send: the remote and the ref updates. A step
25
+ // judges the pushed commits in snapshots, never the working tree, because
26
+ // other sessions can edit the working tree while the hook runs.
27
+ export class Push {
28
+ remote;
29
+ updates;
30
+ #root;
31
+ #environment;
32
+ #notice;
33
+ constructor({ root, environment, remote, notice }, updates) {
34
+ this.remote = remote;
35
+ this.updates = updates;
36
+ this.#root = root;
37
+ this.#environment = environment;
38
+ this.#notice = notice;
39
+ }
40
+ static async read(options) {
41
+ const git = (...args) => gitIn(options.root, options.environment, ...args);
42
+ return new Push(options, await readRefUpdates(git, options.remote.name, options.input));
43
+ }
44
+ // Runs `work` on the snapshot of one commit: its files in a temporary
45
+ // folder, with a node_modules that a build can use. `environment` makes git
46
+ // see a clean checkout of the commit there, and holds the nx cache of the
47
+ // state folder. One snapshot is open at a time in a repo; the snapshot is
48
+ // deleted after `work`.
49
+ async inSnapshot(sha, work) {
50
+ const state = join((await this.#git('rev-parse', '--path-format=absolute', '--git-common-dir')).trim(), 'git-hooks');
51
+ await mkdir(state, { recursive: true });
52
+ using lock = FileLock.open(join(state, 'lock'));
53
+ if (!lock.tryLock()) {
54
+ this.#notice('waiting for another pre-push build in this repo');
55
+ while (!lock.tryLock())
56
+ await delay(200);
57
+ }
58
+ await using temporary = await mkdtempDisposable(join(tmpdir(), 'git-hooks-push-'));
59
+ const top = await realpath(temporary.path);
60
+ const folder = join(top, 'tree');
61
+ await writeCommitFiles((...args) => this.#git(...args), { cwd: this.#root, env: this.#environment }, sha, folder);
62
+ if (!existsSync(join(folder, 'package-lock.json')))
63
+ throw new MissingLockfileError(sha);
64
+ const installed = (await hasInstallDrift(join(folder, 'package-lock.json'), join(this.#root, 'node_modules/.package-lock.json')))
65
+ ? await installFor(state, folder, this.#environment, () => this.#notice(`${sha.slice(0, 7)}: the installed packages differ from package-lock.json; installing it with npm ci (first time for this lockfile)`))
66
+ : this.#root;
67
+ await linkPackages(installed, folder);
68
+ const cache = join(state, 'nx');
69
+ const environment = {
70
+ ...this.#environment,
71
+ GIT_DIR: (await this.#git('rev-parse', '--absolute-git-dir')).trim(),
72
+ GIT_WORK_TREE: folder,
73
+ GIT_INDEX_FILE: join(top, 'index'),
74
+ NX_DAEMON: 'false',
75
+ NX_CACHE_DIRECTORY: cache,
76
+ NX_WORKSPACE_DATA_DIRECTORY: join(cache, 'workspace-data'),
77
+ };
78
+ // A temporary index of the commit, refreshed against the snapshot, so git
79
+ // finds no changed and no untracked files.
80
+ await gitIn(folder, environment, 'read-tree', sha);
81
+ await gitIn(folder, environment, 'update-index', '-q', '--refresh');
82
+ // Awaited here, so the snapshot and the lock stay until `work` ends.
83
+ return await work(folder, environment);
84
+ }
85
+ // Runs nx in the snapshot of one commit, and gives its standard output.
86
+ // When nx exits with a code other than 0, it throws.
87
+ nx(sha, ...args) {
88
+ return this.inSnapshot(sha, async (folder, environment) => {
89
+ const { code, stdout, stderr } = await runNx(folder, environment, args);
90
+ if (code !== 0)
91
+ throw new Error(`nx ${args.join(' ')} exited with ${code}:\n${`${stdout}${stderr}`.trimEnd()}`);
92
+ return stdout;
93
+ });
94
+ }
95
+ #git(...args) {
96
+ return gitIn(this.#root, this.#environment, ...args);
97
+ }
98
+ }
99
+ async function gitIn(cwd, environment, ...args) {
100
+ const { stdout } = await execFileAsync('git', args, {
101
+ cwd,
102
+ env: environment,
103
+ encoding: 'utf8',
104
+ maxBuffer: 2 ** 30,
105
+ });
106
+ return stdout;
107
+ }
108
+ //# sourceMappingURL=push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.js","sourceRoot":"","sources":["../src/push.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ interface RefLine {
2
+ readonly localRef: string;
3
+ readonly localSha: string;
4
+ readonly remoteRef: string;
5
+ readonly remoteSha: string;
6
+ }
7
+ export type RefUpdate = (RefLine & {
8
+ readonly kind: 'create' | 'update';
9
+ readonly head: string;
10
+ readonly base: string | undefined;
11
+ }) | (RefLine & {
12
+ readonly kind: 'delete';
13
+ });
14
+ type Git = (...args: string[]) => Promise<string>;
15
+ export declare function readRefUpdates(git: Git, remote: string, input: string): Promise<RefUpdate[]>;
16
+ export {};
17
+ //# sourceMappingURL=ref-update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ref-update.d.ts","sourceRoot":"","sources":["../src/ref-update.ts"],"names":[],"mappings":"AAEA,UAAU,OAAO;IACf,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAKD,MAAM,MAAM,SAAS,GACjB,CAAC,OAAO,GAAG;IACT,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC,GACF,CAAC,OAAO,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAC;AAE5C,KAAK,GAAG,GAAG,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAIlD,wBAAsB,cAAc,CAClC,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,SAAS,EAAE,CAAC,CAoBtB"}
@@ -0,0 +1,43 @@
1
+ const absent = /^0+$/;
2
+ export async function readRefUpdates(git, remote, input) {
3
+ const updates = [];
4
+ for (const line of input.split('\n')) {
5
+ if (line.trim() === '')
6
+ continue;
7
+ const [localRef = '', localSha = '', remoteRef = '', remoteSha = ''] = line
8
+ .trim()
9
+ .split(' ');
10
+ const refLine = { localRef, localSha, remoteRef, remoteSha };
11
+ if (absent.test(localSha)) {
12
+ updates.push({ ...refLine, kind: 'delete' });
13
+ continue;
14
+ }
15
+ const kind = absent.test(remoteSha) ? 'create' : 'update';
16
+ const base = kind === 'update' && (await isLocal(git, remoteSha))
17
+ ? remoteSha
18
+ : await firstUnseenParent(git, remote, localSha);
19
+ updates.push({ ...refLine, kind, head: localSha, base });
20
+ }
21
+ return updates;
22
+ }
23
+ async function isLocal(git, sha) {
24
+ try {
25
+ await git('cat-file', '-e', `${sha}^{commit}`);
26
+ return true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ // The parent of the first commit that no ref of the remote has, as the
33
+ // pre-commit framework finds the "from" ref of its pre-push stage.
34
+ async function firstUnseenParent(git, remote, head) {
35
+ const unseen = await git('rev-list', head, '--topo-order', '--reverse', '--not', `--remotes=${remote}`);
36
+ const [first = ''] = unseen.split('\n', 1);
37
+ if (first === '')
38
+ return head;
39
+ const parents = await git('rev-list', '--parents', '--max-count=1', first);
40
+ const [, parent] = parents.trim().split(' ');
41
+ return parent;
42
+ }
43
+ //# sourceMappingURL=ref-update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ref-update.js","sourceRoot":"","sources":["../src/ref-update.ts"],"names":[],"mappings":"AAsBA,MAAM,MAAM,GAAG,MAAM,CAAC;AAEtB,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAQ,EACR,MAAc,EACd,KAAa;IAEb,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,SAAS;QACjC,MAAM,CAAC,QAAQ,GAAG,EAAE,EAAE,QAAQ,GAAG,EAAE,EAAE,SAAS,GAAG,EAAE,EAAE,SAAS,GAAG,EAAE,CAAC,GAAG,IAAI;aACxE,IAAI,EAAE;aACN,KAAK,CAAC,GAAG,CAAC,CAAC;QACd,MAAM,OAAO,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;QAC7D,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC7C,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC1D,MAAM,IAAI,GACR,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAClD,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,MAAM,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,GAAQ,EAAE,GAAW;IAC1C,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,GAAG,WAAW,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,uEAAuE;AACvE,mEAAmE;AACnE,KAAK,UAAU,iBAAiB,CAC9B,GAAQ,EACR,MAAc,EACd,IAAY;IAEZ,MAAM,MAAM,GAAG,MAAM,GAAG,CACtB,UAAU,EACV,IAAI,EACJ,cAAc,EACd,WAAW,EACX,OAAO,EACP,aAAa,MAAM,EAAE,CACtB,CAAC;IACF,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3C,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,KAAK,CAAC,CAAC;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { Commit } from '../commit.ts';
1
2
  import type { Step } from '../step.ts';
2
- export declare function preCommit(steps: readonly Step[]): Promise<void>;
3
+ export declare function preCommit(steps: readonly Step<Commit>[]): Promise<void>;
3
4
  //# sourceMappingURL=pre-commit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pre-commit.d.ts","sourceRoot":"","sources":["../../src/scripts/pre-commit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAKvC,wBAAsB,SAAS,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAarE"}
1
+ {"version":3,"file":"pre-commit.d.ts","sourceRoot":"","sources":["../../src/scripts/pre-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAKvC,wBAAsB,SAAS,CAAC,KAAK,EAAE,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAa7E"}
@@ -1 +1 @@
1
- {"version":3,"file":"pre-commit.js","sourceRoot":"","sources":["../../src/scripts/pre-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAGtC,+EAA+E;AAC/E,2EAA2E;AAC3E,0DAA0D;AAC1D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAsB;IACpD,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACtD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1D,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;QACjD,KAAK,MAAM,IAAI,IAAI,IAAI;YAAE,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;QACnE,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;YACzD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"pre-commit.js","sourceRoot":"","sources":["../../src/scripts/pre-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAGtC,+EAA+E;AAC/E,2EAA2E;AAC3E,0DAA0D;AAC1D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAA8B;IAC5D,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACtD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1D,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;QACjD,KAAK,MAAM,IAAI,IAAI,IAAI;YAAE,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;QACnE,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;YACzD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Push } from '../push.ts';
2
+ import type { Step } from '../step.ts';
3
+ export declare function prePush(steps: readonly Step<Push>[]): Promise<void>;
4
+ //# sourceMappingURL=pre-push.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-push.d.ts","sourceRoot":"","sources":["../../src/scripts/pre-push.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAOvC,wBAAsB,OAAO,CAAC,KAAK,EAAE,SAAS,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBzE"}
@@ -0,0 +1,35 @@
1
+ import { text } from 'node:stream/consumers';
2
+ import { Push } from "../push.js";
3
+ // What a repo's `.husky/pre-push.ts` calls. Git runs the hook at the root of
4
+ // the work tree, with the name and the URL of the remote as arguments and one
5
+ // ref update on each line of the standard input. This is the one module that
6
+ // prints and reads the arguments, the input and the environment, as a script
7
+ // may.
8
+ export async function prePush(steps) {
9
+ let current = '';
10
+ const print = (name, message) => {
11
+ const [first = '', ...rest] = message.split('\n');
12
+ console.error(`${name.padEnd(9)} ${first}`);
13
+ for (const line of rest)
14
+ console.error(`${' '.repeat(10)}${line}`);
15
+ };
16
+ const [name = '', url = ''] = process.argv.slice(2);
17
+ const push = await Push.read({
18
+ root: process.cwd(),
19
+ environment: process.env,
20
+ remote: { name, url },
21
+ input: await text(process.stdin),
22
+ notice: (message) => print(current, message),
23
+ });
24
+ for (const step of steps) {
25
+ current = step.name;
26
+ const outcome = await step.run(push);
27
+ print(step.name, outcome.message);
28
+ if (outcome.kind === 'fail') {
29
+ console.error('✖ push stopped by the pre-push hook');
30
+ process.exitCode = 1;
31
+ return;
32
+ }
33
+ }
34
+ }
35
+ //# sourceMappingURL=pre-push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-push.js","sourceRoot":"","sources":["../../src/scripts/pre-push.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAE7C,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGlC,6EAA6E;AAC7E,8EAA8E;AAC9E,6EAA6E;AAC7E,6EAA6E;AAC7E,OAAO;AACP,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAA4B;IACxD,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,OAAe,EAAE,EAAE;QAC9C,MAAM,CAAC,KAAK,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClD,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;QAC5C,KAAK,MAAM,IAAI,IAAI,IAAI;YAAE,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC;IACF,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC;QAC3B,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE;QACnB,WAAW,EAAE,OAAO,CAAC,GAAG;QACxB,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE;QACrB,KAAK,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QAChC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC;KAC7C,CAAC,CAAC;IACH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC;QACpB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;YACrD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function writeCommitFiles(git: (...args: string[]) => Promise<string>, gitOptions: {
2
+ cwd: string;
3
+ env: NodeJS.ProcessEnv;
4
+ }, sha: string, folder: string): Promise<void>;
5
+ //# sourceMappingURL=commit-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-files.d.ts","sourceRoot":"","sources":["../../src/snapshot/commit-files.ts"],"names":[],"mappings":"AAgBA,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,EAC3C,UAAU,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,EACnD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAqDf"}
@@ -0,0 +1,101 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { once } from 'node:events';
3
+ import { chmod, mkdir, stat, symlink, writeFile } from 'node:fs/promises';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ // Writes the files of one commit into an empty folder, from the object store:
6
+ // `git ls-tree` names them and one `git cat-file --batch` gives their content.
7
+ // No filter applies (no autocrlf, no smudge, no LFS), and `export-ignore` does
8
+ // not apply. A submodule is not a file, so it is not written.
9
+ export async function writeCommitFiles(git, gitOptions, sha, folder) {
10
+ const blobs = (await git('ls-tree', '-r', '-z', '--full-tree', sha))
11
+ .split('\0')
12
+ .filter((line) => line !== '')
13
+ .map((line) => {
14
+ const tab = line.indexOf('\t');
15
+ const [mode = '', type = '', object = ''] = line.slice(0, tab).split(' ');
16
+ return { mode, type, object, path: line.slice(tab + 1) };
17
+ })
18
+ .filter(({ type }) => type === 'blob');
19
+ const catFile = spawn('git', ['cat-file', '--batch'], {
20
+ ...gitOptions,
21
+ stdio: ['pipe', 'pipe', 'inherit'],
22
+ });
23
+ const exited = once(catFile, 'close');
24
+ catFile.stdin.end(blobs.map(({ object }) => `${object}\n`).join(''));
25
+ const records = new Records(catFile.stdout);
26
+ const links = [];
27
+ for (const blob of blobs) {
28
+ const header = (await records.line()).split(' ');
29
+ const size = Number(header[2]);
30
+ if (header[1] !== 'blob' || !Number.isInteger(size))
31
+ throw new Error(`git cat-file gave "${header.join(' ')}" for ${blob.path}`);
32
+ const content = await records.bytes(size + 1);
33
+ const path = join(folder, blob.path);
34
+ await mkdir(dirname(path), { recursive: true });
35
+ if (blob.mode === '120000')
36
+ links.push({ blob, target: content.subarray(0, size).toString() });
37
+ else {
38
+ await writeFile(path, content.subarray(0, size));
39
+ if (blob.mode === '100755')
40
+ await chmod(path, 0o755);
41
+ }
42
+ }
43
+ await exited;
44
+ // The files come first: on Windows, a link becomes a junction when its
45
+ // target is a folder of the commit, or else a text file that holds the
46
+ // target, as git does with core.symlinks=false.
47
+ for (const { blob, target } of links) {
48
+ const path = join(folder, blob.path);
49
+ if (process.platform !== 'win32')
50
+ await symlink(target, path);
51
+ else {
52
+ const absolute = resolve(dirname(path), target);
53
+ const isFolder = await stat(absolute).then((stats) => stats.isDirectory(), () => false);
54
+ if (isFolder)
55
+ await symlink(absolute, path, 'junction');
56
+ else
57
+ await writeFile(path, target);
58
+ }
59
+ }
60
+ }
61
+ // Reads the records of `git cat-file --batch`: a header line, then the
62
+ // content and a newline.
63
+ class Records {
64
+ #chunks;
65
+ #buffer = Buffer.alloc(0);
66
+ constructor(stream) {
67
+ this.#chunks = stream[Symbol.asyncIterator]();
68
+ }
69
+ async line() {
70
+ let end = this.#buffer.indexOf(0x0a);
71
+ while (end === -1) {
72
+ this.#buffer = Buffer.concat([this.#buffer, await this.#next()]);
73
+ end = this.#buffer.indexOf(0x0a);
74
+ }
75
+ const line = this.#buffer.subarray(0, end).toString();
76
+ this.#buffer = this.#buffer.subarray(end + 1);
77
+ return line;
78
+ }
79
+ async bytes(count) {
80
+ if (this.#buffer.length < count) {
81
+ const parts = [this.#buffer];
82
+ let length = this.#buffer.length;
83
+ while (length < count) {
84
+ const chunk = await this.#next();
85
+ parts.push(chunk);
86
+ length += chunk.length;
87
+ }
88
+ this.#buffer = Buffer.concat(parts, length);
89
+ }
90
+ const bytes = this.#buffer.subarray(0, count);
91
+ this.#buffer = this.#buffer.subarray(count);
92
+ return bytes;
93
+ }
94
+ async #next() {
95
+ const { done, value } = await this.#chunks.next();
96
+ if (done === true)
97
+ throw new Error('git cat-file ended before it gave each file');
98
+ return Buffer.isBuffer(value) ? value : Buffer.from(String(value));
99
+ }
100
+ }
101
+ //# sourceMappingURL=commit-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-files.js","sourceRoot":"","sources":["../../src/snapshot/commit-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASnD,8EAA8E;AAC9E,+EAA+E;AAC/E,+EAA+E;AAC/E,8DAA8D;AAC9D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAA2C,EAC3C,UAAmD,EACnD,GAAW,EACX,MAAc;IAEd,MAAM,KAAK,GAAW,CAAC,MAAM,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;SACzE,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC;SAC7B,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1E,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;IAC3D,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IAEzC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE;QACpD,GAAG,UAAU;QACb,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;KACnC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACtC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAqC,EAAE,CAAC;IACnD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC;YACjD,MAAM,IAAI,KAAK,CACb,sBAAsB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,CAC3D,CAAC;QACJ,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;YACxB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;aAChE,CAAC;YACJ,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;YACjD,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IACD,MAAM,MAAM,CAAC;IACb,uEAAuE;IACvE,uEAAuE;IACvE,gDAAgD;IAChD,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;YAAE,MAAM,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;aACzD,CAAC;YACJ,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CACxC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAC9B,GAAG,EAAE,CAAC,KAAK,CACZ,CAAC;YACF,IAAI,QAAQ;gBAAE,MAAM,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;;gBACnD,MAAM,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;AACH,CAAC;AAED,uEAAuE;AACvE,yBAAyB;AACzB,MAAM,OAAO;IACF,OAAO,CAAwB;IACxC,OAAO,GAAW,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAElC,YAAY,MAAgB;QAC1B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACrC,OAAO,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACjE,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;QACtD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAa;QACvB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;YAChC,MAAM,KAAK,GAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;YACjC,OAAO,MAAM,GAAG,KAAK,EAAE,CAAC;gBACtB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;gBACjC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;YACzB,CAAC;YACD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC5C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAClD,IAAI,IAAI,KAAK,IAAI;YACf,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACrE,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ export declare function hasInstallDrift(lockfile: string, hiddenLockfile: string): Promise<boolean>;
2
+ export declare function withInstallScripts(lockfile: string): Promise<string[]>;
3
+ //# sourceMappingURL=drift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift.d.ts","sourceRoot":"","sources":["../../src/snapshot/drift.ts"],"names":[],"mappings":"AAcA,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC,CAmBlB;AAmCD,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAQ5E"}
@@ -0,0 +1,72 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ // Whether the installed packages differ from the lockfile of a commit. npm's
3
+ // hidden lockfile, node_modules/.package-lock.json, lists what is installed.
4
+ // Each difference in the third-party packages is drift: a missing package, a
5
+ // different version, or an extra package, which would build here and fail in
6
+ // CI. Links are not compared: a workspace link points into the snapshot.
7
+ export async function hasInstallDrift(lockfile, hiddenLockfile) {
8
+ const wanted = await packagesOf(lockfile);
9
+ let installed;
10
+ try {
11
+ installed = await packagesOf(hiddenLockfile);
12
+ }
13
+ catch (error) {
14
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
15
+ return true;
16
+ throw error;
17
+ }
18
+ for (const [path, entry] of wanted) {
19
+ const have = installed.get(path);
20
+ if (have === undefined) {
21
+ // npm skips an optional package that does not fit the platform.
22
+ if (!entry.optional)
23
+ return true;
24
+ }
25
+ else if (have.version !== entry.version)
26
+ return true;
27
+ }
28
+ for (const path of installed.keys())
29
+ if (!wanted.has(path))
30
+ return true;
31
+ return false;
32
+ }
33
+ // The third-party packages of a lockfile: the entries in a node_modules
34
+ // folder that are not links.
35
+ async function packagesOf(path) {
36
+ const lockfile = JSON.parse(await readFile(path, 'utf8'));
37
+ const packages = typeof lockfile === 'object' && lockfile !== null && 'packages' in lockfile
38
+ ? lockfile.packages
39
+ : undefined;
40
+ if (typeof packages !== 'object' || packages === null)
41
+ throw new TypeError(`${path} has no "packages"; npm 7 or later writes it`);
42
+ const entries = new Map();
43
+ for (const [key, value] of Object.entries(packages)) {
44
+ if (!key.includes('node_modules/'))
45
+ continue;
46
+ const entry = {
47
+ version: field(value, 'version'),
48
+ link: field(value, 'link') === true,
49
+ optional: field(value, 'optional') === true,
50
+ hasInstallScript: field(value, 'hasInstallScript') === true,
51
+ };
52
+ if (!entry.link)
53
+ entries.set(key, entry);
54
+ }
55
+ return entries;
56
+ }
57
+ function field(value, name) {
58
+ return typeof value === 'object' && value !== null && name in value
59
+ ? Reflect.get(value, name)
60
+ : undefined;
61
+ }
62
+ // The third-party packages that the lockfile marks with an install script.
63
+ // The root and the workspace packages have the mark too, but their scripts
64
+ // must not run in the state folder.
65
+ export async function withInstallScripts(lockfile) {
66
+ const names = new Set();
67
+ for (const [key, entry] of await packagesOf(lockfile))
68
+ if (entry.hasInstallScript)
69
+ names.add(key.slice(key.lastIndexOf('node_modules/') + 'node_modules/'.length));
70
+ return [...names];
71
+ }
72
+ //# sourceMappingURL=drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift.js","sourceRoot":"","sources":["../../src/snapshot/drift.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function installFor(state: string, snapshot: string, environment: NodeJS.ProcessEnv, installing: () => void): Promise<string>;
2
+ //# sourceMappingURL=installs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installs.d.ts","sourceRoot":"","sources":["../../src/snapshot/installs.ts"],"names":[],"mappings":"AA8BA,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,CAAC,UAAU,EAC9B,UAAU,EAAE,MAAM,IAAI,GACrB,OAAO,CAAC,MAAM,CAAC,CAejB"}
@@ -0,0 +1,83 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
3
+ import { existsSync } from 'node:fs';
4
+ import { copyFile, mkdir, readFile, readdir, rm, stat, utimes, writeFile, } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ import { promisify } from 'node:util';
7
+ import { withInstallScripts } from "./drift.js";
8
+ import { workspaceFolders } from "./workspaces.js";
9
+ const execFileAsync = promisify(execFile);
10
+ // The installs that the hook keeps: the ones that it used last.
11
+ const kept = 2;
12
+ // Written last, so a folder without it is an install that did not end.
13
+ const marker = 'installed';
14
+ // An install of the lockfile of the snapshot in a folder of the state folder,
15
+ // named by the hash of the lockfile. A second push with the same lockfile
16
+ // uses the same install. `installing` runs before a new install, because a
17
+ // full install takes some time.
18
+ export async function installFor(state, snapshot, environment, installing) {
19
+ const lockfile = await readFile(join(snapshot, 'package-lock.json'));
20
+ const hash = createHash('sha256').update(lockfile).digest('hex');
21
+ const installs = join(state, 'installs');
22
+ const folder = join(installs, hash.slice(0, 16));
23
+ if (existsSync(join(folder, marker))) {
24
+ const now = new Date();
25
+ await utimes(join(folder, marker), now, now);
26
+ }
27
+ else {
28
+ installing();
29
+ await rm(folder, { recursive: true, force: true });
30
+ await install(snapshot, folder, environment);
31
+ }
32
+ await prune(installs);
33
+ return folder;
34
+ }
35
+ // `npm ci --ignore-scripts`, and then `npm rebuild` with only the
36
+ // third-party packages that have install scripts, such as esbuild. The
37
+ // scripts of the repo and of its workspace packages, such as `prepare`,
38
+ // would act on the repo from the state folder, so they do not run. Without
39
+ // names, `npm rebuild` runs them too.
40
+ async function install(snapshot, folder, environment) {
41
+ await mkdir(folder, { recursive: true });
42
+ for (const file of ['package.json', 'package-lock.json', '.npmrc'])
43
+ if (existsSync(join(snapshot, file)))
44
+ await copyFile(join(snapshot, file), join(folder, file));
45
+ for (const workspace of await workspaceFolders(snapshot)) {
46
+ await mkdir(join(folder, workspace), { recursive: true });
47
+ await copyFile(join(snapshot, workspace, 'package.json'), join(folder, workspace, 'package.json'));
48
+ }
49
+ await npm(folder, environment, 'ci', '--ignore-scripts', '--no-audit', '--no-fund');
50
+ const names = await withInstallScripts(join(folder, 'package-lock.json'));
51
+ if (names.length > 0)
52
+ await npm(folder, environment, 'rebuild', ...names);
53
+ await writeFile(join(folder, marker), '');
54
+ }
55
+ async function npm(cwd, environment, ...args) {
56
+ try {
57
+ await execFileAsync('npm', args, {
58
+ cwd,
59
+ env: environment,
60
+ encoding: 'utf8',
61
+ maxBuffer: 2 ** 30,
62
+ // npm is a .cmd file on Windows, which only a shell runs. The
63
+ // arguments are npm's own flags and package names, which need no quotes.
64
+ shell: process.platform === 'win32',
65
+ });
66
+ }
67
+ catch (error) {
68
+ if (!(error instanceof Error) || !('stderr' in error))
69
+ throw error;
70
+ throw new Error(`npm ${args.join(' ')} failed:\n${String(error.stderr).trimEnd()}`, { cause: error });
71
+ }
72
+ }
73
+ async function prune(installs) {
74
+ const used = await Promise.all((await readdir(installs)).map(async (name) => ({
75
+ name,
76
+ at: await stat(join(installs, name, marker)).then(({ mtimeMs }) => mtimeMs, () => -1),
77
+ })));
78
+ used.sort((left, right) => right.at - left.at);
79
+ for (const [index, { name, at }] of used.entries())
80
+ if (index >= kept || at < 0)
81
+ await rm(join(installs, name), { recursive: true, force: true });
82
+ }
83
+ //# sourceMappingURL=installs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installs.js","sourceRoot":"","sources":["../../src/snapshot/installs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface NxRun {
2
+ readonly code: number;
3
+ readonly stdout: string;
4
+ readonly stderr: string;
5
+ }
6
+ export declare function runNx(folder: string, environment: NodeJS.ProcessEnv, args: readonly string[]): Promise<NxRun>;
7
+ //# sourceMappingURL=nx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nx.d.ts","sourceRoot":"","sources":["../../src/snapshot/nx.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAID,wBAAgB,KAAK,CACnB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,CAAC,UAAU,EAC9B,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,OAAO,CAAC,KAAK,CAAC,CAoBhB"}
@@ -0,0 +1,20 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { join } from 'node:path';
3
+ // Runs the nx of the snapshot's node_modules in the snapshot. On Windows,
4
+ // npm writes `.bin/nx.cmd`, which only a shell runs.
5
+ export function runNx(folder, environment, args) {
6
+ const windows = process.platform === 'win32';
7
+ return new Promise((resolve) => {
8
+ execFile(join(folder, 'node_modules/.bin', windows ? 'nx.cmd' : 'nx'), args, {
9
+ cwd: folder,
10
+ env: environment,
11
+ encoding: 'utf8',
12
+ maxBuffer: 2 ** 30,
13
+ shell: windows,
14
+ }, (error, stdout, stderr) => {
15
+ const code = error === null ? 0 : typeof error.code === 'number' ? error.code : 1;
16
+ resolve({ code, stdout, stderr });
17
+ });
18
+ });
19
+ }
20
+ //# sourceMappingURL=nx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nx.js","sourceRoot":"","sources":["../../src/snapshot/nx.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,0EAA0E;AAC1E,qDAAqD;AACrD,MAAM,UAAU,KAAK,CACnB,MAAc,EACd,WAA8B,EAC9B,IAAuB;IAEvB,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC7C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,QAAQ,CACN,IAAI,CAAC,MAAM,EAAE,mBAAmB,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAC5D,IAAI,EACJ;YACE,GAAG,EAAE,MAAM;YACX,GAAG,EAAE,WAAW;YAChB,QAAQ,EAAE,MAAM;YAChB,SAAS,EAAE,CAAC,IAAI,EAAE;YAClB,KAAK,EAAE,OAAO;SACf,EACD,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACxB,MAAM,IAAI,GACR,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACvE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACpC,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function linkPackages(installRoot: string, snapshot: string): Promise<void>;
2
+ //# sourceMappingURL=packages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packages.d.ts","sourceRoot":"","sources":["../../src/snapshot/packages.ts"],"names":[],"mappings":"AAsBA,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAgBf"}