dsh-wechat-remote 1.7.6 → 1.7.8
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/README.md +7 -5
- package/assets/plugin.tgz +0 -0
- package/assets/release.json +10 -49
- package/bin/dsh-discovery.mjs +18 -8
- package/bin/native-recovery.mjs +44 -0
- package/bin/setup.mjs +90 -30
- package/lib/install-control.js +1 -1
- package/lib/install-profile.js +113 -159
- package/lib/install-runtime.js +17 -0
- package/lib/native-recovery.js +7478 -0
- package/lib/update-worker.js +253 -185
- package/package.json +1 -1
package/lib/install-profile.js
CHANGED
|
@@ -3,127 +3,70 @@
|
|
|
3
3
|
// src/install-profile.ts
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
// src/secure-file.ts
|
|
10
|
-
import { execFileSync } from "node:child_process";
|
|
11
|
-
import {
|
|
12
|
-
chmodSync,
|
|
13
|
-
closeSync,
|
|
14
|
-
existsSync,
|
|
15
|
-
fsyncSync,
|
|
16
|
-
mkdirSync,
|
|
17
|
-
openSync,
|
|
18
|
-
readFileSync,
|
|
19
|
-
renameSync,
|
|
20
|
-
rmSync,
|
|
21
|
-
writeFileSync
|
|
22
|
-
} from "node:fs";
|
|
23
|
-
import { dirname } from "node:path";
|
|
24
|
-
import { userInfo } from "node:os";
|
|
25
|
-
import { randomBytes } from "node:crypto";
|
|
26
|
-
function tightenPrivateFile(file) {
|
|
27
|
-
try {
|
|
28
|
-
chmodSync(file, 384);
|
|
29
|
-
} catch {
|
|
30
|
-
}
|
|
31
|
-
if (process.platform !== "win32") return;
|
|
32
|
-
try {
|
|
33
|
-
execFileSync("icacls", [file, "/inheritance:r", "/grant:r", `${userInfo().username}:F`], {
|
|
34
|
-
timeout: 5e3,
|
|
35
|
-
windowsHide: true,
|
|
36
|
-
stdio: "ignore"
|
|
37
|
-
});
|
|
38
|
-
} catch {
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
function writePrivateJsonAtomic(file, value) {
|
|
42
|
-
const parent = dirname(file);
|
|
43
|
-
mkdirSync(parent, { recursive: true, mode: 448 });
|
|
44
|
-
const temporary = `${file}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
45
|
-
try {
|
|
46
|
-
writeFileSync(temporary, `${JSON.stringify(value, null, 2)}
|
|
47
|
-
`, {
|
|
48
|
-
encoding: "utf8",
|
|
49
|
-
mode: 384,
|
|
50
|
-
flag: "wx"
|
|
51
|
-
});
|
|
52
|
-
const fd = openSync(temporary, "r+");
|
|
53
|
-
try {
|
|
54
|
-
try {
|
|
55
|
-
fsyncSync(fd);
|
|
56
|
-
} catch {
|
|
57
|
-
}
|
|
58
|
-
} finally {
|
|
59
|
-
closeSync(fd);
|
|
60
|
-
}
|
|
61
|
-
tightenPrivateFile(temporary);
|
|
62
|
-
renameSync(temporary, file);
|
|
63
|
-
tightenPrivateFile(file);
|
|
64
|
-
} finally {
|
|
65
|
-
if (existsSync(temporary)) {
|
|
66
|
-
try {
|
|
67
|
-
rmSync(temporary, { force: true });
|
|
68
|
-
} catch {
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// src/install-runtime.ts
|
|
75
|
-
var INSTALL_PNPM_VERSION = "11.22.0";
|
|
76
|
-
|
|
77
|
-
// src/install-profile.ts
|
|
6
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
7
|
+
import { spawn, execFile } from "node:child_process";
|
|
78
8
|
var PLUGIN_PACKAGE = "@harness-remote/dsh-wechat-remote";
|
|
79
9
|
function safeProfileName(value) {
|
|
80
10
|
return /^[A-Za-z0-9_-]{1,80}$/.test(value);
|
|
81
11
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
12
|
+
function backupProfile(profile, backup) {
|
|
13
|
+
if (fs.existsSync(backup)) throw new Error("\u672C\u6B21\u5B89\u88C5\u5907\u4EFD\u5DF2\u5B58\u5728\uFF0C\u672A\u8986\u76D6\u3002");
|
|
14
|
+
fs.cpSync(profile, backup, {
|
|
15
|
+
recursive: true,
|
|
16
|
+
dereference: false,
|
|
17
|
+
verbatimSymlinks: true,
|
|
18
|
+
mode: fs.constants.COPYFILE_FICLONE,
|
|
19
|
+
filter(source, target) {
|
|
20
|
+
if (!fs.lstatSync(source).isSymbolicLink()) return true;
|
|
21
|
+
const type = process.platform === "win32" ? fs.statSync(source, { throwIfNoEntry: false })?.isDirectory() ? "junction" : "file" : void 0;
|
|
22
|
+
fs.symlinkSync(fs.readlinkSync(source), target, type);
|
|
23
|
+
return false;
|
|
93
24
|
}
|
|
94
|
-
};
|
|
95
|
-
walk(root);
|
|
25
|
+
});
|
|
96
26
|
}
|
|
97
27
|
function installToolPath(directory, runtime) {
|
|
98
28
|
const bin = path.join(directory, "tool-bin");
|
|
99
29
|
fs.mkdirSync(bin, { mode: 448 });
|
|
100
|
-
const runner = path.join(bin, "pnpm-run.cjs");
|
|
101
|
-
fs.writeFileSync(runner, `require('node:child_process').spawnSync(${JSON.stringify(runtime.executable)},[${JSON.stringify(runtime.cli)},...process.argv.slice(2)],{stdio:'inherit',shell:false,windowsHide:true}).status===0?process.exit(0):process.exit(1)
|
|
102
|
-
`, { mode: 384 });
|
|
103
30
|
if (process.platform === "win32") {
|
|
104
|
-
if (/["\r\n]/.test(runtime.executable)) throw new Error("
|
|
105
|
-
fs.writeFileSync(path.join(bin, "pnpm.cmd"),
|
|
106
|
-
"${runtime.executable.replace(/%/g, "%%")}" "%~dp0pnpm-run.cjs" %*\r
|
|
107
|
-
`, { mode: 448 });
|
|
31
|
+
if (/["\r\n]/.test(runtime.executable + runtime.cli)) throw new Error("\u5B89\u88C5\u5DE5\u5177\u8DEF\u5F84\u5305\u542B\u65E0\u6548\u5B57\u7B26\u3002");
|
|
32
|
+
fs.writeFileSync(path.join(bin, "pnpm.cmd"), '@echo off\r\nsetlocal DisableDelayedExpansion\r\n"%HARNESS_INSTALL_NODE%" "%HARNESS_INSTALL_PNPM%" %*\r\n', { mode: 448 });
|
|
108
33
|
} else {
|
|
109
|
-
|
|
110
|
-
fs.writeFileSync(path.join(bin, "pnpm"), `#!/bin/sh
|
|
111
|
-
exec ${quote(runtime.executable)} ${quote(runner)} "$@"
|
|
112
|
-
`, { mode: 448 });
|
|
34
|
+
fs.writeFileSync(path.join(bin, "pnpm"), '#!/bin/sh\nexec "$HARNESS_INSTALL_NODE" "$HARNESS_INSTALL_PNPM" "$@"\n', { mode: 448 });
|
|
113
35
|
}
|
|
114
36
|
return bin;
|
|
115
37
|
}
|
|
116
|
-
|
|
117
|
-
|
|
38
|
+
var NativeInstallError = class extends Error {
|
|
39
|
+
constructor(message, mayStillBeRunning = false) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.mayStillBeRunning = mayStillBeRunning;
|
|
42
|
+
this.name = "NativeInstallError";
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
function runNativePlugin(cli, profile, home, toolPath, runtime, logFile, archiveName, timeoutMs = 6e5, operation = "add") {
|
|
46
|
+
if (!safeProfileName(profile) || !/^harness-remote-[\w.+-]+\.tgz$/.test(archiveName)) throw new Error("\u65E0\u6548\u7684\u5B89\u88C5\u76EE\u6807\u3002");
|
|
118
47
|
return new Promise((resolve, reject) => {
|
|
119
48
|
const log = fs.openSync(logFile, "a", 384);
|
|
49
|
+
const env = { ...process.env };
|
|
50
|
+
const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path");
|
|
51
|
+
const inheritedPath = pathKey ? env[pathKey] : "";
|
|
52
|
+
if (process.platform === "win32") {
|
|
53
|
+
for (const key of Object.keys(env)) if (key.toLowerCase() === "path") delete env[key];
|
|
54
|
+
}
|
|
55
|
+
Object.assign(env, {
|
|
56
|
+
DSH_HOME: home,
|
|
57
|
+
PATH: toolPath + path.delimiter + (inheritedPath || ""),
|
|
58
|
+
HARNESS_INSTALL_NODE: runtime.executable,
|
|
59
|
+
HARNESS_INSTALL_PNPM: runtime.cli,
|
|
60
|
+
CI: "true",
|
|
61
|
+
COREPACK_ENABLE_AUTO_PIN: "0",
|
|
62
|
+
npm_config_manage_package_manager_versions: "false"
|
|
63
|
+
});
|
|
120
64
|
const child = spawn(runtime.executable, [
|
|
121
65
|
cli,
|
|
122
66
|
"plugin",
|
|
123
67
|
"--profile",
|
|
124
68
|
profile,
|
|
125
|
-
"add",
|
|
126
|
-
"file:harness-remote-update.tgz",
|
|
69
|
+
...operation === "install" ? ["install"] : ["add", `file:${archiveName}`],
|
|
127
70
|
"--ignore-scripts",
|
|
128
71
|
"--config.frozen-lockfile=false",
|
|
129
72
|
"--prefer-offline",
|
|
@@ -133,78 +76,89 @@ function runNativePlugin(cli, profile, home, toolPath, runtime, logFile) {
|
|
|
133
76
|
cwd: home,
|
|
134
77
|
shell: false,
|
|
135
78
|
windowsHide: true,
|
|
79
|
+
detached: process.platform !== "win32",
|
|
136
80
|
stdio: ["ignore", log, log],
|
|
137
|
-
env
|
|
138
|
-
...process.env,
|
|
139
|
-
DSH_HOME: home,
|
|
140
|
-
PATH: toolPath + path.delimiter + (process.env.PATH || ""),
|
|
141
|
-
CI: "true",
|
|
142
|
-
COREPACK_ENABLE_AUTO_PIN: "0",
|
|
143
|
-
npm_config_manage_package_manager_versions: "false"
|
|
144
|
-
}
|
|
81
|
+
env
|
|
145
82
|
});
|
|
146
83
|
fs.closeSync(log);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
84
|
+
let finished = false, terminating = false, closed = false, terminationTimer;
|
|
85
|
+
const fail = (message, uncertain = false) => finish(new NativeInstallError(`${message} \u5B89\u88C5\u65E5\u5FD7\uFF1A${logFile}`, uncertain));
|
|
86
|
+
const finish = (error) => {
|
|
87
|
+
if (finished) return;
|
|
88
|
+
finished = true;
|
|
152
89
|
clearTimeout(timer);
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
90
|
+
clearTimeout(terminationTimer);
|
|
91
|
+
error ? reject(error) : resolve();
|
|
92
|
+
};
|
|
93
|
+
const timer = setTimeout(() => {
|
|
94
|
+
if (closed) return;
|
|
95
|
+
terminating = true;
|
|
96
|
+
terminationTimer = setTimeout(() => fail("\u5B89\u88C5\u8D85\u65F6\uFF0C\u5C1A\u4E0D\u80FD\u786E\u8BA4\u5B89\u88C5\u8FDB\u7A0B\u5DF2\u9000\u51FA\uFF1B\u672A\u81EA\u52A8\u56DE\u9000\uFF0C\u8BF7\u52FF\u91CD\u590D\u5B89\u88C5\u3002", true), 15e3);
|
|
97
|
+
if (process.platform === "win32") {
|
|
98
|
+
if (!child.pid) return fail("\u5B89\u88C5\u7A0B\u5E8F\u672A\u542F\u52A8\u3002");
|
|
99
|
+
execFile(
|
|
100
|
+
path.join(process.env.SystemRoot || "C:\\Windows", "System32", "taskkill.exe"),
|
|
101
|
+
["/PID", String(child.pid), "/T", "/F"],
|
|
102
|
+
{ windowsHide: true, timeout: 1e4 },
|
|
103
|
+
(error) => {
|
|
104
|
+
if (error) fail("\u5B89\u88C5\u8D85\u65F6\uFF0C\u65E0\u6CD5\u786E\u8BA4\u5B89\u88C5\u8FDB\u7A0B\u6811\u5DF2\u9000\u51FA\uFF1B\u672A\u81EA\u52A8\u56DE\u9000\uFF0C\u8BF7\u52FF\u91CD\u590D\u5B89\u88C5\u3002", true);
|
|
105
|
+
else if (closed) fail("\u4E0B\u8F7D\u6216\u5B89\u88C5\u8D85\u65F6\uFF0C\u5B89\u88C5\u8FDB\u7A0B\u5DF2\u505C\u6B62\u3002");
|
|
106
|
+
else child.once("close", () => fail("\u4E0B\u8F7D\u6216\u5B89\u88C5\u8D85\u65F6\uFF0C\u5B89\u88C5\u8FDB\u7A0B\u5DF2\u505C\u6B62\u3002"));
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
} else {
|
|
110
|
+
try {
|
|
111
|
+
if (child.pid) process.kill(-child.pid, "SIGKILL");
|
|
112
|
+
} catch (error) {
|
|
113
|
+
if (error.code !== "ESRCH") return fail("\u65E0\u6CD5\u505C\u6B62\u8D85\u65F6\u7684\u5B89\u88C5\u8FDB\u7A0B\uFF1B\u672A\u81EA\u52A8\u56DE\u9000\u3002", true);
|
|
114
|
+
}
|
|
115
|
+
if (closed) fail("\u4E0B\u8F7D\u6216\u5B89\u88C5\u8D85\u65F6\uFF0C\u5B89\u88C5\u8FDB\u7A0B\u5DF2\u505C\u6B62\u3002");
|
|
116
|
+
else child.once("close", () => fail("\u4E0B\u8F7D\u6216\u5B89\u88C5\u8D85\u65F6\uFF0C\u5B89\u88C5\u8FDB\u7A0B\u5DF2\u505C\u6B62\u3002"));
|
|
117
|
+
}
|
|
118
|
+
}, timeoutMs);
|
|
119
|
+
child.once("error", (error) => fail(`\u65E0\u6CD5\u542F\u52A8 DSH \u539F\u751F\u5B89\u88C5\u7A0B\u5E8F\uFF08${error.code || error.name}\uFF09\u3002`));
|
|
120
|
+
child.once("close", (code, signal) => {
|
|
121
|
+
closed = true;
|
|
122
|
+
if (terminating) return;
|
|
123
|
+
if (code === 0) finish();
|
|
124
|
+
else fail(`DSH \u539F\u751F\u5B89\u88C5\u672A\u5B8C\u6210\uFF08${signal ? `\u4FE1\u53F7 ${signal}` : `\u9000\u51FA\u7801 ${code}`}\uFF09\u3002`);
|
|
158
125
|
});
|
|
159
126
|
});
|
|
160
127
|
}
|
|
161
|
-
async function
|
|
162
|
-
const scope = path.basename(job.profile);
|
|
163
|
-
if (!safeProfileName(scope) ||
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
filter: (p) => !["node_modules", ".harness-remote-update.lock"].includes(path.basename(p))
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
let before = null;
|
|
175
|
-
const filename = path.join(staged, "package.json");
|
|
176
|
-
if (fs.existsSync(filename)) {
|
|
177
|
-
before = JSON.parse(fs.readFileSync(filename, "utf8"));
|
|
178
|
-
for (const [name, spec] of Object.entries(before.dependencies || {})) {
|
|
179
|
-
if (name !== PLUGIN_PACKAGE && !/^[~^]?\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(String(spec))) throw new Error("\u5176\u4ED6\u63D2\u4EF6\u4F7F\u7528\u4E86\u672C\u5730\u94FE\u63A5\u6216\u7279\u6B8A\u6765\u6E90\uFF0C\u672A\u4FEE\u6539\u5F53\u524D\u5B89\u88C5\u3002");
|
|
180
|
-
}
|
|
181
|
-
for (const e of fs.readdirSync(staged, { withFileTypes: true })) if (e.isSymbolicLink()) throw new Error("profile \u914D\u7F6E\u5305\u542B\u94FE\u63A5\uFF0C\u672A\u4FEE\u6539\u5F53\u524D\u5B89\u88C5\u3002");
|
|
182
|
-
if (before.packageManager && !/^pnpm@\d+\.\d+\.\d+(?:\+.*)?$/.test(before.packageManager)) throw new Error("\u5F53\u524D profile \u4F7F\u7528\u4E86\u5176\u4ED6\u5305\u7BA1\u7406\u5668\uFF0C\u672A\u4FEE\u6539\u5B89\u88C5\u3002");
|
|
183
|
-
writePrivateJsonAtomic(filename, { ...before, dependencies: {
|
|
184
|
-
...before.dependencies,
|
|
185
|
-
[PLUGIN_PACKAGE]: "file:harness-remote-update.tgz"
|
|
186
|
-
}, packageManager: `pnpm@${INSTALL_PNPM_VERSION}` });
|
|
187
|
-
}
|
|
188
|
-
fs.copyFileSync(path.join(job.directory, "release.tgz"), path.join(staged, "harness-remote-update.tgz"));
|
|
128
|
+
async function installProfile(job) {
|
|
129
|
+
const scope = path.basename(job.profile), home = path.dirname(path.dirname(job.profile));
|
|
130
|
+
if (!safeProfileName(scope) || path.dirname(job.profile) !== path.join(home, "profiles") || !/^[\w.+-]{1,80}$/.test(job.targetVersion)) throw new Error("\u5B89\u88C5\u76EE\u6807\u4E0D\u660E\u786E\u3002");
|
|
131
|
+
fs.mkdirSync(job.profile, { recursive: true, mode: 448 });
|
|
132
|
+
const archive = path.join(job.directory, "release.tgz");
|
|
133
|
+
const digest = createHash("sha256").update(fs.readFileSync(archive)).digest("hex");
|
|
134
|
+
const archiveBase = `harness-remote-${job.targetVersion}-${digest}`;
|
|
135
|
+
const suffix = fs.existsSync(path.join(job.profile, `${archiveBase}.tgz`)) ? `-${randomBytes(8).toString("hex")}` : "";
|
|
136
|
+
const archiveName = `${archiveBase}${suffix}.tgz`;
|
|
137
|
+
fs.copyFileSync(archive, path.join(job.profile, archiveName), fs.constants.COPYFILE_EXCL);
|
|
189
138
|
const tools = installToolPath(job.directory, job.runtime);
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
const
|
|
193
|
-
|
|
139
|
+
const logFile = path.join(job.directory, "install.log");
|
|
140
|
+
const deadline = Date.now() + 6e5;
|
|
141
|
+
const run = (operation = "add") => runNativePlugin(job.cli, scope, home, tools, job.runtime, logFile, archiveName, Math.max(1, deadline - Date.now()), operation);
|
|
142
|
+
try {
|
|
143
|
+
await run();
|
|
144
|
+
} catch (error) {
|
|
145
|
+
const layoutError = /^\s*(?:\[ERR_PNPM_|ERR_PNPM_)(?:UNEXPECTED_VIRTUAL_STORE|UNEXPECTED_STORE|MODULES_BREAKING_CHANGE|VIRTUAL_STORE_DIR_MAX_LENGTH_DIFF|PUBLIC_HOIST_PATTERN_DIFF|HOIST_PATTERN_DIFF)(?:\]|\s)/m;
|
|
146
|
+
if (!(error instanceof NativeInstallError) || error.mayStillBeRunning || !layoutError.test(fs.readFileSync(logFile, "utf8"))) throw error;
|
|
147
|
+
fs.appendFileSync(logFile, "\nRestoring native pnpm layout with dsh plugin install.\n");
|
|
148
|
+
await run("install");
|
|
149
|
+
await run();
|
|
150
|
+
}
|
|
151
|
+
const installed = path.join(job.profile, "node_modules", PLUGIN_PACKAGE);
|
|
194
152
|
if (JSON.parse(fs.readFileSync(path.join(installed, "package.json"), "utf8")).version !== job.targetVersion) throw new Error("\u5B89\u88C5\u540E\u63D2\u4EF6\u7248\u672C\u4E0D\u5339\u914D\u3002");
|
|
195
|
-
const after = JSON.parse(fs.readFileSync(
|
|
153
|
+
const after = JSON.parse(fs.readFileSync(path.join(job.profile, "package.json"), "utf8"));
|
|
196
154
|
if (!after.dsh?.profile?.bundles?.includes(PLUGIN_PACKAGE)) throw new Error("DSH \u5C1A\u672A\u5C06\u63D2\u4EF6\u6CE8\u518C\u4E3A\u539F\u751F profile \u5C42\u3002");
|
|
197
|
-
for (const name of Object.keys(before?.dependencies || {})) if (name !== PLUGIN_PACKAGE) {
|
|
198
|
-
if (hash(path.join(job.profile, "node_modules", name, "package.json")) !== hash(path.join(staged, "node_modules", name, "package.json"))) throw new Error("\u5B89\u88C5\u8BD5\u56FE\u6539\u53D8\u5176\u4ED6\u63D2\u4EF6\uFF0C\u539F\u5B89\u88C5\u4FDD\u6301\u4E0D\u53D8\u3002");
|
|
199
|
-
}
|
|
200
|
-
assertRelocatableProfile(staged);
|
|
201
|
-
return staged;
|
|
202
155
|
}
|
|
203
156
|
export {
|
|
157
|
+
NativeInstallError,
|
|
204
158
|
PLUGIN_PACKAGE,
|
|
205
|
-
|
|
159
|
+
backupProfile,
|
|
160
|
+
installProfile,
|
|
206
161
|
installToolPath,
|
|
207
162
|
runNativePlugin,
|
|
208
|
-
safeProfileName
|
|
209
|
-
stageProfile
|
|
163
|
+
safeProfileName
|
|
210
164
|
};
|
package/lib/install-runtime.js
CHANGED
|
@@ -6,6 +6,22 @@ import path from "node:path";
|
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { spawn } from "node:child_process";
|
|
8
8
|
var INSTALL_PNPM_VERSION = "11.22.0";
|
|
9
|
+
async function pinInstallRuntime(runtime, directory) {
|
|
10
|
+
let root = path.dirname(runtime.cli);
|
|
11
|
+
while (!fs.existsSync(path.join(root, "package.json"))) {
|
|
12
|
+
const parent = path.dirname(root);
|
|
13
|
+
if (parent === root) throw new Error("\u65E0\u6CD5\u5B9A\u4F4D\u5B89\u88C5\u5DE5\u5177\u5305\u3002");
|
|
14
|
+
root = parent;
|
|
15
|
+
}
|
|
16
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
|
|
17
|
+
if (manifest.name !== "pnpm" || manifest.version !== runtime.version) throw new Error("\u5B89\u88C5\u5DE5\u5177\u7248\u672C\u4E0D\u4E00\u81F4\u3002");
|
|
18
|
+
const target = path.join(directory, "install-runtime");
|
|
19
|
+
if (fs.existsSync(target)) throw new Error("\u672C\u6B21\u5B89\u88C5\u5DE5\u5177\u76EE\u5F55\u5DF2\u5B58\u5728\u3002");
|
|
20
|
+
fs.cpSync(root, target, { recursive: true, dereference: false, verbatimSymlinks: true, mode: fs.constants.COPYFILE_FICLONE });
|
|
21
|
+
const pinned = { ...runtime, cli: path.join(target, path.relative(root, runtime.cli)) };
|
|
22
|
+
await verifyInstallRuntime(pinned);
|
|
23
|
+
return pinned;
|
|
24
|
+
}
|
|
9
25
|
function resolveInstallRuntime(owner, executable = process.execPath, nodeVersion = process.versions.node) {
|
|
10
26
|
const [major, minor] = nodeVersion.split(".").map(Number);
|
|
11
27
|
if (!(major > 22 || major === 22 && minor >= 13)) throw new Error("\u5F53\u524D Node.js \u7248\u672C\u4E0D\u6EE1\u8DB3\u5B89\u88C5\u8981\u6C42\uFF0822.13 \u6216\u66F4\u9AD8\uFF09\uFF0C\u672A\u4FEE\u6539\u63D2\u4EF6\u3002");
|
|
@@ -59,6 +75,7 @@ function verifyInstallRuntime(runtime) {
|
|
|
59
75
|
}
|
|
60
76
|
export {
|
|
61
77
|
INSTALL_PNPM_VERSION,
|
|
78
|
+
pinInstallRuntime,
|
|
62
79
|
resolveInstallRuntime,
|
|
63
80
|
verifyInstallRuntime
|
|
64
81
|
};
|