@workrail/cli 0.5.5 → 0.5.7
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/workrail.js +138 -12
- package/package.json +1 -1
package/bin/workrail.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require("node:fs");
|
|
4
4
|
const path = require("node:path");
|
|
5
|
+
const https = require("node:https");
|
|
6
|
+
const crypto = require("node:crypto");
|
|
5
7
|
const { spawn } = require("node:child_process");
|
|
6
8
|
|
|
7
9
|
function resolveBinaryName() {
|
|
@@ -25,20 +27,144 @@ if (!binName) {
|
|
|
25
27
|
|
|
26
28
|
const binPath = path.join(__dirname, "native", binName);
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
function getPackageVersion() {
|
|
31
|
+
const pkgPath = path.join(__dirname, "..", "package.json");
|
|
32
|
+
try {
|
|
33
|
+
const raw = fs.readFileSync(pkgPath, "utf8");
|
|
34
|
+
const parsed = JSON.parse(raw);
|
|
35
|
+
if (typeof parsed.version === "string" && parsed.version.trim()) {
|
|
36
|
+
return parsed.version.trim();
|
|
37
|
+
}
|
|
38
|
+
} catch {}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function sha256File(filePath) {
|
|
43
|
+
const hash = crypto.createHash("sha256");
|
|
44
|
+
hash.update(fs.readFileSync(filePath));
|
|
45
|
+
return hash.digest("hex");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function parseChecksums(text) {
|
|
49
|
+
const map = new Map();
|
|
50
|
+
for (const line of text.split("\n")) {
|
|
51
|
+
const trimmed = line.trim();
|
|
52
|
+
if (!trimmed) continue;
|
|
53
|
+
const parts = trimmed.split(/\s+/);
|
|
54
|
+
if (parts.length < 2) continue;
|
|
55
|
+
map.set(parts[parts.length - 1], parts[0]);
|
|
56
|
+
}
|
|
57
|
+
return map;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function download(url) {
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
https
|
|
63
|
+
.get(url, (res) => {
|
|
64
|
+
if (
|
|
65
|
+
res.statusCode &&
|
|
66
|
+
res.statusCode >= 300 &&
|
|
67
|
+
res.statusCode < 400 &&
|
|
68
|
+
typeof res.headers.location === "string"
|
|
69
|
+
) {
|
|
70
|
+
resolve(download(new URL(res.headers.location, url).toString()));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (res.statusCode !== 200) {
|
|
74
|
+
reject(new Error(`Download failed (${res.statusCode}) for ${url}`));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const chunks = [];
|
|
78
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
79
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
80
|
+
})
|
|
81
|
+
.on("error", (err) => reject(err));
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function ensureBinaryInstalled(binaryPath, binaryName) {
|
|
86
|
+
if (fs.existsSync(binaryPath)) return;
|
|
87
|
+
|
|
88
|
+
const version = getPackageVersion();
|
|
89
|
+
if (!version) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
"Unable to resolve @workrail/cli version for binary download",
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const baseUrl =
|
|
96
|
+
process.env.WORKRAIL_BINARY_BASE_URL ||
|
|
97
|
+
`https://cli.workrail.dev/workrail/v${version}`;
|
|
98
|
+
const binUrl = `${baseUrl}/${binaryName}`;
|
|
99
|
+
const checksumsUrl = `${baseUrl}/checksums.txt`;
|
|
100
|
+
|
|
101
|
+
fs.mkdirSync(path.dirname(binaryPath), { recursive: true });
|
|
102
|
+
console.error(
|
|
103
|
+
`[workrail] Native binary missing, downloading ${binaryName}...`,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const binaryBytes = await download(binUrl);
|
|
107
|
+
fs.writeFileSync(binaryPath, binaryBytes);
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const checksumsText = (await download(checksumsUrl)).toString("utf8");
|
|
111
|
+
const checksums = parseChecksums(checksumsText);
|
|
112
|
+
const expected = checksums.get(binaryName);
|
|
113
|
+
if (!expected) {
|
|
114
|
+
throw new Error(`No checksum entry found for ${binaryName}`);
|
|
115
|
+
}
|
|
116
|
+
const actual = sha256File(binaryPath);
|
|
117
|
+
if (actual !== expected) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Checksum mismatch for ${binaryName}. expected=${expected} actual=${actual}`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
if (process.platform !== "win32") {
|
|
123
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
try {
|
|
127
|
+
fs.unlinkSync(binaryPath);
|
|
128
|
+
} catch {}
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function printInstallHelp() {
|
|
134
|
+
console.error("Workrail binary is not installed.");
|
|
135
|
+
console.error("Try reinstalling with one of:");
|
|
30
136
|
console.error(" npm i -g @workrail/cli");
|
|
31
|
-
|
|
137
|
+
console.error(" pnpm add -g @workrail/cli");
|
|
138
|
+
console.error(" bun add -g @workrail/cli");
|
|
32
139
|
}
|
|
33
140
|
|
|
34
|
-
|
|
141
|
+
async function main() {
|
|
142
|
+
try {
|
|
143
|
+
await ensureBinaryInstalled(binPath, binName);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error(
|
|
146
|
+
`[workrail] Failed to install native binary: ${error instanceof Error ? error.message : String(error)}`,
|
|
147
|
+
);
|
|
148
|
+
printInstallHelp();
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
35
151
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
152
|
+
if (!fs.existsSync(binPath)) {
|
|
153
|
+
printInstallHelp();
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const child = spawn(binPath, process.argv.slice(2), { stdio: "inherit" });
|
|
158
|
+
|
|
159
|
+
child.on("error", (err) => {
|
|
160
|
+
console.error(`Failed to run Workrail binary: ${err.message}`);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
child.on("exit", (code, signal) => {
|
|
165
|
+
if (signal) process.exit(1);
|
|
166
|
+
process.exit(code ?? 1);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
40
169
|
|
|
41
|
-
|
|
42
|
-
if (signal) process.exit(1);
|
|
43
|
-
process.exit(code ?? 1);
|
|
44
|
-
});
|
|
170
|
+
main();
|