Skip to content

Commit 86b52bc

Browse files
Refactor install script (#114)
* Refactor install script: * Convert from CJS to ESM * Improve code documentation * Adopt many ES6+ coding styles (let/const, promises, optional chaining, endsWith, etc.) * Manifest Maintenance: * Reduce dependencies from 10 to 5 by swapping most out for native Node modules, or newer alternatives. * Updated dependencies. * Remove "engines" and "packageManager" from manifest to avoid reported issues. * Bug fixes: * #26 & #74 - Freezing during or after post-install step. * #77 - Decompress API change bug. Swapped Decompress for Compressing. * #93 - Errors on install and deprecation warnings * #109 - Engines/packageManager mismatch
1 parent 8f6ac34 commit 86b52bc

File tree

4 files changed

+357
-880
lines changed

4 files changed

+357
-880
lines changed

lib/install.mjs

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import { createWriteStream, existsSync } from 'node:fs';
2+
import { rename, rm } from 'node:fs/promises';
3+
import { get } from 'node:https';
4+
import { dirname, resolve } from 'node:path';
5+
import { arch, env, platform, exit } from 'node:process';
6+
import { fileURLToPath, URL } from 'node:url';
7+
8+
import compressing from 'compressing';
9+
import progress from 'cli-progress';
10+
import semver from 'semver';
11+
12+
import nodeManifest from '../package.json' assert { type: 'json' };
13+
14+
/**
15+
* NW.js build flavor
16+
*
17+
* @type {'sdk' | 'normal'}
18+
*/
19+
let buildType = env.npm_config_nwjs_build_type || env.NWJS_BUILD_TYPE || 'normal';
20+
21+
/**
22+
* Parsed string version to Semver version object
23+
*/
24+
let parsedVersion = semver.parse(nodeManifest.version);
25+
26+
/**
27+
* Version string of the format `X.Y.Z-pre`.
28+
* The prerelease segment `pre` is used to specify build flavor, or other tags.
29+
*
30+
* @type {string}
31+
*/
32+
let versionString = [
33+
parsedVersion.major,
34+
parsedVersion.minor,
35+
parsedVersion.patch
36+
].join('.');
37+
38+
// Check if version is a prelease.
39+
if (typeof parsedVersion?.prerelease?.[0] === 'string') {
40+
let prerelease = parsedVersion.prerelease[0].split('-');
41+
if (prerelease.length > 1) {
42+
prerelease = prerelease.slice(0, -1);
43+
}
44+
versionString = [versionString, ...prerelease].join('-');
45+
}
46+
47+
// Check build flavor and slice that off the `versionString`.
48+
if (versionString.endsWith('-sdk')) {
49+
versionString = versionString.slice(0, -4);
50+
buildType = 'sdk';
51+
} else if (versionString.endsWith('sdk')) {
52+
versionString = versionString.slice(0, -3);
53+
buildType = 'sdk';
54+
}
55+
56+
/**
57+
* URL to download or get binaries from.
58+
*
59+
* @type {string}
60+
*/
61+
let url = '';
62+
63+
/**
64+
* Host operating system
65+
*
66+
* @type {NodeJS.Platform | 'osx' | 'win'}
67+
*/
68+
let hostOs = env.npm_config_nwjs_platform || env.NWJS_PLATFORM || platform;
69+
70+
/**
71+
* Host architecture
72+
*
73+
* @type {NodeJS.Architecture}
74+
*/
75+
let hostArch = env.npm_config_nwjs_process_arch || arch;
76+
77+
/**
78+
* URL base prepended to `url`.
79+
*
80+
* @type {string}
81+
*/
82+
let urlBase = env.npm_config_nwjs_urlbase || env.NWJS_URLBASE || 'https://dl.nwjs.io/v';
83+
84+
const PLATFORM_KV = {
85+
darwin: 'osx',
86+
linux: 'linux',
87+
win32: 'win',
88+
};
89+
90+
const ARCH_KV = {
91+
x64: 'x64',
92+
ia32: 'ia32',
93+
arm64: 'arm64',
94+
};
95+
96+
url = [
97+
urlBase,
98+
versionString,
99+
'/nwjs',
100+
buildType === 'normal' ? '' : `-${buildType}`,
101+
'-v',
102+
versionString,
103+
'-',
104+
PLATFORM_KV[hostOs],
105+
'-',
106+
ARCH_KV[hostArch],
107+
PLATFORM_KV[hostOs] === 'linux' ? '.tar.gz' : '.zip'
108+
].join('');
109+
110+
if (!PLATFORM_KV[hostOs] || !ARCH_KV[hostArch]) {
111+
console.error('[ ERROR ] Could not find a compatible version of nw.js to download for your platform.');
112+
exit(1);
113+
}
114+
115+
const __dirname = dirname(fileURLToPath(import.meta.url));
116+
117+
/**
118+
* The folder where NW.js binaries are placed.
119+
*
120+
* @type {string}
121+
*/
122+
let nwDir = resolve(__dirname, '..', 'nwjs');
123+
124+
if (existsSync(nwDir) === true) {
125+
exit(0);
126+
}
127+
128+
let parsedUrl = new URL(url);
129+
130+
/**
131+
* Path to the compressed binary.
132+
*
133+
* @type {string}
134+
*/
135+
let filePath = '';
136+
137+
/**
138+
* Recursively delete the passed in directory.
139+
* Rename the downloaded file.
140+
* @param {string} dir - directory to remove
141+
*/
142+
const rmAndRename = async (dir) => {
143+
await rm(dir, { recursive: true, force: true });
144+
await rename(`nwjs-v${versionString}-${PLATFORM_KV[hostOs]}-${ARCH_KV[hostArch]}`, 'nwjs');
145+
};
146+
147+
/**
148+
* @param {'zip' | 'tgz'} zipOrTgz
149+
* @param {string} filePath
150+
* @return {Promise<void>}
151+
*/
152+
const decompress = function (zipOrTgz, filePath) {
153+
return compressing[zipOrTgz].uncompress(filePath, '.')
154+
.then(async () => await rmAndRename(filePath));
155+
}
156+
157+
// If the url is linking to the file system,
158+
// then it is assumed that a compressed binary exists in that location.
159+
if (parsedUrl.protocol === 'file:') {
160+
filePath = resolve(decodeURIComponent(url.slice('file://'.length)));
161+
162+
if (existsSync(filePath) === false) {
163+
console.error('[ ERROR ] Could not find ' + filePath);
164+
}
165+
166+
// If the compressed file is of ZIP format:
167+
if (filePath.endsWith('.zip')) {
168+
decompress('zip', filePath);
169+
// If the compressed file is of TGZ format:
170+
} else if (filePath.endsWith('.tar.gz')) {
171+
decompress('tgz', filePath);
172+
} else {
173+
console.error(`[ ERROR ] Expected .zip or .tar.gz file format. Got ${filePath}`);
174+
exit(1);
175+
}
176+
177+
} else {
178+
179+
const bar = new progress.SingleBar({}, progress.Presets.rect);
180+
181+
const stream = createWriteStream(nwDir);
182+
183+
get(url, (response) => {
184+
185+
let chunks = 0;
186+
bar.start(Number(response.headers['content-length']), 0);
187+
response.on('data', async (chunk) => {
188+
chunks += chunk.length;
189+
bar.increment();
190+
bar.update(chunks);
191+
});
192+
193+
response.on('error', async () => await rm(nwDir, { force: true }));
194+
195+
response.on('end', () => {
196+
if (PLATFORM_KV[hostOs] === 'linux') {
197+
decompress('tgz', nwDir);
198+
} else {
199+
decompress('zip', nwDir);
200+
}
201+
});
202+
response.pipe(stream);
203+
});
204+
}

0 commit comments

Comments
 (0)