|
4c4aa94…
|
lmata
|
1 |
#!/usr/bin/env node |
|
4c4aa94…
|
lmata
|
2 |
/** |
|
4c4aa94…
|
lmata
|
3 |
* scuttlectl npm wrapper. |
|
4c4aa94…
|
lmata
|
4 |
* Downloads the appropriate scuttlectl binary for the current platform |
|
4c4aa94…
|
lmata
|
5 |
* and executes it, passing all arguments through. |
|
4c4aa94…
|
lmata
|
6 |
*/ |
|
4c4aa94…
|
lmata
|
7 |
"use strict"; |
|
4c4aa94…
|
lmata
|
8 |
|
|
4c4aa94…
|
lmata
|
9 |
const { execFileSync } = require("child_process"); |
|
4c4aa94…
|
lmata
|
10 |
const { createWriteStream, existsSync, mkdirSync, chmodSync } = require("fs"); |
|
4c4aa94…
|
lmata
|
11 |
const { get } = require("https"); |
|
4c4aa94…
|
lmata
|
12 |
const { join } = require("path"); |
|
4c4aa94…
|
lmata
|
13 |
const { createGunzip } = require("zlib"); |
|
4c4aa94…
|
lmata
|
14 |
const { Extract } = require("tar"); |
|
4c4aa94…
|
lmata
|
15 |
|
|
4c4aa94…
|
lmata
|
16 |
const REPO = "ConflictHQ/scuttlebot"; |
|
4c4aa94…
|
lmata
|
17 |
const BIN_DIR = join(__dirname, "..", "dist"); |
|
4c4aa94…
|
lmata
|
18 |
const BIN_PATH = join(BIN_DIR, process.platform === "win32" ? "scuttlectl.exe" : "scuttlectl"); |
|
4c4aa94…
|
lmata
|
19 |
|
|
4c4aa94…
|
lmata
|
20 |
function platformSuffix() { |
|
4c4aa94…
|
lmata
|
21 |
const os = process.platform === "darwin" ? "darwin" : "linux"; |
|
4c4aa94…
|
lmata
|
22 |
const arch = process.arch === "arm64" ? "arm64" : "x86_64"; |
|
4c4aa94…
|
lmata
|
23 |
return `${os}-${arch}`; |
|
4c4aa94…
|
lmata
|
24 |
} |
|
4c4aa94…
|
lmata
|
25 |
|
|
4c4aa94…
|
lmata
|
26 |
async function fetchLatestVersion() { |
|
4c4aa94…
|
lmata
|
27 |
return new Promise((resolve, reject) => { |
|
4c4aa94…
|
lmata
|
28 |
get( |
|
4c4aa94…
|
lmata
|
29 |
`https://api.github.com/repos/${REPO}/releases/latest`, |
|
4c4aa94…
|
lmata
|
30 |
{ headers: { "User-Agent": "scuttlectl-npm" } }, |
|
4c4aa94…
|
lmata
|
31 |
(res) => { |
|
4c4aa94…
|
lmata
|
32 |
let data = ""; |
|
4c4aa94…
|
lmata
|
33 |
res.on("data", (c) => (data += c)); |
|
4c4aa94…
|
lmata
|
34 |
res.on("end", () => { |
|
4c4aa94…
|
lmata
|
35 |
try { |
|
4c4aa94…
|
lmata
|
36 |
resolve(JSON.parse(data).tag_name); |
|
4c4aa94…
|
lmata
|
37 |
} catch (e) { |
|
4c4aa94…
|
lmata
|
38 |
reject(e); |
|
4c4aa94…
|
lmata
|
39 |
} |
|
4c4aa94…
|
lmata
|
40 |
}); |
|
4c4aa94…
|
lmata
|
41 |
} |
|
4c4aa94…
|
lmata
|
42 |
).on("error", reject); |
|
4c4aa94…
|
lmata
|
43 |
}); |
|
4c4aa94…
|
lmata
|
44 |
} |
|
4c4aa94…
|
lmata
|
45 |
|
|
4c4aa94…
|
lmata
|
46 |
async function download(url, dest) { |
|
4c4aa94…
|
lmata
|
47 |
return new Promise((resolve, reject) => { |
|
4c4aa94…
|
lmata
|
48 |
get(url, { headers: { "User-Agent": "scuttlectl-npm" } }, (res) => { |
|
4c4aa94…
|
lmata
|
49 |
if (res.statusCode === 302 || res.statusCode === 301) { |
|
4c4aa94…
|
lmata
|
50 |
return download(res.headers.location, dest).then(resolve).catch(reject); |
|
4c4aa94…
|
lmata
|
51 |
} |
|
4c4aa94…
|
lmata
|
52 |
mkdirSync(BIN_DIR, { recursive: true }); |
|
4c4aa94…
|
lmata
|
53 |
const out = createWriteStream(dest); |
|
4c4aa94…
|
lmata
|
54 |
res.pipe(out); |
|
4c4aa94…
|
lmata
|
55 |
out.on("finish", resolve); |
|
4c4aa94…
|
lmata
|
56 |
out.on("error", reject); |
|
4c4aa94…
|
lmata
|
57 |
}).on("error", reject); |
|
4c4aa94…
|
lmata
|
58 |
}); |
|
4c4aa94…
|
lmata
|
59 |
} |
|
4c4aa94…
|
lmata
|
60 |
|
|
4c4aa94…
|
lmata
|
61 |
async function ensureBinary() { |
|
4c4aa94…
|
lmata
|
62 |
if (existsSync(BIN_PATH)) return; |
|
4c4aa94…
|
lmata
|
63 |
|
|
4c4aa94…
|
lmata
|
64 |
const version = await fetchLatestVersion(); |
|
4c4aa94…
|
lmata
|
65 |
const suffix = platformSuffix(); |
|
4c4aa94…
|
lmata
|
66 |
const asset = `scuttlectl-${version}-${suffix}.tar.gz`; |
|
4c4aa94…
|
lmata
|
67 |
const url = `https://github.com/${REPO}/releases/download/${version}/${asset}`; |
|
4c4aa94…
|
lmata
|
68 |
const tarPath = join(BIN_DIR, asset); |
|
4c4aa94…
|
lmata
|
69 |
|
|
4c4aa94…
|
lmata
|
70 |
process.stderr.write(`Downloading scuttlectl ${version}...\n`); |
|
4c4aa94…
|
lmata
|
71 |
await download(url, tarPath); |
|
4c4aa94…
|
lmata
|
72 |
|
|
4c4aa94…
|
lmata
|
73 |
await new Promise((resolve, reject) => { |
|
4c4aa94…
|
lmata
|
74 |
require("fs") |
|
4c4aa94…
|
lmata
|
75 |
.createReadStream(tarPath) |
|
4c4aa94…
|
lmata
|
76 |
.pipe(createGunzip()) |
|
4c4aa94…
|
lmata
|
77 |
.pipe(Extract({ cwd: BIN_DIR, strip: 0 })) |
|
4c4aa94…
|
lmata
|
78 |
.on("finish", resolve) |
|
4c4aa94…
|
lmata
|
79 |
.on("error", reject); |
|
4c4aa94…
|
lmata
|
80 |
}); |
|
4c4aa94…
|
lmata
|
81 |
|
|
4c4aa94…
|
lmata
|
82 |
chmodSync(BIN_PATH, 0o755); |
|
4c4aa94…
|
lmata
|
83 |
require("fs").unlinkSync(tarPath); |
|
4c4aa94…
|
lmata
|
84 |
} |
|
4c4aa94…
|
lmata
|
85 |
|
|
4c4aa94…
|
lmata
|
86 |
ensureBinary() |
|
4c4aa94…
|
lmata
|
87 |
.then(() => { |
|
4c4aa94…
|
lmata
|
88 |
execFileSync(BIN_PATH, process.argv.slice(2), { stdio: "inherit" }); |
|
4c4aa94…
|
lmata
|
89 |
}) |
|
4c4aa94…
|
lmata
|
90 |
.catch((err) => { |
|
4c4aa94…
|
lmata
|
91 |
process.stderr.write(`scuttlectl: ${err.message}\n`); |
|
4c4aa94…
|
lmata
|
92 |
process.exit(1); |
|
4c4aa94…
|
lmata
|
93 |
}); |