endform 0.48.0 → 0.48.2
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/bin/endform +88 -38
- package/package.json +5 -5
package/bin/endform
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
const child_process = require("node:child_process");
|
|
10
10
|
const path = require("node:path");
|
|
11
11
|
const fs = require("node:fs");
|
|
12
|
-
const
|
|
12
|
+
const { pipeline } = require("node:stream/promises");
|
|
13
13
|
|
|
14
14
|
// Define supported platforms and architectures.
|
|
15
15
|
const supportedPlatforms = ["darwin", "linux"];
|
|
@@ -72,48 +72,93 @@ const getDownloadInfo = () => {
|
|
|
72
72
|
};
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
const downloadBinary = () => {
|
|
75
|
+
const downloadBinary = async ({ force } = {}) => {
|
|
77
76
|
const { url, binaryName } = getDownloadInfo();
|
|
78
77
|
const currentDir = __dirname;
|
|
79
78
|
const binaryPath = path.join(currentDir, binaryName);
|
|
80
79
|
|
|
80
|
+
// Fast path: binary already present.
|
|
81
|
+
if (!force && fs.existsSync(binaryPath)) return binaryPath;
|
|
82
|
+
|
|
81
83
|
console.log(
|
|
82
84
|
"Endform was not installed as an optional dependency, preparing on the fly...",
|
|
83
85
|
);
|
|
84
86
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
87
|
+
const tmpPath = path.join(
|
|
88
|
+
currentDir,
|
|
89
|
+
`${binaryName}.${process.pid}.${Date.now()}.tmp`,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const response = await fetch(url);
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Failed to download binary: ${response.status} ${response.statusText}`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!response.body) {
|
|
100
|
+
throw new Error("Failed to download binary: empty response body");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const file = fs.createWriteStream(tmpPath, { mode: 0o755 });
|
|
104
|
+
try {
|
|
105
|
+
await pipeline(response.body, file);
|
|
106
|
+
} finally {
|
|
107
|
+
// `pipeline` will close the stream on success/errors, but be defensive.
|
|
108
|
+
try {
|
|
109
|
+
file.close();
|
|
110
|
+
} catch {}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
fs.renameSync(tmpPath, binaryPath);
|
|
115
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
116
|
+
return binaryPath;
|
|
117
|
+
} catch (err) {
|
|
118
|
+
fs.unlink(tmpPath, () => {});
|
|
119
|
+
throw err;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
124
|
+
|
|
125
|
+
const isTextFileBusyError = (err) => {
|
|
126
|
+
if (!err) return false;
|
|
127
|
+
if (err.code === "ETXTBSY") return true;
|
|
128
|
+
|
|
129
|
+
// On some platforms Node may surface a numeric errno.
|
|
130
|
+
if (typeof err.errno === "number" && err.errno === -26) return true;
|
|
131
|
+
if (typeof err.message === "string" && err.message.includes("ETXTBSY")) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return false;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const execFileSyncWithRetry = async (binaryPath, args, options) => {
|
|
139
|
+
const maxAttempts = 5;
|
|
140
|
+
let delayMs = 50;
|
|
141
|
+
|
|
142
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
143
|
+
try {
|
|
144
|
+
child_process.execFileSync(binaryPath, args, options);
|
|
145
|
+
return;
|
|
146
|
+
} catch (err) {
|
|
147
|
+
const shouldRetry = isTextFileBusyError(err) && attempt < maxAttempts;
|
|
148
|
+
if (!shouldRetry) throw err;
|
|
149
|
+
|
|
150
|
+
console.error(
|
|
151
|
+
`Endform binary was busy (ETXTBSY). Re-downloading and retrying (attempt ${attempt}/${maxAttempts})...`,
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
await downloadBinary({ force: true });
|
|
156
|
+
} catch {}
|
|
157
|
+
|
|
158
|
+
await sleep(delayMs);
|
|
159
|
+
delayMs *= 2;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
117
162
|
};
|
|
118
163
|
|
|
119
164
|
// Main execution function
|
|
@@ -129,11 +174,11 @@ const main = async () => {
|
|
|
129
174
|
// If not found locally, try to resolve from installed optional dependency
|
|
130
175
|
try {
|
|
131
176
|
binaryPath = require.resolve(`${packageName}/${binaryRelativePath}`);
|
|
132
|
-
} catch (
|
|
177
|
+
} catch (_err) {
|
|
133
178
|
// If still not found, download the binary
|
|
134
179
|
try {
|
|
135
180
|
binaryPath = await downloadBinary();
|
|
136
|
-
} catch (
|
|
181
|
+
} catch (_err) {
|
|
137
182
|
console.error(
|
|
138
183
|
`Error: Could not download the Endform binary for ${platform} (${arch}).`,
|
|
139
184
|
);
|
|
@@ -144,10 +189,15 @@ const main = async () => {
|
|
|
144
189
|
|
|
145
190
|
// Execute the binary and forward any command-line arguments.
|
|
146
191
|
try {
|
|
147
|
-
|
|
192
|
+
await execFileSyncWithRetry(binaryPath, process.argv.slice(2), {
|
|
148
193
|
stdio: "inherit",
|
|
149
194
|
});
|
|
150
195
|
} catch (err) {
|
|
196
|
+
// err.code is a string (e.g., "ENOENT") when the binary failed to execute,
|
|
197
|
+
// otherwise it's typically undefined (the CLI already printed its own error)
|
|
198
|
+
if (err.message && typeof err.code === "string") {
|
|
199
|
+
console.error(err.message);
|
|
200
|
+
}
|
|
151
201
|
process.exit(err.status || 1);
|
|
152
202
|
}
|
|
153
203
|
} catch (err) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "endform",
|
|
3
|
-
"version": "0.48.
|
|
3
|
+
"version": "0.48.2",
|
|
4
4
|
"description": "Endform CLI",
|
|
5
5
|
"repository": "https://github.com/endformdev/npm",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
"bin"
|
|
13
13
|
],
|
|
14
14
|
"optionalDependencies": {
|
|
15
|
-
"endform-darwin-arm64": "0.48.
|
|
16
|
-
"endform-darwin-x86": "0.48.
|
|
17
|
-
"endform-linux-arm64": "0.48.
|
|
18
|
-
"endform-linux-x86": "0.48.
|
|
15
|
+
"endform-darwin-arm64": "0.48.2",
|
|
16
|
+
"endform-darwin-x86": "0.48.2",
|
|
17
|
+
"endform-linux-arm64": "0.48.2",
|
|
18
|
+
"endform-linux-x86": "0.48.2"
|
|
19
19
|
}
|
|
20
20
|
}
|