fleet/tools/fleetctl-npm/run.js

119 lines
3.7 KiB
JavaScript
Executable File

#!/usr/bin/env node
const child = require("child_process");
const fs = require("fs");
const os = require("os");
const path = require("path");
const axios = require("axios");
const rimraf = require("rimraf");
const tar = require("tar");
const { version } = require("./package.json");
// Strip any v4.0.0-1 style suffix (but not -rc1) so that the correct package is
// downloaded if there is a mistake in the NPM publish and we need to release a
// -1, etc. (because NPM packages are immutable and can't be fixed after a mistake).
let strippedVersion = version.replace(/-[0-9]+/i, "");
if (!strippedVersion.startsWith("v")) {
strippedVersion = `v${strippedVersion}`;
}
const binDir = path.join(__dirname, "install");
// Determine the install directory by version so that we can detect when we need
// to upgrade to a new version.
const installDir = path.join(binDir, strippedVersion);
const platform = (() => {
switch (os.type()) {
case "Windows_NT":
return "windows";
case "Linux":
return "linux";
case "Darwin":
return "macos";
default:
throw new Error(`platform ${os.type} unrecognized`);
}
})();
const binName = platform === "windows" ? "fleetctl.exe" : "fleetctl";
const binPath = path.join(installDir, binName);
const install = async () => {
const url = `https://github.com/fleetdm/fleet/releases/download/fleet-${strippedVersion}/fleetctl_${strippedVersion}_${platform}.tar.gz`;
fs.mkdirSync(installDir, { recursive: true });
try {
const response = await axios({ url, responseType: "stream" });
// Strip the outer directory when extracting. Just get the binary.
const tarWriter = tar.extract({ strip: 1, cwd: installDir });
response.data.pipe(tarWriter);
// Need to return a promise with the writer to ensure we can await for it to complete.
return new Promise((resolve, reject) => {
tarWriter.on("finish", resolve);
tarWriter.on("error", reject);
});
} catch (err) {
throw new Error(`download archive ${url}: ${err.message}`);
}
};
const run = async () => {
if (!fs.existsSync(binPath)) {
// Remove any existing binaries before installing the new one.
rimraf.sync(binDir);
console.log(`Installing fleetctl ${strippedVersion}...`);
try {
await install();
} catch (err) {
// Users commonly see permission errors when trying to install the binaries if they have run
// `sudo npm install -g fleetctl` (or the Windows equivalent of running as admin), then later
// try to run fleetctl without those elevated privileges.
if (err.code === "EACCES") {
switch (process.platform) {
case "darwin":
case "linux":
console.error(
"Error: It looks like your fleetctl has been installed as root."
);
console.error("Please re-run this command with sudo.");
process.exit(1);
break;
case "win32":
case "win64":
console.error(
"Error: It looks like your fleetctl has been installed as administrator."
);
console.error(
"Please re-run this command using 'Run as administrator'."
);
process.exit(1);
break;
default:
// Fall through to generic error print below
}
}
console.error(`Error: Failed to install: ${err.message}`);
process.exit(1);
}
console.log("Install completed.");
}
const [, , ...args] = process.argv;
const options = { cwd: process.cwd(), stdio: "inherit" };
const { status, error } = child.spawnSync(binPath, args, options);
if (error) {
console.error(error);
process.exit(1);
}
process.exit(status);
};
run();