nw-builder 4.4.2 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/get.js CHANGED
@@ -1,26 +1,48 @@
1
- import { spawnSync } from "node:child_process";
2
- import { createWriteStream, existsSync } from "node:fs";
3
- import { mkdir, readdir, rm, rmdir } from "node:fs/promises";
4
- import { get as getRequest } from "node:https";
5
- import { resolve } from "node:path";
6
- import { arch as ARCH, platform as PLATFORM, exit as EXIT } from "node:process";
1
+ import child_process from "node:child_process";
2
+ import console from "node:console";
3
+ import fs from "node:fs";
4
+ import fsm from "node:fs/promises";
5
+ import https from "node:https";
6
+ import path from "node:path";
7
7
 
8
8
  import progress from "cli-progress";
9
- import compressing from "compressing";
9
+ import tar from "tar";
10
+ import unzipper from "unzipper";
10
11
 
11
- import { log } from "./log.js";
12
- import { ARCH_KV, PLATFORM_KV, replaceFfmpeg } from "./util.js";
12
+ import util from "./util.js";
13
+
14
+ /**
15
+ * @typedef {object} GetOptions
16
+ * @property {string | "latest" | "stable" | "lts"} [options.version = "latest"] Runtime version
17
+ * @property {"normal" | "sdk"} [options.flavor = "normal"] Build flavor
18
+ * @property {"linux" | "osx" | "win"} [options.platform] Target platform
19
+ * @property {"ia32" | "x64" | "arm64"} [options.arch] Target arch
20
+ * @property {string} [options.downloadUrl = "https://dl.nwjs.io"] Download server
21
+ * @property {string} [options.cacheDir = "./cache"] Cache directory
22
+ * @property {boolean} [options.cache = true] If false, remove cache and redownload.
23
+ * @property {boolean} [options.ffmpeg = false] If true, ffmpeg is not downloaded.
24
+ * @property {false | "gyp"} [options.nativeAddon = false] Rebuild native modules
25
+ */
13
26
 
14
27
  /**
15
- * _Note: This an internal function which is not called directly. Please see example usage below._
16
- *
17
28
  * Get binaries.
29
+ *
30
+ * @async
31
+ * @function
32
+ * @param {GetOptions} options Get mode options
33
+ * @returns {Promise<void>}
18
34
  *
19
35
  * @example
20
36
  * // Minimal Usage (uses default values)
21
37
  * nwbuild({
22
38
  * mode: "get",
23
39
  * });
40
+ *
41
+ * // Use with nw module
42
+ * nwbuild({
43
+ * mode: "get",
44
+ * cacheDir: "./node_modules/nw"
45
+ * });
24
46
  *
25
47
  * @example
26
48
  * // Unofficial macOS builds (upto v0.75.0)
@@ -54,293 +76,274 @@ import { ARCH_KV, PLATFORM_KV, replaceFfmpeg } from "./util.js";
54
76
  * ffmpeg: true,
55
77
  * });
56
78
  *
57
- * @param {object} options Get mode options
58
- * @param {string} options.version NW.js runtime version. Defaults to "latest".
59
- * @param {"normal" | "sdk"} options.flavor NW.js build flavor. Defaults to "normal".
60
- * @param {"linux" | "osx" | "win"} options.platform Target platform. Defaults to host platform.
61
- * @param {"ia32" | "x64" | "arm64"} options.arch Target architecture. Defaults to host architecture.
62
- * @param {string} options.downloadUrl File server to download from. Defaults to "https://dl.nwjs.io". Set "https://npm.taobao.org/mirrors/nwjs" for China mirror or "https://cnpmjs.org/mirrors/nwjs/" for Singapore mirror.
63
- * @param {string} options.cacheDir Cache directory path. Defaults to "./cache"
64
- * @param {boolean} options.cache If false, remove cache before download. Defaults to true.
65
- * @param {boolean} options.ffmpeg If true, ffmpeg is not downloaded. Defaults to false.
66
- * @return {Promise<void>}
79
+ * @example
80
+ * // Node headers
81
+ * nwbuild({
82
+ * mode: "get",
83
+ * nativeAddon: "gyp",
84
+ * });
67
85
  */
