nw-builder 4.6.0 → 4.6.2
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/README.md +13 -2
- package/package.json +4 -4
- package/src/bld.js +15 -13
- package/src/get/decompress.js +45 -45
- package/src/get/index.js +211 -0
- package/src/index.js +18 -16
- package/src/run.js +11 -9
- package/src/util.js +8 -58
- package/src/get.js +0 -232
package/README.md
CHANGED
|
@@ -107,6 +107,8 @@ nwbuild({
|
|
|
107
107
|
|
|
108
108
|
### Run Mode
|
|
109
109
|
|
|
110
|
+
> Deprecation warning: From v4.6.0 onward, run mode is deprecated. This logic will be ported over to `nwjs/npm-installer` repo and removed in the next major release.
|
|
111
|
+
|
|
110
112
|
```javascript
|
|
111
113
|
nwbuild({
|
|
112
114
|
mode: "run",
|
|
@@ -270,10 +272,18 @@ nwbuild({
|
|
|
270
272
|
|
|
271
273
|
### Maintainer guidelines
|
|
272
274
|
|
|
275
|
+
- Approve pull requests before merging.
|
|
276
|
+
- Enforce conventional commits before merging pull requests.
|
|
277
|
+
- A commit's first line should be formatted as `<type>[optional scope]: <description>`.
|
|
278
|
+
- A commit's body should have a description of changes in bullet points followed by any links it references or issues it fixes or closes. It may include an optional `Notes: ...` section to provide additional context on why the PR is being merged when it doesn't seem like it should.
|
|
279
|
+
- Google's Release Please Action is used to update the changelog, bump the package version and generate GitHub releases.
|
|
280
|
+
- NPM Publish Action publishes to `npm` if there is a version bump.
|
|
281
|
+
|
|
273
282
|
## Roadmap
|
|
274
283
|
|
|
275
284
|
### Bugs
|
|
276
285
|
|
|
286
|
+
- Managed Manifest is broken. If glob is disabled and srcDir has no package.json, build fails.
|
|
277
287
|
- MacOS fails to unzip MacOS NW.js binaries consistently
|
|
278
288
|
- Add back error, info, warn and debug logs
|
|
279
289
|
|
|
@@ -290,10 +300,10 @@ nwbuild({
|
|
|
290
300
|
|
|
291
301
|
### Chores
|
|
292
302
|
|
|
293
|
-
- chore(cicd): use `google-github-actions/release-please-action` to automate publishing to npm, updating changelog and creating releases
|
|
294
303
|
- chore(cli): migrate from `yargs` to `commander`
|
|
304
|
+
- chore(get): investigate [how symlinks are identified](https://github.com/overlookmotel/yauzl-promise/issues/39) and remove the workaround where they are created manually
|
|
295
305
|
- chore(get): verify sha checksum for downloads
|
|
296
|
-
- chore
|
|
306
|
+
- chore: annotate file paths as `fs.PathLike` instead of `string`.
|
|
297
307
|
- chore(bld): factor out core build step
|
|
298
308
|
- chore(bld): factor out linux config
|
|
299
309
|
- chore(bld): factor out macos config
|
|
@@ -302,6 +312,7 @@ nwbuild({
|
|
|
302
312
|
- chore(bld): factor out compressing
|
|
303
313
|
- chore(bld): factor out managed manifest
|
|
304
314
|
- chore(bld): move `.desktop` entry file logic to `create-desktop-shortcuts` package
|
|
315
|
+
- chore(util): factor out file paths as constant variables
|
|
305
316
|
|
|
306
317
|
## FAQ
|
|
307
318
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nw-builder",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.2",
|
|
4
4
|
"description": "Build NW.js desktop applications for MacOS, Windows and Linux.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NW.js",
|
|
@@ -42,9 +42,10 @@
|
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"lint": "eslint ./src/**/*.js ./test/**/*.js",
|
|
45
|
-
"lint:fix": "eslint --fix
|
|
45
|
+
"lint:fix": "eslint --fix ./src/**/*.js ./test/**/*.js",
|
|
46
|
+
"markdown:fix": "markdownlint --fix ./README.md",
|
|
46
47
|
"docs": "jsdoc -d docs ./README.md ./src/index.js ./src/get.js ./src/run.js ./src/bld.js",
|
|
47
|
-
"test": "vitest",
|
|
48
|
+
"test": "vitest run",
|
|
48
49
|
"demo": "cd test/fixture && node demo.js"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
@@ -63,7 +64,6 @@
|
|
|
63
64
|
"axios": "^1.6.7",
|
|
64
65
|
"cli-progress": "^3.12.0",
|
|
65
66
|
"compressing": "^1.10.0",
|
|
66
|
-
"fs-extra": "^11.2.0",
|
|
67
67
|
"glob": "^10.3.10",
|
|
68
68
|
"node-gyp": "^10.0.1",
|
|
69
69
|
"plist": "^3.1.0",
|
package/src/bld.js
CHANGED
|
@@ -83,22 +83,24 @@ import util from "./util.js"
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* @typedef {object} BuildOptions
|
|
86
|
-
* @property {string | "latest" | "stable" | "lts"} [
|
|
87
|
-
* @property {"normal" | "sdk"} [
|
|
88
|
-
* @property {"linux" | "osx" | "win"} [
|
|
89
|
-
* @property {"ia32" | "x64" | "arm64"} [
|
|
90
|
-
* @property {string} [
|
|
91
|
-
* @property {string} [
|
|
92
|
-
* @property {string} [
|
|
93
|
-
* @property {string} [
|
|
94
|
-
* @property {LinuxRc | WinRc | OsxRc} [
|
|
95
|
-
* @property {boolean} [
|
|
96
|
-
* @property {boolean | string | object} [
|
|
97
|
-
* @property {false | "gyp"} [
|
|
98
|
-
* @property {false | "zip" | "tar" | "tgz"} [
|
|
86
|
+
* @property {string | "latest" | "stable" | "lts"} [version = "latest"] Runtime version
|
|
87
|
+
* @property {"normal" | "sdk"} [flavor = "normal"] Build flavor
|
|
88
|
+
* @property {"linux" | "osx" | "win"} [platform] Target platform
|
|
89
|
+
* @property {"ia32" | "x64" | "arm64"} [arch] Target arch
|
|
90
|
+
* @property {string} [manifestUrl = "https://nwjs.io/versions"] Manifest URL
|
|
91
|
+
* @property {string} [srcDir = "./src"] Source directory
|
|
92
|
+
* @property {string} [cacheDir = "./cache"] Cache directory
|
|
93
|
+
* @property {string} [outDir = "./out"] Out directory
|
|
94
|
+
* @property {LinuxRc | WinRc | OsxRc} [app] Platform specific rc
|
|
95
|
+
* @property {boolean} [glob = true] File globbing
|
|
96
|
+
* @property {boolean | string | object} [managedManifest = false] Manage manifest
|
|
97
|
+
* @property {false | "gyp"} [nativeAddon = false] Rebuild native modules
|
|
98
|
+
* @property {false | "zip" | "tar" | "tgz"} [zip = false] Compress built artifacts
|
|
99
99
|
*/
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
|
+
* Build NW.js application.
|
|
103
|
+
*
|
|
102
104
|
* @async
|
|
103
105
|
* @function
|
|
104
106
|
* @param {BuildOptions} options - Build options
|
package/src/get/decompress.js
CHANGED
|
@@ -4,7 +4,6 @@ import stream from "node:stream";
|
|
|
4
4
|
|
|
5
5
|
import tar from "tar";
|
|
6
6
|
import yauzl from "yauzl-promise";
|
|
7
|
-
import {ensureSymlink} from "fs-extra";
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Decompresses a file at `filePath` to `cacheDir` directory.
|
|
@@ -24,73 +23,74 @@ export default async function decompress(filePath, cacheDir) {
|
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
/**
|
|
27
|
-
*
|
|
26
|
+
* Get file mode from entry. Reference implementation is [here](https://github.com/fpsqdb/zip-lib/blob/ac447d269218d396e05cd7072d0e9cd82b5ec52c/src/unzip.ts#L380).
|
|
28
27
|
*
|
|
29
|
-
* @
|
|
30
|
-
* @
|
|
31
|
-
* @param {string} zippedFile - file path to .zip file
|
|
32
|
-
* @param {string} cacheDir - directory to unzip in
|
|
33
|
-
* @return {Promise<void>}
|
|
28
|
+
* @param {yauzl.Entry} entry - Yauzl entry
|
|
29
|
+
* @return {number} - entry's file mode
|
|
34
30
|
*/
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
function modeFromEntry(entry) {
|
|
32
|
+
const attr = entry.externalFileAttributes >> 16 || 33188;
|
|
33
|
+
|
|
34
|
+
return [448 /* S_IRWXU */, 56 /* S_IRWXG */, 7 /* S_IRWXO */]
|
|
35
|
+
.map(mask => attr & mask)
|
|
36
|
+
.reduce((a, b) => a + b, attr & 61440 /* S_IFMT */);
|
|
39
37
|
}
|
|
40
38
|
|
|
41
39
|
/**
|
|
42
|
-
*
|
|
40
|
+
* Unzip `zippedFile` to `cacheDir`.
|
|
43
41
|
*
|
|
44
42
|
* @async
|
|
45
43
|
* @function
|
|
46
|
-
* @param
|
|
47
|
-
* @param {string}
|
|
48
|
-
* @param {string} cacheDir - directory to unzip in
|
|
49
|
-
* @param {boolean} unzipSymlink - Using or not symlink
|
|
44
|
+
* @param {string} zippedFile - file path to .zip file
|
|
45
|
+
* @param {string} cacheDir - directory to unzip in
|
|
50
46
|
* @return {Promise<void>}
|
|
51
47
|
*/
|
|
52
|
-
async function
|
|
48
|
+
async function unzip(zippedFile, cacheDir) {
|
|
53
49
|
const zip = await yauzl.open(zippedFile);
|
|
54
|
-
|
|
55
50
|
let entry = await zip.readEntry();
|
|
51
|
+
const symlinks = []; // Array to hold symbolic link entries
|
|
56
52
|
|
|
57
53
|
while (entry !== null) {
|
|
58
|
-
// console.log(entry)
|
|
59
54
|
let entryPathAbs = path.join(cacheDir, entry.filename);
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
const readStream = await entry.openReadStream();
|
|
55
|
+
// Check if entry is a symbolic link
|
|
56
|
+
const isSymlink = ((modeFromEntry(entry) & 0o170000) === 0o120000);
|
|
63
57
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
if (isSymlink) {
|
|
59
|
+
// Store symlink entries to process later
|
|
60
|
+
symlinks.push(entry);
|
|
61
|
+
} else {
|
|
62
|
+
// Handle regular files and directories
|
|
63
|
+
await fs.promises.mkdir(path.dirname(entryPathAbs), {recursive: true});
|
|
64
|
+
if (!entry.filename.endsWith('/')) { // Skip directories
|
|
65
|
+
const readStream = await entry.openReadStream();
|
|
67
66
|
const writeStream = fs.createWriteStream(entryPathAbs);
|
|
68
67
|
await stream.promises.pipeline(readStream, writeStream);
|
|
69
|
-
} else {
|
|
70
|
-
// Need check before if file is a symlink or not at this point
|
|
71
|
-
const pathContent = await fs.promises.lstat(entryPathAbs);
|
|
72
68
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
await stream.promises.finished(readStream);
|
|
77
|
-
// need fetch value of current symlink here
|
|
78
|
-
const linkTarget = Buffer.concat(chunks).toString('utf8').trim();
|
|
79
|
-
await ensureSymlink(entryPathAbs, path.join(path.dirname(entryPathAbs), linkTarget));
|
|
80
|
-
}else{
|
|
81
|
-
// Regular method and silent error at this point
|
|
82
|
-
const writeStream = fs.createWriteStream(entryPathAbs);
|
|
83
|
-
await stream.promises.pipeline(readStream, writeStream);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
} catch (error) {
|
|
87
|
-
if (unzipSymlink) {
|
|
88
|
-
console.error(error);
|
|
69
|
+
// Set file permissions after the file has been written
|
|
70
|
+
const mode = modeFromEntry(entry);
|
|
71
|
+
await fs.promises.chmod(entryPathAbs, mode);
|
|
89
72
|
}
|
|
90
73
|
}
|
|
91
74
|
|
|
75
|
+
// Read next entry
|
|
92
76
|
entry = await zip.readEntry();
|
|
93
77
|
}
|
|
94
78
|
|
|
95
|
-
|
|
79
|
+
// Process symbolic links after all other files have been extracted
|
|
80
|
+
for (const symlinkEntry of symlinks) {
|
|
81
|
+
let entryPathAbs = path.join(cacheDir, symlinkEntry.filename);
|
|
82
|
+
const readStream = await symlinkEntry.openReadStream();
|
|
83
|
+
const chunks = [];
|
|
84
|
+
readStream.on("data", (chunk) => chunks.push(chunk));
|
|
85
|
+
await new Promise(resolve => readStream.on("end", resolve));
|
|
86
|
+
const linkTarget = Buffer.concat(chunks).toString('utf8').trim();
|
|
87
|
+
|
|
88
|
+
// Check if the symlink or a file/directory already exists at the destination
|
|
89
|
+
if (fs.existsSync(entryPathAbs)) {
|
|
90
|
+
//skip
|
|
91
|
+
} else {
|
|
92
|
+
// Create symbolic link
|
|
93
|
+
await fs.promises.symlink(linkTarget, entryPathAbs);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
96
|
}
|
package/src/get/index.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import decompress from "./decompress.js";
|
|
5
|
+
import ffmpeg from "./ffmpeg.js";
|
|
6
|
+
import node from "./node.js";
|
|
7
|
+
import nw from "./nw.js";
|
|
8
|
+
|
|
9
|
+
import util from "../util.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {object} GetOptions
|
|
13
|
+
* @property {string | "latest" | "stable" | "lts"} [version = "latest"] Runtime version
|
|
14
|
+
* @property {"normal" | "sdk"} [flavor = "normal"] Build flavor
|
|
15
|
+
* @property {"linux" | "osx" | "win"} [platform] Target platform
|
|
16
|
+
* @property {"ia32" | "x64" | "arm64"} [arch] Target arch
|
|
17
|
+
* @property {string} [downloadUrl = "https://dl.nwjs.io"] Download server
|
|
18
|
+
* @property {string} [cacheDir = "./cache"] Cache directory
|
|
19
|
+
* @property {boolean} [cache = true] If false, remove cache and redownload.
|
|
20
|
+
* @property {boolean} [ffmpeg = false] If true, ffmpeg is not downloaded.
|
|
21
|
+
* @property {false | "gyp"} [nativeAddon = false] Rebuild native modules
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get binaries.
|
|
26
|
+
*
|
|
27
|
+
* @async
|
|
28
|
+
* @function
|
|
29
|
+
* @param {GetOptions} options Get mode options
|
|
30
|
+
* @return {Promise<void>}
|
|
31
|
+
*/
|
|
32
|
+
async function get(options) {
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* If `options.cacheDir` exists, then `true`. Otherwise, it is `false`.
|
|
36
|
+
*
|
|
37
|
+
* @type {boolean}
|
|
38
|
+
*/
|
|
39
|
+
const cacheDirExists = await util.fileExists(options.cacheDir);
|
|
40
|
+
if (cacheDirExists === false) {
|
|
41
|
+
await fs.promises.mkdir(options.cacheDir, { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* File path to compressed binary.
|
|
46
|
+
*
|
|
47
|
+
* @type {string}
|
|
48
|
+
*/
|
|
49
|
+
let nwFilePath = path.resolve(
|
|
50
|
+
options.cacheDir,
|
|
51
|
+
`nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}.${options.platform === "linux" ? "tar.gz" : "zip"
|
|
52
|
+
}`,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* File path to directory which contain NW.js and related binaries.
|
|
57
|
+
*
|
|
58
|
+
* @type {string}
|
|
59
|
+
*/
|
|
60
|
+
let nwDirPath = path.resolve(
|
|
61
|
+
options.cacheDir,
|
|
62
|
+
`nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}`,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// If `options.cache` is false, then remove the compressed binary.
|
|
66
|
+
if (options.cache === false) {
|
|
67
|
+
await fs.promises.rm(nwFilePath, {
|
|
68
|
+
recursive: true,
|
|
69
|
+
force: true,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// We remove the nwDir to prevent the edge case where you download with ffmpeg flag enabled
|
|
74
|
+
// but want a subsequent build with ffmpeg flag disabled. By removing the directory and
|
|
75
|
+
// decompressing it again, we prevent the community ffmpeg files from being left over.
|
|
76
|
+
// This is important since the community ffmpeg builds have specific licensing constraints.
|
|
77
|
+
await fs.promises.rm(nwDirPath, { recursive: true, force: true });
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* If the compressed binary exists, then `true`. Otherwise, it is `false`.
|
|
81
|
+
*
|
|
82
|
+
* @type {boolean}
|
|
83
|
+
*/
|
|
84
|
+
const nwFilePathExists = await util.fileExists(nwFilePath);
|
|
85
|
+
if (nwFilePathExists === false) {
|
|
86
|
+
nwFilePath = await nw(options.downloadUrl, options.version, options.flavor, options.platform, options.arch, options.cacheDir);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
await decompress(nwFilePath, options.cacheDir);
|
|
90
|
+
|
|
91
|
+
if (options.ffmpeg === true) {
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* File path to compressed binary which contains community FFmpeg binary.
|
|
95
|
+
*
|
|
96
|
+
* @type {string}
|
|
97
|
+
*/
|
|
98
|
+
let ffmpegFilePath = path.resolve(
|
|
99
|
+
options.cacheDir,
|
|
100
|
+
`ffmpeg-${options.version}-${options.platform}-${options.arch}.zip`,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// If `options.cache` is false, then remove the compressed binary.
|
|
104
|
+
if (options.cache === false) {
|
|
105
|
+
await fs.promises.rm(ffmpegFilePath, {
|
|
106
|
+
recursive: true,
|
|
107
|
+
force: true,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* If the compressed binary exists, then `true`. Otherwise, it is `false`.
|
|
113
|
+
*
|
|
114
|
+
* @type {boolean}
|
|
115
|
+
*/
|
|
116
|
+
const ffmpegFilePathExists = await util.fileExists(ffmpegFilePath);
|
|
117
|
+
if (ffmpegFilePathExists === false) {
|
|
118
|
+
// Do not update the options.downloadUrl with the ffmpeg URL here. Doing so would lead to error when options.ffmpeg and options.nativeAddon are both enabled.
|
|
119
|
+
const downloadUrl =
|
|
120
|
+
"https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download";
|
|
121
|
+
ffmpegFilePath = await ffmpeg(downloadUrl, options.version, options.platform, options.arch, options.cacheDir);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
await decompress(ffmpegFilePath, options.cacheDir);
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Platform dependant file name of FFmpeg binary.
|
|
128
|
+
*
|
|
129
|
+
* @type {string}
|
|
130
|
+
*/
|
|
131
|
+
let ffmpegFileName = "";
|
|
132
|
+
|
|
133
|
+
if (options.platform === "linux") {
|
|
134
|
+
ffmpegFileName = "libffmpeg.so";
|
|
135
|
+
} else if (options.platform === "win") {
|
|
136
|
+
ffmpegFileName = "ffmpeg.dll";
|
|
137
|
+
} else if (options.platform === "osx") {
|
|
138
|
+
ffmpegFileName = "libffmpeg.dylib";
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* File path to platform specific FFmpeg file.
|
|
143
|
+
*
|
|
144
|
+
* @type {string}
|
|
145
|
+
*/
|
|
146
|
+
let ffmpegBinaryPath = path.resolve(nwDirPath, ffmpegFileName);
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* File path of where FFmpeg will be copied to.
|
|
150
|
+
*
|
|
151
|
+
* @type {string}
|
|
152
|
+
*/
|
|
153
|
+
let ffmpegBinaryDest = "";
|
|
154
|
+
|
|
155
|
+
if (options.platform === "linux") {
|
|
156
|
+
ffmpegBinaryDest = path.resolve(nwDirPath, "lib", ffmpegFileName);
|
|
157
|
+
} else if (options.platform === "win") {
|
|
158
|
+
// Extracted file is already in the correct path
|
|
159
|
+
} else if (options.platform === "osx") {
|
|
160
|
+
ffmpegBinaryDest = path.resolve(
|
|
161
|
+
nwDirPath,
|
|
162
|
+
"nwjs.app",
|
|
163
|
+
"Contents",
|
|
164
|
+
"Frameworks",
|
|
165
|
+
"nwjs Framework.framework",
|
|
166
|
+
"Versions",
|
|
167
|
+
"Current",
|
|
168
|
+
ffmpegFileName,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
await fs.promises.copyFile(ffmpegBinaryPath, ffmpegBinaryDest);
|
|
173
|
+
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (options.nativeAddon === "gyp") {
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* File path to NW'js Node headers tarball.
|
|
180
|
+
*
|
|
181
|
+
* @type {string}
|
|
182
|
+
*/
|
|
183
|
+
let nodeFilePath = path.resolve(
|
|
184
|
+
options.cacheDir,
|
|
185
|
+
`headers-v${options.version}.tar.gz`,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// If `options.cache` is false, then remove the compressed binary.
|
|
189
|
+
if (options.cache === false) {
|
|
190
|
+
await fs.promises.rm(nodeFilePath, {
|
|
191
|
+
recursive: true,
|
|
192
|
+
force: true,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* If the compressed binary exists, then `true`. Otherwise, it is `false`.
|
|
198
|
+
*
|
|
199
|
+
* @type {boolean}
|
|
200
|
+
*/
|
|
201
|
+
const nodeFilePathExists = await util.fileExists(nodeFilePath);
|
|
202
|
+
if (nodeFilePathExists === false) {
|
|
203
|
+
nodeFilePath = await node(options.downloadUrl, options.version, options.cacheDir);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
await decompress(nodeFilePath, options.cacheDir);
|
|
207
|
+
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export default get;
|
package/src/index.js
CHANGED
|
@@ -3,33 +3,35 @@ import fs from "node:fs";
|
|
|
3
3
|
import fsm from "node:fs/promises";
|
|
4
4
|
|
|
5
5
|
import bld from "./bld.js";
|
|
6
|
-
import get from "./get.js";
|
|
6
|
+
import get from "./get/index.js";
|
|
7
7
|
import run from "./run.js";
|
|
8
8
|
import util from "./util.js";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {object} Options Configuration options
|
|
12
|
-
* @property {"
|
|
13
|
-
* @property {"
|
|
14
|
-
* @property {"
|
|
15
|
-
* @property {"
|
|
16
|
-
* @property {"
|
|
17
|
-
* @property {"
|
|
12
|
+
* @property {"get" | "run" | "build"} [mode="build"] Choose between get, run or build mode
|
|
13
|
+
* @property {"latest" | "stable" | string} [version="latest"] Runtime version
|
|
14
|
+
* @property {"normal" | "sdk"} [flavor="normal"] Runtime flavor
|
|
15
|
+
* @property {"linux" | "osx" | "win"} platform Host platform
|
|
16
|
+
* @property {"ia32" | "x64" | "arm64"} arch Host architecture
|
|
17
|
+
* @property {"https://dl.nwjs.io" | string} [downloadUrl="https://dl.nwjs.io"] Download server
|
|
18
|
+
* @property {"https://nwjs.io/versions" | string} [manifestUrl="https://nwjs.io/versions"] Versions manifest
|
|
19
|
+
* @property {"./cache" | string} [cacheDir="./cache"] Directory to cache NW binaries
|
|
20
|
+
* @property {"./" | string} [srcDir="./"] File paths to application code
|
|
18
21
|
* @property {"./out" | string} [outDir="./out"] Directory to store build artifacts
|
|
19
|
-
* @property {
|
|
20
|
-
* @property {
|
|
21
|
-
* @property {"https://nwjs.io/versions" | string} [manifestUrl="https://nwjs.io/versions"] URI to download manifest from
|
|
22
|
+
* @property {boolean | string | object} [managedManifest = false] Managed manifest mode
|
|
23
|
+
* @property {false | "gyp"} [nodeAddon = false] Rebuild Node native addons
|
|
22
24
|
* @property {object} app Refer to Linux/Windows Specific Options under Getting Started in the docs
|
|
23
25
|
* @property {boolean} [cache=true] If true the existing cache is used. Otherwise it removes and redownloads it.
|
|
24
|
-
* @property {boolean | "zip" | "tar" | "tgz"} [zip=false] If true, "zip", "tar" or "tgz" the outDir directory is compressed.
|
|
25
|
-
* @property {boolean} [cli=false] If true the CLI is used to glob srcDir and parse other options
|
|
26
26
|
* @property {boolean} [ffmpeg=false] If true the chromium ffmpeg is replaced by community version
|
|
27
|
-
* @property {boolean} [glob=true] If true globbing is enabled
|
|
28
|
-
* @property {"error" | "warn" | "info" | "debug"} [logLevel="info"]
|
|
27
|
+
* @property {boolean} [glob=true] If true file globbing is enabled when parsing srcDir.
|
|
28
|
+
* @property {"error" | "warn" | "info" | "debug"} [logLevel="info"] Specify level of logging.
|
|
29
|
+
* @property {boolean | "zip" | "tar" | "tgz"} [zip=false] If true, "zip", "tar" or "tgz" the outDir directory is compressed.
|
|
30
|
+
* @property {boolean} [cli=false] If true the CLI is used to parse options. This option is used internally.
|
|
29
31
|
*/
|
|
30
32
|
|
|
31
33
|
/**
|
|
32
|
-
* Main module exported
|
|
34
|
+
* Main module exported.
|
|
33
35
|
*
|
|
34
36
|
* @async
|
|
35
37
|
* @function
|
|
@@ -37,7 +39,7 @@ import util from "./util.js";
|
|
|
37
39
|
* @param {Options} options Options
|
|
38
40
|
* @return {Promise<void>}
|
|
39
41
|
*/
|
|
40
|
-
async function nwbuild
|
|
42
|
+
async function nwbuild(options) {
|
|
41
43
|
let built;
|
|
42
44
|
let releaseInfo = {};
|
|
43
45
|
let manifest = {};
|
package/src/run.js
CHANGED
|
@@ -7,19 +7,21 @@ import util from "./util.js";
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @typedef {object} RunOptions
|
|
10
|
-
* @property {string | "latest" | "stable" | "lts"} [
|
|
11
|
-
* @property {"normal" | "sdk"} [
|
|
12
|
-
* @property {"linux" | "osx" | "win"} [
|
|
13
|
-
* @property {"ia32" | "x64" | "arm64"} [
|
|
14
|
-
* @property {string} [
|
|
15
|
-
* @property {string} [
|
|
16
|
-
* @property {boolean} [
|
|
17
|
-
* @property {string[]} [
|
|
10
|
+
* @property {string | "latest" | "stable" | "lts"} [version = "latest"] Runtime version
|
|
11
|
+
* @property {"normal" | "sdk"} [flavor = "normal"] Build flavor
|
|
12
|
+
* @property {"linux" | "osx" | "win"} [platform] Target platform
|
|
13
|
+
* @property {"ia32" | "x64" | "arm64"} [arch] Target arch
|
|
14
|
+
* @property {string} [srcDir = "./src"] Source directory
|
|
15
|
+
* @property {string} [cacheDir = "./cache"] Cache directory
|
|
16
|
+
* @property {boolean} [glob = false] If true, throw error
|
|
17
|
+
* @property {string[]} [argv = []] CLI arguments
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* Run NW.js application
|
|
21
|
+
* Run NW.js application.
|
|
22
22
|
*
|
|
23
|
+
* @deprecated since v4.6.0. This logic will be ported over to `nwjs/npm-installer` repo and removed in the next major release (v5.0).
|
|
24
|
+
*
|
|
23
25
|
* @async
|
|
24
26
|
* @function
|
|
25
27
|
*
|
package/src/util.js
CHANGED
|
@@ -8,7 +8,7 @@ import * as GlobModule from "glob";
|
|
|
8
8
|
import semver from "semver";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Get manifest (array of NW release metadata) from URL
|
|
11
|
+
* Get manifest (array of NW release metadata) from URL.
|
|
12
12
|
*
|
|
13
13
|
* @param {string} manifestUrl Url to manifest
|
|
14
14
|
* @return {Promise<object | undefined>} - Manifest object
|
|
@@ -39,7 +39,7 @@ function getManifest(manifestUrl) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
* Get version specific release metadata
|
|
42
|
+
* Get version specific release metadata.
|
|
43
43
|
*
|
|
44
44
|
* @param {string} version NW version
|
|
45
45
|
* @param {string} platform NW platform
|
|
@@ -105,60 +105,7 @@ const EXE_NAME = {
|
|
|
105
105
|
};
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* @param {string} platform The platform to replace the ffmpeg file for
|
|
111
|
-
* @param {string} nwDir The directory of the nwjs installation
|
|
112
|
-
*/
|
|
113
|
-
const replaceFfmpeg = async (platform, nwDir) => {
|
|
114
|
-
let ffmpegFile;
|
|
115
|
-
if (platform === "linux") {
|
|
116
|
-
ffmpegFile = "libffmpeg.so";
|
|
117
|
-
} else if (platform === "win") {
|
|
118
|
-
ffmpegFile = "ffmpeg.dll";
|
|
119
|
-
} else if (platform === "osx") {
|
|
120
|
-
ffmpegFile = "libffmpeg.dylib";
|
|
121
|
-
}
|
|
122
|
-
const src = path.resolve(nwDir, ffmpegFile);
|
|
123
|
-
if (platform === "linux") {
|
|
124
|
-
const dest = path.resolve(nwDir, "lib", ffmpegFile);
|
|
125
|
-
await fs.promises.copyFile(src, dest);
|
|
126
|
-
} else if (platform === "win") {
|
|
127
|
-
// don't do anything for windows because the extracted file is already in the correct path
|
|
128
|
-
// await copyFile(src, path.resolve(nwDir, ffmpegFile));
|
|
129
|
-
} else if (platform === "osx") {
|
|
130
|
-
let dest = path.resolve(
|
|
131
|
-
nwDir,
|
|
132
|
-
"nwjs.app",
|
|
133
|
-
"Contents",
|
|
134
|
-
"Frameworks",
|
|
135
|
-
"nwjs Framework.framework",
|
|
136
|
-
"Versions",
|
|
137
|
-
"Current",
|
|
138
|
-
ffmpegFile,
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
await fs.promises.copyFile(src, dest);
|
|
143
|
-
} catch (e) {
|
|
144
|
-
//some versions of node/macOS complain about destination being a file, and others complain when it is only a directory.
|
|
145
|
-
//the only thing I can think to do is to try both
|
|
146
|
-
dest = path.resolve(
|
|
147
|
-
nwDir,
|
|
148
|
-
"nwjs.app",
|
|
149
|
-
"Contents",
|
|
150
|
-
"Frameworks",
|
|
151
|
-
"nwjs Framework.framework",
|
|
152
|
-
"Versions",
|
|
153
|
-
"Current",
|
|
154
|
-
);
|
|
155
|
-
await fs.promises.copyFile(src, dest);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Glob files
|
|
108
|
+
* Glob files.
|
|
162
109
|
*
|
|
163
110
|
* @async
|
|
164
111
|
* @function
|
|
@@ -187,6 +134,8 @@ async function globFiles({
|
|
|
187
134
|
}
|
|
188
135
|
|
|
189
136
|
/**
|
|
137
|
+
* Get Node manifest.
|
|
138
|
+
*
|
|
190
139
|
* @async
|
|
191
140
|
* @function
|
|
192
141
|
* @param {object} options - node manifest options
|
|
@@ -325,7 +274,7 @@ export const parse = async (options, pkg) => {
|
|
|
325
274
|
};
|
|
326
275
|
|
|
327
276
|
/**
|
|
328
|
-
* Validate options
|
|
277
|
+
* Validate options.
|
|
329
278
|
*
|
|
330
279
|
* @param {import("../index.js").Options} options Options
|
|
331
280
|
* @param {object} releaseInfo Version specific NW release info
|
|
@@ -468,6 +417,7 @@ async function getPath(type, options) {
|
|
|
468
417
|
}
|
|
469
418
|
|
|
470
419
|
/**
|
|
420
|
+
* Check if file exists at specified path.
|
|
471
421
|
*
|
|
472
422
|
* @param {string} filePath - File path to check existence of
|
|
473
423
|
* @return {Promise<boolean>} `true` if exists, otherwise `false`
|
|
@@ -482,4 +432,4 @@ async function fileExists(filePath) {
|
|
|
482
432
|
return exists;
|
|
483
433
|
}
|
|
484
434
|
|
|
485
|
-
export default { fileExists, getReleaseInfo, getPath, PLATFORM_KV, ARCH_KV, EXE_NAME,
|
|
435
|
+
export default { fileExists, getReleaseInfo, getPath, PLATFORM_KV, ARCH_KV, EXE_NAME, globFiles, getNodeManifest, parse, validate };
|
package/src/get.js
DELETED
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import https from "node:https";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
|
|
5
|
-
import progress from "cli-progress";
|
|
6
|
-
import tar from "tar";
|
|
7
|
-
|
|
8
|
-
import decompress, { unzip } from "./get/decompress.js";
|
|
9
|
-
import nw from "./get/nw.js";
|
|
10
|
-
|
|
11
|
-
import util from "./util.js";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @typedef {object} GetOptions
|
|
15
|
-
* @property {string | "latest" | "stable" | "lts"} [version = "latest"] Runtime version
|
|
16
|
-
* @property {"normal" | "sdk"} [flavor = "normal"] Build flavor
|
|
17
|
-
* @property {"linux" | "osx" | "win"} [platform] Target platform
|
|
18
|
-
* @property {"ia32" | "x64" | "arm64"} [arch] Target arch
|
|
19
|
-
* @property {string} [downloadUrl = "https://dl.nwjs.io"] Download server
|
|
20
|
-
* @property {string} [cacheDir = "./cache"] Cache directory
|
|
21
|
-
* @property {boolean} [cache = true] If false, remove cache and redownload.
|
|
22
|
-
* @property {boolean} [ffmpeg = false] If true, ffmpeg is not downloaded.
|
|
23
|
-
* @property {false | "gyp"} [nativeAddon = false] Rebuild native modules
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Get binaries.
|
|
28
|
-
*
|
|
29
|
-
* @async
|
|
30
|
-
* @function
|
|
31
|
-
* @param {GetOptions} options Get mode options
|
|
32
|
-
* @return {Promise<void>}
|
|
33
|
-
*/
|
|
34
|
-
async function get(options) {
|
|
35
|
-
|
|
36
|
-
const cacheDirExists = await util.fileExists(options.cacheDir);
|
|
37
|
-
if (cacheDirExists === false) {
|
|
38
|
-
await fs.promises.mkdir(options.cacheDir, { recursive: true });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let nwFilePath = path.resolve(
|
|
42
|
-
options.cacheDir,
|
|
43
|
-
`nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}.${options.platform === "linux" ? "tar.gz" : "zip"
|
|
44
|
-
}`,
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
let nwDirPath = path.resolve(
|
|
48
|
-
options.cacheDir,
|
|
49
|
-
`nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}`,
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
if (options.cache === false) {
|
|
53
|
-
await fs.promises.rm(nwFilePath, {
|
|
54
|
-
recursive: true,
|
|
55
|
-
force: true,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (util.fileExists(nwFilePath)) {
|
|
60
|
-
nwFilePath = await nw(options.downloadUrl, options.version, options.flavor, options.platform, options.arch, options.cacheDir);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
await fs.promises.rm(nwDirPath, { recursive: true, force: true });
|
|
64
|
-
|
|
65
|
-
await decompress(nwFilePath, options.cacheDir);
|
|
66
|
-
|
|
67
|
-
if (options.platform === "osx") {
|
|
68
|
-
await createSymlinks(options);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (options.ffmpeg === true) {
|
|
72
|
-
await getFfmpeg(options);
|
|
73
|
-
}
|
|
74
|
-
if (options.nativeAddon === "gyp") {
|
|
75
|
-
await getNodeHeaders(options);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const getFfmpeg = async (options) => {
|
|
80
|
-
const nwDir = path.resolve(
|
|
81
|
-
options.cacheDir,
|
|
82
|
-
`nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}`,
|
|
83
|
-
);
|
|
84
|
-
const bar = new progress.SingleBar({}, progress.Presets.rect);
|
|
85
|
-
|
|
86
|
-
// If options.ffmpeg is true, then download ffmpeg.
|
|
87
|
-
options.downloadUrl = "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download";
|
|
88
|
-
let url = `${options.downloadUrl}/${options.version}/${options.version}-${options.platform}-${options.arch}.zip`;
|
|
89
|
-
const out = path.resolve(options.cacheDir, `ffmpeg-v${options.version}-${options.platform}-${options.arch}.zip`);
|
|
90
|
-
|
|
91
|
-
// If options.cache is false, remove cache.
|
|
92
|
-
if (options.cache === false) {
|
|
93
|
-
await fs.promises.rm(out, {
|
|
94
|
-
recursive: true,
|
|
95
|
-
force: true,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Check if cache exists.
|
|
100
|
-
if (fs.existsSync(out) === true) {
|
|
101
|
-
await util.unzip(out, nwDir);
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const stream = fs.createWriteStream(out);
|
|
106
|
-
const request = new Promise((res, rej) => {
|
|
107
|
-
https.get(url, (response) => {
|
|
108
|
-
// For GitHub releases and mirrors, we need to follow the redirect.
|
|
109
|
-
url = response.headers.location;
|
|
110
|
-
|
|
111
|
-
https.get(url, (response) => {
|
|
112
|
-
let chunks = 0;
|
|
113
|
-
bar.start(Number(response.headers["content-length"]), 0);
|
|
114
|
-
response.on("data", (chunk) => {
|
|
115
|
-
chunks += chunk.length;
|
|
116
|
-
bar.increment();
|
|
117
|
-
bar.update(chunks);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
response.on("error", (error) => {
|
|
121
|
-
rej(error);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
response.on("end", () => {
|
|
125
|
-
bar.stop();
|
|
126
|
-
res();
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
response.pipe(stream);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
response.on("error", (error) => {
|
|
133
|
-
rej(error);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// Remove compressed file after download and decompress.
|
|
139
|
-
await request;
|
|
140
|
-
await unzip(out, nwDir);
|
|
141
|
-
await util.replaceFfmpeg(options.platform, nwDir);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const getNodeHeaders = async (options) => {
|
|
145
|
-
const bar = new progress.SingleBar({}, progress.Presets.rect);
|
|
146
|
-
const out = path.resolve(
|
|
147
|
-
options.cacheDir,
|
|
148
|
-
`headers-v${options.version}-${options.platform}-${options.arch}.tar.gz`,
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
// If options.cache is false, remove cache.
|
|
152
|
-
if (options.cache === false) {
|
|
153
|
-
await fs.promises.rm(out, {
|
|
154
|
-
recursive: true,
|
|
155
|
-
force: true,
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (fs.existsSync(out) === true) {
|
|
160
|
-
await tar.extract({
|
|
161
|
-
file: out,
|
|
162
|
-
C: options.cacheDir
|
|
163
|
-
});
|
|
164
|
-
await fs.promises.rm(path.resolve(options.cacheDir, `node-v${options.version}-${options.platform}-${options.arch}`), {
|
|
165
|
-
recursive: true,
|
|
166
|
-
force: true,
|
|
167
|
-
});
|
|
168
|
-
await fs.promises.rename(
|
|
169
|
-
path.resolve(options.cacheDir, "node"),
|
|
170
|
-
path.resolve(options.cacheDir, `node-v${options.version}-${options.platform}-${options.arch}`),
|
|
171
|
-
);
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const stream = fs.createWriteStream(out);
|
|
176
|
-
const request = new Promise((res, rej) => {
|
|
177
|
-
const url = `${options.downloadUrl}/v${options.version}/nw-headers-v${options.version}.tar.gz`;
|
|
178
|
-
https.get(url, (response) => {
|
|
179
|
-
let chunks = 0;
|
|
180
|
-
bar.start(Number(response.headers["content-length"]), 0);
|
|
181
|
-
response.on("data", (chunk) => {
|
|
182
|
-
chunks += chunk.length;
|
|
183
|
-
bar.increment();
|
|
184
|
-
bar.update(chunks);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
response.on("error", (error) => {
|
|
188
|
-
rej(error);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
response.on("end", () => {
|
|
192
|
-
bar.stop();
|
|
193
|
-
res();
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
response.pipe(stream);
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
await request;
|
|
201
|
-
await tar.extract({
|
|
202
|
-
file: out,
|
|
203
|
-
C: options.cacheDir
|
|
204
|
-
});
|
|
205
|
-
await fs.promises.rename(
|
|
206
|
-
path.resolve(options.cacheDir, "node"),
|
|
207
|
-
path.resolve(options.cacheDir, `node-v${options.version}-${options.platform}-${options.arch}`),
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const createSymlinks = async (options) => {
|
|
212
|
-
let frameworksPath = path.resolve(process.cwd(), options.cacheDir, `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}`, "nwjs.app", "Contents", "Frameworks", "nwjs Framework.framework")
|
|
213
|
-
// Allow resolve cacheDir from another directory for prevent crash
|
|
214
|
-
if (!fs.lstatSync(frameworksPath).isDirectory()) {
|
|
215
|
-
frameworksPath = path.resolve(options.cacheDir, `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}`, "nwjs.app", "Contents", "Frameworks", "nwjs Framework.framework")
|
|
216
|
-
}
|
|
217
|
-
const symlinks = [
|
|
218
|
-
path.join(frameworksPath, "Helpers"),
|
|
219
|
-
path.join(frameworksPath, "Libraries"),
|
|
220
|
-
path.join(frameworksPath, "nwjs Framework"),
|
|
221
|
-
path.join(frameworksPath, "Resources"),
|
|
222
|
-
path.join(frameworksPath, "Versions", "Current"),
|
|
223
|
-
];
|
|
224
|
-
for await (const symlink of symlinks) {
|
|
225
|
-
const buffer = await fs.promises.readFile(symlink);
|
|
226
|
-
const link = buffer.toString();
|
|
227
|
-
await fs.promises.rm(symlink);
|
|
228
|
-
await fs.promises.symlink(link, symlink);
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
export default get;
|