Skip to content
This repository was archived by the owner on Sep 17, 2023. It is now read-only.

Commit 3122d60

Browse files
committed
feat: download release binary in postinstall script
This implementation uses a local copy of binary-install to bring in changes from EverlastingBugstopper/binary-install#12.
1 parent 4bf9237 commit 3122d60

File tree

7 files changed

+11360
-11020
lines changed

7 files changed

+11360
-11020
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## Supported Systems
2+
3+
The following operating systems are supported
4+
5+
- [x] GNU/Linux
6+
- [x] Mac OS
7+
- [ ] Windows
8+
9+
The following package managers are supported
10+
11+
- [x] npm
12+
- [ ] yarn

npm/binary-install.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
const { existsSync, mkdirSync } = require("fs");
2+
const { join } = require("path");
3+
const { spawnSync } = require("child_process");
4+
5+
const axios = require("axios");
6+
const tar = require("tar");
7+
const rimraf = require("rimraf");
8+
9+
const error = msg => {
10+
console.error(msg);
11+
process.exit(1);
12+
};
13+
14+
class Binary {
15+
constructor(name, url) {
16+
let errors = [];
17+
if (typeof url !== "string") {
18+
errors.push("url must be a string");
19+
} else {
20+
try {
21+
new URL(url);
22+
} catch (e) {
23+
errors.push(e);
24+
}
25+
}
26+
if (name && typeof name !== "string") {
27+
errors.push("name must be a string");
28+
}
29+
30+
if (!name) {
31+
errors.push("You must specify the name of your binary");
32+
}
33+
if (errors.length > 0) {
34+
let errorMsg =
35+
"One or more of the parameters you passed to the Binary constructor are invalid:\n";
36+
errors.forEach(error => {
37+
errorMsg += error;
38+
});
39+
errorMsg +=
40+
'\n\nCorrect usage: new Binary("my-binary", "https://example.com/binary/download.tar.gz")';
41+
error(errorMsg);
42+
}
43+
this.url = url;
44+
this.name = name;
45+
this.installDirectory = join(__dirname, "../node_modules/binary-install/bin");
46+
47+
if (!existsSync(this.installDirectory)) {
48+
mkdirSync(this.installDirectory, { recursive: true });
49+
}
50+
51+
this.binaryPath = join(this.installDirectory, this.name);
52+
}
53+
54+
install(fetchOptions) {
55+
if (existsSync(this.installDirectory)) {
56+
rimraf.sync(this.installDirectory);
57+
}
58+
59+
mkdirSync(this.installDirectory, { recursive: true });
60+
61+
// console.log(`Downloading release from ${this.url}`);
62+
63+
return axios({ ...fetchOptions, url: this.url, responseType: "stream" })
64+
.then(res => {
65+
return new Promise((resolve, reject) => {
66+
const sink = tar.x({ strip: 1, C: this.installDirectory });
67+
res.data.pipe(sink);
68+
sink.on('finish', () => resolve());
69+
sink.on('error', err => reject(err));
70+
});
71+
})
72+
.then(() => {
73+
// console.log(`${this.name} has been installed!`);
74+
})
75+
.catch(e => {
76+
error(`Error fetching release: ${e.message}`);
77+
});
78+
}
79+
80+
run() {
81+
if (!existsSync(this.binaryPath)) {
82+
error(`You must install ${this.name} before you can run it`);
83+
}
84+
85+
const [, , ...args] = process.argv;
86+
87+
const options = { cwd: process.cwd(), stdio: "inherit" };
88+
89+
const result = spawnSync(this.binaryPath, args, options);
90+
91+
if (result.error) {
92+
error(result.error);
93+
}
94+
95+
process.exit(result.status);
96+
}
97+
}
98+
99+
module.exports.Binary = Binary;

npm/get-binary.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const os = require('os')
2+
const { Binary } = require('./binary-install')
3+
4+
const knownUnixLikePackages = {
5+
'darwin x64 LE': 'x86_64-apple-darwin',
6+
'linux x64 LE': 'x86_64-unknown-linux-gnu',
7+
}
8+
9+
const binPathForCurrentPlatform = () => {
10+
const platformKey = `${process.platform} ${os.arch()} ${os.endianness()}`
11+
if (platformKey in knownUnixLikePackages) {
12+
return knownUnixLikePackages[platformKey]
13+
}
14+
15+
throw new Error('Unsupported platform: ${platformKey}')
16+
}
17+
18+
const getBinary = () => {
19+
const { version, repository } = require('../package.json')
20+
const platform = binPathForCurrentPlatform()
21+
const url = `${repository.url}/releases/download/v${version}/typescript-tools-${platform}.tar.gz`
22+
const binaryName = 'monorepo'
23+
return new Binary(binaryName, url)
24+
}
25+
26+
module.exports = getBinary

npm/install.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const fs = require('fs')
2+
const path = require('path')
3+
const getBinary = require('./get-binary')
4+
5+
// Link the downloaded binary into the node_modules/.bin directory
6+
const linkBinaryIntoBin = () => {
7+
const binaryName = 'monorepo'
8+
const existingPath = path.resolve(__dirname, `../node_modules/binary-install/bin/${binaryName}`)
9+
const desiredPath = path.resolve(__dirname, `../node_modules/.bin/${binaryName}`)
10+
11+
// Only symlink the path when it does not yet exist
12+
if (!fs.existsSync(desiredPath)) {
13+
fs.linkSync(existingPath, desiredPath)
14+
}
15+
}
16+
17+
// Downloaded binary to /node_modules/binary-install/bin/{ name }
18+
getBinary().install()
19+
.then(linkBinaryIntoBin)

npm/uninstall.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// When installing, the `preinstall` script is executed before any dependencies are
2+
// installed. Since this script `require`s a dependency, another developer who clones
3+
// the repository and runs `npm install` will get an error that dependencies are
4+
// missing.
5+
//
6+
// We guard against this with a try/catch to swallow the error: if the dependencies are
7+
// not found it means the package wasn't installed yet, and that means there's no binary
8+
// to uninstall in the first place.
9+
10+
const getBinary = () => {
11+
try {
12+
const getBinary = require('./get-binary')
13+
return getBinary()
14+
} catch {
15+
16+
}
17+
}
18+
19+
const binary = getBinary()
20+
console.log("Binary is", binary)
21+
if (binary) {
22+
binary.uninstall()
23+
}

0 commit comments

Comments
 (0)