68
- export async function get({
69
- version = "latest",
70
- flavor = "normal",
71
- platform = PLATFORM_KV[PLATFORM],
72
- arch = ARCH_KV[ARCH],
73
- downloadUrl = "https://dl.nwjs.io",
74
- cacheDir = "./cache",
75
- cache = true,
76
- ffmpeg = false,
77
- }) {
78
- await get_nwjs({
79
- version,
80
- flavor,
81
- platform,
82
- arch,
83
- downloadUrl,
84
- cacheDir,
85
- cache,
86
- });
87
- if (ffmpeg === true) {
88
- await get_ffmpeg({
89
- version,
90
- flavor,
91
- platform,
92
- arch,
93
- downloadUrl,
94
- cacheDir,
95
- cache,
96
- });
86
+ async function get(options) {
87
+ await getNwjs(options);
88
+ if (options.ffmpeg === true) {
89
+ await getFfmpeg(options);
90
+ }
91
+ if (options.nativeAddon === "gyp") {
92
+ await getNodeHeaders(options);
97
93
  }
98
94
  }
99
95
 
100
- /**
101
- * Note: This an internal function which is not called directly. Please see example usage below.
102
- *
103
- * Get NW.js binaries
104
- *
105
- * @param {object} options Get mode options
106
- * @param {string} options.version NW.js runtime version. Defaults to "latest".
107
- * @param {"normal" | "sdk"} options.flavor NW.js build flavor. Defaults to "normal".
108
- * @param {"linux" | "osx" | "win"} options.platform Target platform. Defaults to host platform.
109
- * @param {"ia32" | "x64" | "arm64"} options.arch Target architecture. Defaults to host architecture.
110
- * @param {string} options.downloadUrl File server to download from. Defaults to "https://dl.nwjs.io". Set "https://npm.taobao.org/mirrors/nwjs" for China mirror or "https://cnpmjs.org/mirrors/nwjs/" for Singapore mirror.
111
- * @param {string} options.cacheDir Cache directory path. Defaults to "./cache"
112
- * @param {boolean} options.cache If false, remove cache before download. Defaults to true.
113
- * @return {Promise<void>}
114
- */
115
- async function get_nwjs({
116
- version = "latest",
117
- flavor = "normal",
118
- platform = PLATFORM_KV[PLATFORM],
119
- arch = ARCH_KV[ARCH],
120
- downloadUrl = "https://dl.nwjs.io",
121
- cacheDir = "./cache",
122
- cache = true,
123
- }) {
124
- log.debug(`Start getting binaries`);
125
- let nwCached = true;
126
- const nwDir = resolve(
127
- cacheDir,
128
- `nwjs${flavor === "sdk" ? "-sdk" : ""}-v${version}-${platform}-${arch}`,
129
- );
130
- let out = undefined;
131
- let url = undefined;
96
+ const getNwjs = async (options) => {
132
97
  const bar = new progress.SingleBar({}, progress.Presets.rect);
133
-
134
- // Set download url and destination.
135
- if (
136
- downloadUrl === "https://dl.nwjs.io" ||
137
- downloadUrl === "https://npm.taobao.org/mirrors/nwjs" ||
138
- downloadUrl === "https://npmmirror.com/mirrors/nwjs"
139
- ) {
140
- url = `${downloadUrl}/v${version}/nwjs${
141
- flavor === "sdk" ? "-sdk" : ""
142
- }-v${version}-${platform}-${arch}.${
143
- platform === "linux" ? "tar.gz" : "zip"
144
- }`;
145
- out = resolve(cacheDir, `nw.${platform === "linux" ? "tgz" : "zip"}`);
146
- }
147
-
98
+ const out = path.resolve(
99
+ options.cacheDir,
100
+ `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}.${options.platform === "linux" ? "tar.gz" : "zip"
101
+ }`,
102
+ );
148
103
  // If options.cache is false, remove cache.
149
- if (cache === false) {
150
- log.debug(`Removing existing binaries`);
151
- rmdir(nwDir, { recursive: true, force: true });
104
+ if (options.cache === false) {
105
+ await fsm.rm(out, {
106
+ recursive: true,
107
+ force: true,
108
+ });
152
109
  }
153
110
 
154
- // Check if cache exists.
155
- try {
156
- await readdir(nwDir);
157
- log.debug(`Found existing NW.js binaries`);
158
- } catch (error) {
159
- log.debug(`No existing binaries`);
160
- nwCached = false;
111
+ if (fs.existsSync(out) === true) {
112
+ await fsm.rm(
113
+ path.resolve(
114
+ options.cacheDir,
115
+ `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}`,
116
+ ),
117
+ { recursive: true, force: true },
118
+ );
119
+ if (options.platform === "linux") {
120
+ await tar.extract({
121
+ file: out,
122
+ C: options.cacheDir
123
+ });
124
+ } else {
125
+ fs.createReadStream(out)
126
+ .pipe(unzipper.Extract({ path: options.cacheDir }));
127
+ }
128
+ return;
161
129
  }
162
130
 
163
- // If not cached, then download.
164
- if (nwCached === false) {
165
- log.debug(`Downloading binaries`);
166
- await mkdir(nwDir, { recursive: true });
167
-
168
- const stream = createWriteStream(out);
169
- const request = new Promise((resolve, reject) => {
170
- getRequest(url, (response) => {
171
- log.debug(`Response from ${url}`);
172
- // For GitHub releases and mirrors, we need to follow the redirect.
173
- if (
174
- downloadUrl === "https://npm.taobao.org/mirrors/nwjs" ||
175
- downloadUrl === "https://npmmirror.com/mirrors/nwjs"
176
- ) {
177
- url = response.headers.location;
178
- }
179
-
180
- getRequest(url, (response) => {
181
- log.debug(`Response from ${url}`);
182
- let chunks = 0;
183
- bar.start(Number(response.headers["content-length"]), 0);
184
- response.on("data", async (chunk) => {
185
- chunks += chunk.length;
186
- bar.increment();
187
- bar.update(chunks);
188
- });
189
-
190
- response.on("error", (error) => {
191
- reject(error);
192
- });
193
-
194
- response.on("end", () => {
195
- log.debug(`Binary fully downloaded`);
196
- bar.stop();
197
- if (platform === "linux") {
198
- compressing.tgz.uncompress(out, cacheDir).then(() => resolve());
199
- } else if (platform === "osx") {
200
- //TODO: compressing package does not restore symlinks on some macOS (eg: circleCI)
201
- const exec = function (cmd) {
202
- log.debug(cmd);
203
- const result = spawnSync(cmd, {
204
- shell: true,
205
- stdio: "inherit",
206
- });
207
- if (result.status !== 0) {
208
- log.debug(`Command failed with status ${result.status}`);
209
- if (result.error) console.log(result.error);
210
- EXIT(1);
211
- }
212
- return resolve();
213
- };
214
- exec(`unzip -o "${out}" -d "${cacheDir}"`);
215
- } else {
216
- compressing.zip.uncompress(out, cacheDir).then(() => resolve());
217
- }
218
- });
219
-
220
- response.pipe(stream);
131
+ const stream = fs.createWriteStream(out);
132
+ const request = new Promise((res, rej) => {
133
+ let url = "";
134
+
135
+ // Set download url and destination.
136
+ if (
137
+ options.downloadUrl === "https://dl.nwjs.io" ||
138
+ options.downloadUrl === "https://npm.taobao.org/mirrors/nwjs" ||
139
+ options.downloadUrl === "https://npmmirror.com/mirrors/nwjs"
140
+ ) {
141
+ url = `${options.downloadUrl}/v${options.version}/nwjs${options.flavor === "sdk" ? "-sdk" : ""
142
+ }-v${options.version}-${options.platform}-${options.arch}.${options.platform === "linux" ? "tar.gz" : "zip"
143
+ }`;
144
+ }
145
+
146
+ https.get(url, (response) => {
147
+ // For GitHub releases and mirrors, we need to follow the redirect.
148
+ if (
149
+ options.downloadUrl === "https://npm.taobao.org/mirrors/nwjs" ||
150
+ options.downloadUrl === "https://npmmirror.com/mirrors/nwjs"
151
+ ) {
152
+ url = response.headers.location;
153
+ }
154
+
155
+ https.get(url, (response) => {
156
+ let chunks = 0;
157
+ bar.start(Number(response.headers["content-length"]), 0);
158
+ response.on("data", (chunk) => {
159
+ chunks += chunk.length;
160
+ bar.increment();
161
+ bar.update(chunks);
221
162
  });
222
163
 
223
164
  response.on("error", (error) => {
224
- reject(error);
165
+ rej(error);
225
166
  });
167
+
168
+ response.on("end", () => {
169
+ bar.stop();
170
+ res();
171
+ });
172
+
173
+ response.pipe(stream);
226
174
  });
227
- });
228
175
 
229
- // Remove compressed file after download and decompress.
230
- return request.then(async () => {
231
- log.debug(`Binary decompressed starting removal`);
176
+ response.on("error", (error) => {
177
+ rej(error);
178
+ });
179
+ });
180
+ });
232
181
 
233
- await rm(
234
- resolve(cacheDir, `nw.${platform === "linux" ? "tgz" : "zip"}`),
235
- { recursive: true, force: true },
236
- );
237
- log.debug(`Binary zip removed`);
182
+ await request;
183
+ await fsm.rm(
184
+ path.resolve(
185
+ options.cacheDir,
186
+ `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}`,
187
+ ),
188
+ { recursive: true, force: true },
189
+ );
190
+ if (options.platform === "linux") {
191
+ await tar.extract({
192
+ file: out,
193
+ C: options.cacheDir
238
194
  });
195
+ } else {
196
+ fs.createReadStream(out)
197
+ .pipe(unzipper.Extract({ path: options.cacheDir }));
239
198
  }
240
199
  }
241
200
 
242
- /**
243
- *
244
- * Note: This an internal function which is not called directly. Please see example usage below.
245
- *
246
- * Get FFmpeg binary.
247
- *
248
- * @param {object} options Get mode options
249
- * @param {string} options.version NW.js runtime version. Defaults to "latest".
250
- * @param {"normal" | "sdk"} options.flavor NW.js build flavor. Defaults to "normal".
251
- * @param {"linux" | "osx" | "win"} options.platform Target platform. Defaults to host platform.
252
- * @param {"ia32" | "x64" | "arm64"} options.arch Target architecture. Defaults to host architecture.
253
- * @param {string} options.cacheDir Cache directory path. Defaults to "./cache"
254
- * @param {boolean} options.cache If false, remove cache before download. Defaults to true.
255
- * @return {Promise<void>}
256
- */
257
- async function get_ffmpeg({
258
- version = "latest",
259
- flavor = "normal",
260
- platform = PLATFORM_KV[PLATFORM],
261
- arch = ARCH_KV[ARCH],
262
- cacheDir = "./cache",
263
- cache = true,
264
- }) {
265
- log.debug(`Start getting binaries`);
266
- const nwDir = resolve(
267
- cacheDir,
268
- `nwjs${flavor === "sdk" ? "-sdk" : ""}-v${version}-${platform}-${arch}`,
201
+
202
+ const getFfmpeg = async (options) => {
203
+ const nwDir = path.resolve(
204
+ options.cacheDir,
205
+ `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}`,
269
206
  );
270
207
  const bar = new progress.SingleBar({}, progress.Presets.rect);
271
208
 
272
209
  // If options.ffmpeg is true, then download ffmpeg.
273
- const downloadUrl =
274
- "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download";
275
- let url = `${downloadUrl}/${version}/${version}-${platform}-${arch}.zip`;
276
- const out = resolve(cacheDir, `ffmpeg-v${version}-${platform}-${arch}.zip`);
210
+ options.downloadUrl = "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download";
211
+ let url = `${options.downloadUrl}/${options.version}/${options.version}-${options.platform}-${options.arch}.zip`;
212
+ const out = path.resolve(options.cacheDir, `ffmpeg-v${options.version}-${options.platform}-${options.arch}.zip`);
277
213
 
278
214
  // If options.cache is false, remove cache.
279
- if (cache === false) {
280
- log.debug(`Removing existing binaries`);
281
- await rm(out, {
215
+ if (options.cache === false) {
216
+ await fsm.rm(out, {
282
217
  recursive: true,
283
218
  force: true,
284
219
  });
285
- log.debug(`FFMPEG zip cache removed`);
286
220
  }
287
221
 
288
222
  // Check if cache exists.
289
- if (existsSync(out) === true) {
290
- log.debug(`Found existing FFMPEG cache`);
291
- await compressing.zip.uncompress(out, nwDir);
223
+ if (fs.existsSync(out) === true) {
224
+ fs.createReadStream(out)
225
+ .pipe(unzipper.Extract({ path: nwDir }));
292
226
  return;
293
227
  }
294
228
 
295
- log.debug(`Downloading FFMPEG`);
296
- const stream = createWriteStream(out);
297
- const request = new Promise((resolve, reject) => {
298
- getRequest(url, (response) => {
299
- log.debug(`Response from ${url}`);
229
+ const stream = fs.createWriteStream(out);
230
+ const request = new Promise((res, rej) => {
231
+ https.get(url, (response) => {
300
232
  // For GitHub releases and mirrors, we need to follow the redirect.
301
233
  url = response.headers.location;
302
234
 
303
- getRequest(url, (response) => {
304
- log.debug(`Response from ${url}`);
235
+ https.get(url, (response) => {
305
236
  let chunks = 0;
306
237
  bar.start(Number(response.headers["content-length"]), 0);
307
- response.on("data", async (chunk) => {
238
+ response.on("data", (chunk) => {
308
239
  chunks += chunk.length;
309
240
  bar.increment();
310
241
  bar.update(chunks);
311
242
  });
312
243
 
313
244
  response.on("error", (error) => {
314
- reject(error);
245
+ rej(error);
315
246
  });
316
247
 
317
248
  response.on("end", () => {
318
- log.debug(`FFMPEG fully downloaded`);
319
249
  bar.stop();
320
- resolve();
250
+ res();
321
251
  });
322
252
 
323
253
  response.pipe(stream);
324
254
  });
325
255
 
326
256
  response.on("error", (error) => {
327
- reject(error);
257
+ rej(error);
328
258
  });
329
259
  });
330
260
  });
331
261
 
332
262
  // Remove compressed file after download and decompress.
333
- return request
334
- .then(async () => await compressing.zip.uncompress(out, nwDir))
335
- .then(async () => await replaceFfmpeg(platform, nwDir))
336
- .then(async () => {
337
- if (cache === false) {
338
- log.debug(`Removing FFMPEG zip cache`);
339
- await rm(out, {
340
- recursive: true,
341
- force: true,
342
- });
343
- log.debug(`FFMPEG zip cache removed`);
344
- }
263
+ await request;
264
+ fs.createReadStream(out)
265
+ .pipe(unzipper.Extract({ path: nwDir }));
266
+ await util.replaceFfmpeg(options.platform, nwDir);
267
+ }
268
+
269
+ const getNodeHeaders = async (options) => {
270
+ const bar = new progress.SingleBar({}, progress.Presets.rect);
271
+ const out = path.resolve(
272
+ options.cacheDir,
273
+ `headers-v${options.version}-${options.platform}-${options.arch}.tar.gz`,
274
+ );
275
+
276
+ // If options.cache is false, remove cache.
277
+ if (options.cache === false) {
278
+ await fsm.rm(out, {
279
+ recursive: true,
280
+ force: true,
345
281
  });
282
+ }
283
+
284
+ if (fs.existsSync(out) === true) {
285
+ await tar.extract({
286
+ file: out,
287
+ C: options.cacheDir
288
+ });
289
+ await fsm.rm(path.resolve(options.cacheDir, `node-v${options.version}-${options.platform}-${options.arch}`), {
290
+ recursive: true,
291
+ force: true,
292
+ });
293
+ await fsm.rename(
294
+ path.resolve(options.cacheDir, "node"),
295
+ path.resolve(options.cacheDir, `node-v${options.version}-${options.platform}-${options.arch}`),
296
+ );
297
+
298
+ child_process.exec(
299
+ "patch " +
300
+ path.resolve(
301
+ options.cacheDir,
302
+ `node-v${options.version}-${options.platform}-${options.arch}`,
303
+ "common.gypi",
304
+ ) +
305
+ " " +
306
+ path.resolve("..", "..", "patches", "node_header.patch"),
307
+ (error) => {
308
+ console.error(error);
309
+ },
310
+ );
311
+ }
312
+
313
+ const stream = fs.createWriteStream(out);
314
+ const request = new Promise((res, rej) => {
315
+ const url = `${options.downloadUrl}/v${options.version}/nw-headers-v${options.version}.tar.gz`;
316
+ https.get(url, (response) => {
317
+ let chunks = 0;
318
+ bar.start(Number(response.headers["content-length"]), 0);
319
+ response.on("data", (chunk) => {
320
+ chunks += chunk.length;
321
+ bar.increment();
322
+ bar.update(chunks);
323
+ });
324
+
325
+ response.on("error", (error) => {
326
+ rej(error);
327
+ });
328
+
329
+ response.on("end", () => {
330
+ bar.stop();
331
+ res();
332
+ });
333
+
334
+ response.pipe(stream);
335
+ });
336
+ });
337
+
338
+ await request;
339
+ await tar.extract({
340
+ file: out,
341
+ C: options.cacheDir
342
+ });
343
+ await fsm.rename(
344
+ path.resolve(options.cacheDir, "node"),
345
+ path.resolve(options.cacheDir, `node-v${options.version}-${options.platform}-${options.arch}`),
346
+ );
346
347
  }
348
+
349
+ export default get;