Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Download binary on npm postinstall hook #43

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .npm/bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@ function spawnCommand(binaryExecutable) {
});
}

if (process.platform === 'darwin') {
spawnCommand('lefthook-mac');
} else if (process.platform === 'linux') {
spawnCommand('lefthook-linux');
if (process.platform === 'darwin' || process.platform === 'linux') {
spawnCommand('lefthook');
} else if (process.platform === 'win32') {
spawnCommand('lefthook-win.exe');
spawnCommand('lefthook.exe');
} else {
console.log("Unsupported OS");
process.exit(1);
Expand Down
Binary file removed .npm/bin/lefthook-linux
Binary file not shown.
Binary file removed .npm/bin/lefthook-mac
Binary file not shown.
Binary file removed .npm/bin/lefthook-win.exe
Binary file not shown.
128 changes: 117 additions & 11 deletions .npm/postinstall.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,129 @@
require("process");
const { spawn } = require("child_process");
const { join } = require("path");
const { createWriteStream, mkdirSync, unlink } = require("fs");
const { createGunzip } = require("zlib");
const { get } = require("https");
const { join, resolve } = require("path");

const { version } = require("./package.json");

const binaryName = "lefthook";
const packageDir = process.env.INIT_CWD || resolve(".");

function closeAndRemoveFile(file) {
file.on("close", () => {
unlink(file);
});
file.close();
}

function resolveDownloadPath(os, version, arch) {
let archStr;
let osStr;

if (os === "darwin") {
osStr = "MacOS";
} else if (os === "linux") {
osStr = "Linux";
} else if (os === "win32") {
if (arch === "ia32" || arch === "x86") {
console.error("Lefthook is only supported on Windows with 64bit architecture.");
process.exit(0);
}
osStr = "Windows";
}

if (arch === "x64") {
archStr = "x86_64";
} else if (arch === "ia32" || arch === "x86") {
archStr = "i386";
} else {
console.error(`Unable to resolve architecture (${arch}), only supported architectures are: 'ia32', 'x86', and 'x64'`);
process.exit(0);
}

return `https://github.com/Arkweid/lefthook/releases/download/v${version}/lefthook_${version}_${osStr}_${archStr}.gz`;
}

function downloadBinary(os, callback) {
// construct single binary file path
const binaryDir = join(packageDir, "node_modules", "@arkweid", "lefthook", "bin");
const binaryPath = join(binaryDir, `${binaryName}${os === "win32" ? ".exe" : ""}`);

// create directory if not existing, yet
try {
mkdirSync(binaryDir);
} catch (err) {
if (err.code !== 'EEXIST') {
console.error(err.message);
process.exit(0);
}
}

// create write stream as file with the constructed binaryPath, set it
// up to close as soon as no more data is expected
const file = createWriteStream(binaryPath, { mode: 0o755 });
file.on("finish", () => {
file.close();
});
file.on("close", () => {
callback(binaryPath);
});

// start download of binary file, set it up to remove the file if an
// error occurs
const downloadPath = resolveDownloadPath(os, version, process.arch);
const download = get(downloadPath, downloadResponse => {
// handle github binary redirect
if (downloadResponse.statusCode === 302) {
const redirectDownloadPath = downloadResponse.headers.location;

const redirectDownload = get(redirectDownloadPath, redirectDownloadResponse => {
if (redirectDownloadResponse.statusCode === 200) {
const gzip = createGunzip();
redirectDownloadResponse.pipe(gzip).pipe(file);
} else {
console.error("Unable to download lefthook binary file from redirect");
}
});

redirectDownload.on("error", err => {
console.error("Unable to download lefthook binary file");
console.error(err.message);
closeAndRemoveFile(file);
});
} else if (downloadResponse.statusCode === 200) {
downloadResponse.pipe(file);
downloadResponse.on("close", () => {
callback(binaryPath);
});
} else {
console.error("Unable to download lefthook binary file: Unhandled response", downloadResponse.statusCode);
}
});
download.on("error", err => {
console.error("Unable to download lefthook binary file");
console.error(err.message);
closeAndRemoveFile(file);
});
}

function installGitHooks(binaryPath) {
console.log("Installing git hooks");
spawn(binaryPath, ["install", "-f"], { stdio: [process.stdin, process.stdout, process.stderr] });
}

const isCI = process.env.CI;
if (!isCI) {
process.chdir(process.env.INIT_CWD);

if (process.platform === 'darwin') {
binary = 'lefthook-mac';
} else if (process.platform === 'linux') {
binary = 'lefthook-linux';
} else if (process.platform === 'win32') {
binary = 'lefthook-win.exe';
} else {
if (!["darwin", "linux", "win32"].includes(process.platform)) {
console.log("Unsupported OS");
process.exit(0);
}

binpath = join(process.cwd(), 'node_modules', '@arkweid', 'lefthook', 'bin', binary);

result = spawn(binpath, ["install", "-f"], { stdio: [process.stdin, process.stdout, process.stderr] });
console.log("Downloading `lefthook` binary");
downloadBinary(process.platform, installGitHooks);
} else {
console.log("Skipping downloading of `lefthook` binary due to CI environment.");
}