@clovapi/cli 0.1.23 → 0.1.26
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/package.json +2 -1
- package/scripts/install.js +6 -3
- package/scripts/win-replace.js +128 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clovapi/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "Install clovapi CLI from GitHub Releases",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"bin",
|
|
20
20
|
"scripts/install.js",
|
|
21
21
|
"scripts/paths.js",
|
|
22
|
+
"scripts/win-replace.js",
|
|
22
23
|
"vendor",
|
|
23
24
|
"README.md"
|
|
24
25
|
],
|
package/scripts/install.js
CHANGED
|
@@ -15,6 +15,7 @@ const {
|
|
|
15
15
|
exeName,
|
|
16
16
|
vendorBinPath,
|
|
17
17
|
} = require("./paths");
|
|
18
|
+
const { installBinaryWindows } = require("./win-replace");
|
|
18
19
|
|
|
19
20
|
const PLATFORM_MAP = {
|
|
20
21
|
darwin: "darwin",
|
|
@@ -155,12 +156,14 @@ async function withInstallLock(fn) {
|
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
function installBinary(sourcePath, targetPath) {
|
|
159
|
+
if (process.platform === "win32") {
|
|
160
|
+
installBinaryWindows(sourcePath, targetPath);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
158
163
|
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
159
164
|
const tmpPath = path.join(path.dirname(targetPath), `.clovapi-install-${process.pid}-${Date.now()}`);
|
|
160
165
|
fs.copyFileSync(sourcePath, tmpPath);
|
|
161
|
-
|
|
162
|
-
fs.chmodSync(tmpPath, 0o755);
|
|
163
|
-
}
|
|
166
|
+
fs.chmodSync(tmpPath, 0o755);
|
|
164
167
|
try {
|
|
165
168
|
fs.renameSync(tmpPath, targetPath);
|
|
166
169
|
} catch {
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const { spawnSync } = require("node:child_process");
|
|
2
|
+
const fs = require("node:fs");
|
|
3
|
+
const path = require("node:path");
|
|
4
|
+
|
|
5
|
+
function sleepSync(ms) {
|
|
6
|
+
const deadline = Date.now() + ms;
|
|
7
|
+
while (Date.now() < deadline) {
|
|
8
|
+
/* spin */
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function stopProxy(cliPath) {
|
|
13
|
+
const target = String(cliPath || "").trim();
|
|
14
|
+
if (!target || !fs.existsSync(target)) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
spawnSync(target, ["proxy", "stop"], {
|
|
19
|
+
stdio: "ignore",
|
|
20
|
+
windowsHide: true,
|
|
21
|
+
timeout: 15000,
|
|
22
|
+
});
|
|
23
|
+
} catch {
|
|
24
|
+
/* best effort */
|
|
25
|
+
}
|
|
26
|
+
sleepSync(400);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function removeIfExists(filePath) {
|
|
30
|
+
try {
|
|
31
|
+
fs.rmSync(filePath, { force: true });
|
|
32
|
+
return true;
|
|
33
|
+
} catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function runDeferredWindowsReplace(targetPath, pendingPath, cliPath) {
|
|
39
|
+
const script = [
|
|
40
|
+
"$ErrorActionPreference = 'Continue'",
|
|
41
|
+
`$target = ${JSON.stringify(targetPath)}`,
|
|
42
|
+
`$pending = ${JSON.stringify(pendingPath)}`,
|
|
43
|
+
`$cli = ${JSON.stringify(cliPath || targetPath)}`,
|
|
44
|
+
"for ($i = 0; $i -lt 40; $i++) {",
|
|
45
|
+
" try {",
|
|
46
|
+
" if (Test-Path $cli) { & $cli proxy stop 2>$null | Out-Null }",
|
|
47
|
+
" Start-Sleep -Milliseconds 300",
|
|
48
|
+
" if (Test-Path $target) { Remove-Item -LiteralPath $target -Force -ErrorAction Stop }",
|
|
49
|
+
" Move-Item -LiteralPath $pending -Destination $target -Force -ErrorAction Stop",
|
|
50
|
+
" Remove-Item -LiteralPath ($target + '.old') -Force -ErrorAction SilentlyContinue",
|
|
51
|
+
" exit 0",
|
|
52
|
+
" } catch {",
|
|
53
|
+
" Start-Sleep -Milliseconds 500",
|
|
54
|
+
" }",
|
|
55
|
+
"}",
|
|
56
|
+
"exit 1",
|
|
57
|
+
].join("\n");
|
|
58
|
+
|
|
59
|
+
const result = spawnSync(
|
|
60
|
+
"powershell.exe",
|
|
61
|
+
["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", script],
|
|
62
|
+
{
|
|
63
|
+
windowsHide: true,
|
|
64
|
+
timeout: 60000,
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
return (
|
|
68
|
+
result.status === 0 &&
|
|
69
|
+
fs.existsSync(targetPath) &&
|
|
70
|
+
!fs.existsSync(pendingPath)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function installBinaryWindows(sourcePath, targetPath) {
|
|
75
|
+
const target = path.resolve(String(targetPath || "").trim());
|
|
76
|
+
const source = path.resolve(String(sourcePath || "").trim());
|
|
77
|
+
if (!target || !source || !fs.existsSync(source)) {
|
|
78
|
+
throw new Error("install paths are invalid");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
stopProxy(target);
|
|
82
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
83
|
+
|
|
84
|
+
const tmpPath = path.join(
|
|
85
|
+
path.dirname(target),
|
|
86
|
+
`.clovapi-install-${process.pid}-${Date.now()}`
|
|
87
|
+
);
|
|
88
|
+
fs.copyFileSync(source, tmpPath);
|
|
89
|
+
|
|
90
|
+
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
91
|
+
try {
|
|
92
|
+
if (fs.existsSync(target)) {
|
|
93
|
+
removeIfExists(target);
|
|
94
|
+
if (fs.existsSync(target)) {
|
|
95
|
+
try {
|
|
96
|
+
fs.renameSync(target, `${target}.old`);
|
|
97
|
+
} catch {
|
|
98
|
+
/* still locked */
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
fs.renameSync(tmpPath, target);
|
|
103
|
+
removeIfExists(`${target}.old`);
|
|
104
|
+
return;
|
|
105
|
+
} catch {
|
|
106
|
+
stopProxy(target);
|
|
107
|
+
sleepSync(300 * (attempt + 1));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
removeIfExists(tmpPath);
|
|
112
|
+
const pendingPath = `${target}.new`;
|
|
113
|
+
fs.copyFileSync(source, pendingPath);
|
|
114
|
+
if (runDeferredWindowsReplace(target, pendingPath, target)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
removeIfExists(pendingPath);
|
|
119
|
+
throw new Error(
|
|
120
|
+
`EPERM: operation not permitted, replace '${target}'. Stop the clovapi proxy and retry.`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = {
|
|
125
|
+
installBinaryWindows,
|
|
126
|
+
runDeferredWindowsReplace,
|
|
127
|
+
stopProxy,
|
|
128
|
+
};
|