nw-builder 4.2.3 → 4.2.4
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 +5 -0
- package/package.json +17 -65
- package/src/bld/build.js +7 -9
- package/src/bld/linuxCfg.js +27 -2
- package/src/bld/osxCfg.js +5 -5
- package/src/bld/winCfg.js +19 -3
- package/src/cli.js +1 -1
- package/src/get/decompress.js +10 -10
- package/src/get/download.js +2 -2
- package/src/get/getReleaseInfo.js +2 -2
- package/src/get/remove.js +1 -1
- package/src/index.d.ts +22 -0
- package/src/index.js +209 -0
- package/src/run/develop.js +1 -1
- package/src/util/cache.js +2 -2
- package/src/util/ffmpeg.js +2 -2
- package/src/util/files.js +1 -1
- package/src/util/osx.arm.versions.json +13 -3
- package/src/util/parse.js +6 -5
- package/src/util/platform.js +2 -2
- package/src/util/validate.js +10 -8
- package/index.js +0 -248
- package/src/util/arch.test.js +0 -9
- package/src/util/cache.test.js +0 -9
- package/src/util/platform.test.js +0 -13
package/README.md
CHANGED
|
@@ -15,3 +15,8 @@ Build [NW.js](https://github.com/nwjs/nw.js) applications for Mac, Windows and L
|
|
|
15
15
|
Check out the [documentation](https://nwutils.io/nw-builder/) if you wish to give `nw-builder` a try.
|
|
16
16
|
|
|
17
17
|
> Please note that the documentation assumes you know [how to write NW.js applications](https://nwjs.readthedocs.io/en/latest/For%20Users/Getting%20Started/).
|
|
18
|
+
|
|
19
|
+
## Alternatives
|
|
20
|
+
|
|
21
|
+
- [nw-builder-platforms](https://github.com/naviapps/nw-builder-platforms) - Fork of this repo with platform specific build options
|
|
22
|
+
- [nwjs-builder-phoenix](https://github.com/evshiron/nwjs-builder-phoenix) - Previously the most used build tool, however it is no longer maintained
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nw-builder",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.4",
|
|
4
4
|
"description": "Build NW.js desktop applications for MacOS, Windows and Linux.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NW.js",
|
|
@@ -20,20 +20,18 @@
|
|
|
20
20
|
],
|
|
21
21
|
"contributors": [
|
|
22
22
|
{
|
|
23
|
-
"name": "
|
|
23
|
+
"name": "nw-builder Contributors",
|
|
24
24
|
"url": "https://github.com/nwutil/nw-builder/graphs/contributors"
|
|
25
25
|
}
|
|
26
26
|
],
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"exports": {
|
|
29
|
-
"default": "./index.js",
|
|
30
|
-
"types": "./index.d.ts"
|
|
29
|
+
"default": "./src/index.js",
|
|
30
|
+
"types": "./src/index.d.ts"
|
|
31
31
|
},
|
|
32
32
|
"type": "module",
|
|
33
33
|
"files": [
|
|
34
|
-
"./
|
|
35
|
-
"./src",
|
|
36
|
-
"./LICENSE"
|
|
34
|
+
"./src"
|
|
37
35
|
],
|
|
38
36
|
"homepage": "https://github.com/nwutils/nw-builder",
|
|
39
37
|
"repository": {
|
|
@@ -42,35 +40,29 @@
|
|
|
42
40
|
},
|
|
43
41
|
"scripts": {
|
|
44
42
|
"fmt": "prettier --write \"./**/*.{css,html,js,json,md,yml}\"",
|
|
45
|
-
"lnt": "eslint --fix
|
|
46
|
-
"doc:
|
|
47
|
-
"doc:dev": "vitepress dev
|
|
48
|
-
"doc:bld": "vitepress build
|
|
49
|
-
"doc:pkg": "gh-pages -d docs/.vitepress/dist",
|
|
50
|
-
"test:jest": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
43
|
+
"lnt": "eslint --config=cfg/eslint.config.cjs --fix src",
|
|
44
|
+
"doc:api": "jsdoc2md ./src/index.js > ./doc/api.md && jsdoc2md ./src/bld/linuxCfg.js > ./doc/api-nux.md && jsdoc2md ./src/bld/winCfg.js > ./doc/api-win.md",
|
|
45
|
+
"doc:dev": "vitepress dev doc",
|
|
46
|
+
"doc:bld": "vitepress build doc",
|
|
51
47
|
"test:unit": "node --test-reporter=spec --test test/unit/index.js",
|
|
52
|
-
"test:e2e": "node --test-reporter=spec --test e2e/index.js",
|
|
53
|
-
"test:
|
|
54
|
-
"test:manual:dev": "cd test/fixture && nwbuild --mode=run --version=0.74.0 ./app --no-glob",
|
|
55
|
-
"test:manual:bld": "cd test/fixture && nwbuild --mode=build --version=0.74.0 ./app --no-glob"
|
|
48
|
+
"test:e2e": "node --test-reporter=spec --test test/e2e/index.js",
|
|
49
|
+
"test:demo": "cd test/fixture && node demo.js"
|
|
56
50
|
},
|
|
57
51
|
"devDependencies": {
|
|
58
|
-
"eslint": "^8.
|
|
52
|
+
"eslint": "^8.42.0",
|
|
59
53
|
"eslint-config-tjw-jsdoc": "^1.0.3",
|
|
60
54
|
"gh-pages": "^5.0.0",
|
|
61
|
-
"jest": "^29.4.3",
|
|
62
|
-
"jest-environment-jsdom": "^29.4.3",
|
|
63
55
|
"jsdoc": "^4.0.2",
|
|
64
|
-
"
|
|
56
|
+
"jsdoc-to-markdown": "^8.0.0",
|
|
65
57
|
"prettier": "^2.8.6",
|
|
66
|
-
"selenium-webdriver": "^4.
|
|
67
|
-
"vitepress": "^1.0.0-
|
|
58
|
+
"selenium-webdriver": "^4.10.0",
|
|
59
|
+
"vitepress": "^1.0.0-beta.2"
|
|
68
60
|
},
|
|
69
61
|
"dependencies": {
|
|
70
62
|
"archiver": "^5.3.1",
|
|
71
63
|
"cli-progress": "^3.12.0",
|
|
72
|
-
"
|
|
73
|
-
"glob": "^
|
|
64
|
+
"compressing": "^1.9.0",
|
|
65
|
+
"glob": "^10.2.7",
|
|
74
66
|
"plist": "^3.0.6",
|
|
75
67
|
"rcedit": "^3.0.1",
|
|
76
68
|
"winston": "^3.8.2",
|
|
@@ -78,45 +70,5 @@
|
|
|
78
70
|
},
|
|
79
71
|
"bin": {
|
|
80
72
|
"nwbuild": "./src/cli.js"
|
|
81
|
-
},
|
|
82
|
-
"prettier": {
|
|
83
|
-
"printWidth": 80,
|
|
84
|
-
"tabWidth": 2,
|
|
85
|
-
"useTabs": false,
|
|
86
|
-
"semi": true,
|
|
87
|
-
"singleQuote": false,
|
|
88
|
-
"quoteProps": "consistent",
|
|
89
|
-
"trailingComma": "all",
|
|
90
|
-
"bracketSpacing": true,
|
|
91
|
-
"bracketSameLine": false,
|
|
92
|
-
"arrowParens": "always",
|
|
93
|
-
"proseWrap": "preserve",
|
|
94
|
-
"htmlWhitespaceSensitivity": "strict",
|
|
95
|
-
"endOfLine": "lf",
|
|
96
|
-
"singleAttributePerLine": true
|
|
97
|
-
},
|
|
98
|
-
"eslintConfig": {
|
|
99
|
-
"parserOptions": {
|
|
100
|
-
"ecmaVersion": 2023,
|
|
101
|
-
"sourceType": "module"
|
|
102
|
-
},
|
|
103
|
-
"env": {
|
|
104
|
-
"es6": true,
|
|
105
|
-
"node": true,
|
|
106
|
-
"jest": true
|
|
107
|
-
},
|
|
108
|
-
"extends": [
|
|
109
|
-
"eslint:recommended",
|
|
110
|
-
"tjw-jsdoc"
|
|
111
|
-
],
|
|
112
|
-
"rules": {
|
|
113
|
-
"jsdoc/require-file-overview": "off",
|
|
114
|
-
"jsdoc/require-returns-description": "off",
|
|
115
|
-
"jsdoc/match-description": "off",
|
|
116
|
-
"jsdoc/valid-types": "off"
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
"jest": {
|
|
120
|
-
"testEnvironment": "jsdom"
|
|
121
73
|
}
|
|
122
74
|
}
|
package/src/bld/build.js
CHANGED
|
@@ -29,7 +29,7 @@ export const build = async (
|
|
|
29
29
|
zip,
|
|
30
30
|
releaseInfo,
|
|
31
31
|
app,
|
|
32
|
-
nwPkg
|
|
32
|
+
nwPkg
|
|
33
33
|
) => {
|
|
34
34
|
log.debug(`Remove any files at ${outDir} directory`);
|
|
35
35
|
await rm(outDir, { force: true, recursive: true });
|
|
@@ -43,11 +43,9 @@ export const build = async (
|
|
|
43
43
|
files,
|
|
44
44
|
resolve(
|
|
45
45
|
outDir,
|
|
46
|
-
platform !== "osx"
|
|
47
|
-
? "package.nw"
|
|
48
|
-
: "nwjs.app/Contents/Resources/app.nw",
|
|
46
|
+
platform !== "osx" ? "package.nw" : "nwjs.app/Contents/Resources/app.nw"
|
|
49
47
|
),
|
|
50
|
-
{ recursive: true }
|
|
48
|
+
{ recursive: true, verbatimSymlinks: true }
|
|
51
49
|
);
|
|
52
50
|
} else {
|
|
53
51
|
for (let file of files) {
|
|
@@ -59,9 +57,9 @@ export const build = async (
|
|
|
59
57
|
platform !== "osx"
|
|
60
58
|
? "package.nw"
|
|
61
59
|
: "nwjs.app/Contents/Resources/app.nw",
|
|
62
|
-
file
|
|
60
|
+
file
|
|
63
61
|
),
|
|
64
|
-
{ recursive: true }
|
|
62
|
+
{ recursive: true, verbatimSymlinks: true }
|
|
65
63
|
);
|
|
66
64
|
}
|
|
67
65
|
|
|
@@ -74,10 +72,10 @@ export const build = async (
|
|
|
74
72
|
platform !== "osx"
|
|
75
73
|
? "package.nw"
|
|
76
74
|
: "nwjs.app/Contents/Resources/app.nw",
|
|
77
|
-
"package.json"
|
|
75
|
+
"package.json"
|
|
78
76
|
),
|
|
79
77
|
JSON.stringify(nwPkg, null, 2),
|
|
80
|
-
"utf8"
|
|
78
|
+
"utf8"
|
|
81
79
|
);
|
|
82
80
|
}
|
|
83
81
|
|
package/src/bld/linuxCfg.js
CHANGED
|
@@ -3,18 +3,43 @@ import { rename, writeFile } from "node:fs/promises";
|
|
|
3
3
|
|
|
4
4
|
import { log } from "../log.js";
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {object} LinuxRc Linux configuration options
|
|
8
|
+
* @property {string} genericName Generic name of the application
|
|
9
|
+
* @property {boolean} noDisplay If true the application is not displayed
|
|
10
|
+
* @property {string} comment Tooltip for the entry, for example "View sites on the Internet".
|
|
11
|
+
* @property {string} icon Icon to display in file manager, menus, etc.
|
|
12
|
+
* @property {boolean} hidden TBD
|
|
13
|
+
* @property {string[]} onlyShowIn A list of strings identifying the desktop environments that should (/not) display a given desktop entry
|
|
14
|
+
* @property {string[]} notShowIn A list of strings identifying the desktop environments that should (/not) display a given desktop entry
|
|
15
|
+
* @property {boolean} dBusActivatable A boolean value specifying if D-Bus activation is supported for this application
|
|
16
|
+
* @property {string} tryExec Path to an executable file on disk used to determine if the program is actually installed
|
|
17
|
+
* @property {string} exec Program to execute, possibly with arguments.
|
|
18
|
+
* @property {string} path If entry is of type Application, the working directory to run the program in.
|
|
19
|
+
* @property {boolean} terminal Whether the program runs in a terminal window.
|
|
20
|
+
* @property {string[]} actions Identifiers for application actions.
|
|
21
|
+
* @property {string[]} mimeType The MIME type(s) supported by this application.
|
|
22
|
+
* @property {string[]} categories Categories in which the entry should be shown in a menu
|
|
23
|
+
* @property {string[]} implements A list of interfaces that this application implements.
|
|
24
|
+
* @property {string[]} keywords A list of strings which may be used in addition to other metadata to describe this entry.
|
|
25
|
+
* @property {boolean} startupNotify If true, it is KNOWN that the application will send a "remove" message when started with the DESKTOP_STARTUP_ID environment variable set. If false, it is KNOWN that the application does not work with startup notification at all.
|
|
26
|
+
* @property {string} startupWMClass If specified, it is known that the application will map at least one window with the given string as its WM class or WM name hin
|
|
27
|
+
* @property {boolean} prefersNonDefaultGPU If true, the application prefers to be run on a more powerful discrete GPU if available.
|
|
28
|
+
* @property {string} singleMainWindow If true, the application has a single main window, and does not support having an additional one opened.
|
|
29
|
+
*/
|
|
30
|
+
|
|
6
31
|
/**
|
|
7
32
|
* Generates a Desktop Entry file for Linux
|
|
8
33
|
* https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html
|
|
9
34
|
*
|
|
10
|
-
* @param {
|
|
35
|
+
* @param {LinuxRc} app Resource configuration options for Linux
|
|
11
36
|
* @param {string} outDir Directory which stores build artifacts
|
|
12
37
|
* @return {Promise<void>}
|
|
13
38
|
*/
|
|
14
39
|
export const setLinuxConfig = async (app, outDir) => {
|
|
15
40
|
if (platform === "win32") {
|
|
16
41
|
log.warn(
|
|
17
|
-
"Linux apps built on Windows platform do not preserve all file permissions. See #716"
|
|
42
|
+
"Linux apps built on Windows platform do not preserve all file permissions. See #716"
|
|
18
43
|
);
|
|
19
44
|
}
|
|
20
45
|
let desktopEntryFile = {
|
package/src/bld/osxCfg.js
CHANGED
|
@@ -16,7 +16,7 @@ import { log } from "../log.js";
|
|
|
16
16
|
const setOsxConfig = async (pkg, outDir) => {
|
|
17
17
|
if (platform === "win32") {
|
|
18
18
|
log.warn(
|
|
19
|
-
"MacOS apps built on Windows platform do not preserve all file permissions. See #716"
|
|
19
|
+
"MacOS apps built on Windows platform do not preserve all file permissions. See #716"
|
|
20
20
|
);
|
|
21
21
|
}
|
|
22
22
|
try {
|
|
@@ -26,7 +26,7 @@ const setOsxConfig = async (pkg, outDir) => {
|
|
|
26
26
|
// Rename CFBundleDisplayName in Contents/Info.plist
|
|
27
27
|
const contentsInfoPlistPath = path.resolve(outApp, "Contents/Info.plist");
|
|
28
28
|
const contentsInfoPlistJson = plist.parse(
|
|
29
|
-
await fs.readFile(contentsInfoPlistPath, "utf-8")
|
|
29
|
+
await fs.readFile(contentsInfoPlistPath, "utf-8")
|
|
30
30
|
);
|
|
31
31
|
contentsInfoPlistJson.CFBundleDisplayName = pkg.name;
|
|
32
32
|
const contentsInfoPlist = plist.build(contentsInfoPlistJson);
|
|
@@ -35,15 +35,15 @@ const setOsxConfig = async (pkg, outDir) => {
|
|
|
35
35
|
// Rename CFBundleDisplayName in Contents/Resources/en.lproj/InfoPlist.strings
|
|
36
36
|
const contentsInfoPlistStringsPath = path.resolve(
|
|
37
37
|
outApp,
|
|
38
|
-
"Contents/Resources/en.lproj/InfoPlist.strings"
|
|
38
|
+
"Contents/Resources/en.lproj/InfoPlist.strings"
|
|
39
39
|
);
|
|
40
40
|
const contentsInfoPlistStrings = await fs.readFile(
|
|
41
41
|
contentsInfoPlistStringsPath,
|
|
42
|
-
"utf-8"
|
|
42
|
+
"utf-8"
|
|
43
43
|
);
|
|
44
44
|
const newPlistStrings = contentsInfoPlistStrings.replace(
|
|
45
45
|
/CFBundleGetInfoString = "nwjs /,
|
|
46
|
-
`CFBundleGetInfoString = "${pkg.name}
|
|
46
|
+
`CFBundleGetInfoString = "${pkg.name} `
|
|
47
47
|
);
|
|
48
48
|
await fs.writeFile(contentsInfoPlistStringsPath, newPlistStrings);
|
|
49
49
|
|
package/src/bld/winCfg.js
CHANGED
|
@@ -5,6 +5,22 @@ import rcedit from "rcedit";
|
|
|
5
5
|
|
|
6
6
|
import { log } from "../log.js";
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {object} WinRc Windows configuration options
|
|
10
|
+
* @property {string} comments Additional information that should be displayed for diagnostic purposes.
|
|
11
|
+
* @property {string} company Company that produced the file—for example, Microsoft Corporation or Standard Microsystems Corporation, Inc. This string is required.
|
|
12
|
+
* @property {string} fileDescription File description to be presented to users. This string may be displayed in a list box when the user is choosing files to install. For example, Keyboard Driver for AT-Style Keyboards. This string is required.
|
|
13
|
+
* @property {string} fileVersion Version number of the file. For example, 3.10 or 5.00.RC2. This string is required.
|
|
14
|
+
* @property {string} internalName Internal name of the file, if one exists—for example, a module name if the file is a dynamic-link library. If the file has no internal name, this string should be the original filename, without extension. This string is required.
|
|
15
|
+
* @property {string} legalCopyright Copyright notices that apply to the file. This should include the full text of all notices, legal symbols, copyright dates, and so on. This string is optional.
|
|
16
|
+
* @property {string} legalTrademark Trademarks and registered trademarks that apply to the file. This should include the full text of all notices, legal symbols, trademark numbers, and so on. This string is optional.
|
|
17
|
+
* @property {string} originalFilename Original name of the file, not including a path. This information enables an application to determine whether a file has been renamed by a user. The format of the name depends on the file system for which the file was created. This string is required.
|
|
18
|
+
* @property {string} privateBuild Information about a private version of the file—for example, Built by TESTER1 on \\TESTBED. This string should be present only if VS_FF_PRIVATEBUILD is specified in the fileflags parameter of the root block.
|
|
19
|
+
* @property {string} productName Name of the product with which the file is distributed. This string is required.
|
|
20
|
+
* @property {string} productVersion Version of the product with which the file is distributed—for example, 3.10 or 5.00.RC2. This string is required.
|
|
21
|
+
* @property {string} specialBuild Text that specifies how this version of the file differs from the standard version—for example, Private build for TESTER1 solving mouse problems on M250 and M250E computers. This string should be present only if VS_FF_SPECIALBUILD is specified in the fileflags parameter of the root block.
|
|
22
|
+
*/
|
|
23
|
+
|
|
8
24
|
/**
|
|
9
25
|
* Windows specific configuration steps
|
|
10
26
|
* https://learn.microsoft.com/en-us/windows/win32/msi/version
|
|
@@ -12,7 +28,7 @@ import { log } from "../log.js";
|
|
|
12
28
|
* https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2015/deployment/trustinfo-element-clickonce-application?view=vs-2015#requestedexecutionlevel
|
|
13
29
|
* https://learn.microsoft.com/en-gb/windows/win32/menurc/versioninfo-resource
|
|
14
30
|
*
|
|
15
|
-
* @param {
|
|
31
|
+
* @param {WinRc} app Resource configuration options for Windows
|
|
16
32
|
* @param {string} outDir The directory to hold build artifacts
|
|
17
33
|
*/
|
|
18
34
|
const setWinConfig = async (app, outDir) => {
|
|
@@ -42,13 +58,13 @@ const setWinConfig = async (app, outDir) => {
|
|
|
42
58
|
await rename(resolve(outDir, "nw.exe"), outDirAppExe);
|
|
43
59
|
await rcedit(outDirAppExe, {
|
|
44
60
|
"file-version": app.version,
|
|
45
|
-
|
|
61
|
+
icon: app.icon,
|
|
46
62
|
"product-version": app.version,
|
|
47
63
|
"version-string": versionString,
|
|
48
64
|
});
|
|
49
65
|
} catch (error) {
|
|
50
66
|
log.warn(
|
|
51
|
-
"Renaming EXE failed or unable to modify EXE. If it's the latter, ensure WINE is installed or build in Windows"
|
|
67
|
+
"Renaming EXE failed or unable to modify EXE. If it's the latter, ensure WINE is installed or build in Windows"
|
|
52
68
|
);
|
|
53
69
|
log.error(error);
|
|
54
70
|
}
|
package/src/cli.js
CHANGED
package/src/get/decompress.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import compressing from "compressing";
|
|
4
4
|
|
|
5
5
|
import { log } from "../log.js";
|
|
6
6
|
|
|
@@ -17,23 +17,23 @@ const decompress = async (platform, cacheDir, downloadUrl) => {
|
|
|
17
17
|
if (
|
|
18
18
|
downloadUrl === "https://dl.nwjs.io" ||
|
|
19
19
|
downloadUrl === "https://npm.taobao.org/mirrors/nwjs" ||
|
|
20
|
-
downloadUrl === "https://npmmirror.com/mirrors/nwjs"
|
|
20
|
+
downloadUrl === "https://npmmirror.com/mirrors/nwjs" ||
|
|
21
|
+
downloadUrl ===
|
|
22
|
+
"https://github.com/corwin-of-amber/nw.js/releases/download"
|
|
21
23
|
) {
|
|
22
24
|
if (platform === "linux") {
|
|
23
|
-
await
|
|
25
|
+
await compressing.tgz.uncompress(resolve(cacheDir, "nw.tgz"), cacheDir);
|
|
24
26
|
} else {
|
|
25
|
-
await
|
|
27
|
+
await compressing.zip.uncompress(resolve(cacheDir, "nw.zip"), cacheDir);
|
|
26
28
|
}
|
|
27
|
-
} else if (
|
|
28
|
-
downloadUrl ===
|
|
29
|
-
"https://github.com/corwin-of-amber/nw.js/releases/download"
|
|
30
|
-
) {
|
|
31
|
-
await Decompress(resolve(cacheDir, "nw.zip"), cacheDir);
|
|
32
29
|
} else if (
|
|
33
30
|
downloadUrl ===
|
|
34
31
|
"https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download"
|
|
35
32
|
) {
|
|
36
|
-
await
|
|
33
|
+
await compressing.zip.uncompress(
|
|
34
|
+
resolve(cacheDir, "ffmpeg.zip"),
|
|
35
|
+
cacheDir
|
|
36
|
+
);
|
|
37
37
|
}
|
|
38
38
|
} catch (error) {
|
|
39
39
|
log.error(error);
|
package/src/get/download.js
CHANGED
|
@@ -23,7 +23,7 @@ const download = (
|
|
|
23
23
|
platform,
|
|
24
24
|
architecture,
|
|
25
25
|
downloadUrl,
|
|
26
|
-
cacheDir
|
|
26
|
+
cacheDir
|
|
27
27
|
) => {
|
|
28
28
|
let url;
|
|
29
29
|
let out;
|
|
@@ -38,7 +38,7 @@ const download = (
|
|
|
38
38
|
}-v${version}-${platform}-${architecture}.${
|
|
39
39
|
platform === "linux" ? "tar.gz" : "zip"
|
|
40
40
|
}`;
|
|
41
|
-
out = resolve(cacheDir, `nw.${platform === "linux" ? "
|
|
41
|
+
out = resolve(cacheDir, `nw.${platform === "linux" ? "tgz" : "zip"}`);
|
|
42
42
|
} else if (
|
|
43
43
|
downloadUrl ===
|
|
44
44
|
"https://github.com/corwin-of-amber/nw.js/releases/download"
|
|
@@ -20,7 +20,7 @@ export const getReleaseInfo = async (
|
|
|
20
20
|
platform,
|
|
21
21
|
arch,
|
|
22
22
|
cacheDir,
|
|
23
|
-
manifestUrl
|
|
23
|
+
manifestUrl
|
|
24
24
|
) => {
|
|
25
25
|
let releaseData = undefined;
|
|
26
26
|
let manifestPath = undefined;
|
|
@@ -47,7 +47,7 @@ export const getReleaseInfo = async (
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
releaseData = manifest.versions.find(
|
|
50
|
-
(release) => release.version === `v${version}
|
|
50
|
+
(release) => release.version === `v${version}`
|
|
51
51
|
);
|
|
52
52
|
}
|
|
53
53
|
return releaseData;
|
package/src/get/remove.js
CHANGED
|
@@ -15,7 +15,7 @@ const remove = async (platform, cacheDir, downloadUrl) => {
|
|
|
15
15
|
try {
|
|
16
16
|
if (downloadUrl === "https://dl.nwjs.io/") {
|
|
17
17
|
if (platform === "linux") {
|
|
18
|
-
await rm(resolve(cacheDir, "nw.
|
|
18
|
+
await rm(resolve(cacheDir, "nw.tgz"));
|
|
19
19
|
} else {
|
|
20
20
|
await rm(resolve(cacheDir, "nw.zip"));
|
|
21
21
|
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type Options = {
|
|
2
|
+
srcDir: string,
|
|
3
|
+
mode: "get" | "run" | "build",
|
|
4
|
+
version: string | "latest" | "stable",
|
|
5
|
+
flavor: "normal" | "sdk",
|
|
6
|
+
platform: "linux" | "osx" | "win",
|
|
7
|
+
arch: "ia32" | "x64" | "arm64",
|
|
8
|
+
outDir: string,
|
|
9
|
+
cacheDir: string,
|
|
10
|
+
downloadUrl: string,
|
|
11
|
+
manifestUrl: string,
|
|
12
|
+
app: object,
|
|
13
|
+
cache: boolean,
|
|
14
|
+
zip: boolean | "zip",
|
|
15
|
+
cli: boolean,
|
|
16
|
+
ffmpeg: boolean,
|
|
17
|
+
glob: boolean,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
declare function nwbuild(options: Options): Promise<unknown>;
|
|
21
|
+
|
|
22
|
+
export default nwbuild;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { mkdir, rm } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { decompress } from "./get/decompress.js";
|
|
5
|
+
import { download } from "./get/download.js";
|
|
6
|
+
import { getReleaseInfo } from "./get/getReleaseInfo.js";
|
|
7
|
+
import { remove } from "./get/remove.js";
|
|
8
|
+
import { build } from "./bld/build.js";
|
|
9
|
+
import { develop } from "./run/develop.js";
|
|
10
|
+
import { isCached } from "./util/cache.js";
|
|
11
|
+
import { replaceFfmpeg } from "./util/ffmpeg.js";
|
|
12
|
+
import { getFiles } from "./util/files.js";
|
|
13
|
+
import { getVersionManifest } from "./util/versionManifest.js";
|
|
14
|
+
import { parse } from "./util/parse.js";
|
|
15
|
+
import { validate } from "./util/validate.js";
|
|
16
|
+
import { xattr } from "./util/xattr.js";
|
|
17
|
+
|
|
18
|
+
import { log } from "./log.js";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {object} Options Configuration options
|
|
22
|
+
* @property {"./" | string} [srcDir="./"] String of space separated glob patterns which correspond to NW app code
|
|
23
|
+
* @property {"get" | "run" | "build"} [mode="build"] Run or build application
|
|
24
|
+
* @property {"latest" | "stable" | string} [version="latest"] NW runtime version
|
|
25
|
+
* @property {"normal" | "sdk"} [flavor="normal"] NW runtime build flavor
|
|
26
|
+
* @property {"linux" | "osx" | "win"} platform NW supported platforms
|
|
27
|
+
* @property {"ia32" | "x64" | "arm64"} arch NW supported architectures
|
|
28
|
+
* @property {"./out" | string} [outDir="./out"] Directory to store build artifacts
|
|
29
|
+
* @property {"./cache" | string} [cacheDir="./cache"] Directory to store NW binaries
|
|
30
|
+
* @property {"https://dl.nwjs.io" | string} [downloadUrl="https://dl.nwjs.io"] URI to download NW binaries from
|
|
31
|
+
* @property {"https://nwjs.io/versions" | string} [manifestUrl="https://nwjs.io/versions"] URI to download manifest from
|
|
32
|
+
* @property {object} app Refer to Linux/Windows Specific Options under Getting Started in the docs
|
|
33
|
+
* @property {boolean} [cache=true] If true the existing cache is used. Otherwise it removes and redownloads it.
|
|
34
|
+
* @property {boolean} [zip=false] If true the outDir directory is zipped
|
|
35
|
+
* @property {boolean} [cli=false] If true the CLI is used to glob srcDir and parse other options
|
|
36
|
+
* @property {boolean} [ffmpeg=false] If true the chromium ffmpeg is replaced by community version
|
|
37
|
+
* @property {boolean} [glob=true] If true globbing is enabled
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Automates building an NW.js application.
|
|
42
|
+
*
|
|
43
|
+
* @param {Options} options Options
|
|
44
|
+
* @return {Promise<undefined>}
|
|
45
|
+
*/
|
|
46
|
+
const nwbuild = async (options) => {
|
|
47
|
+
let nwDir = "";
|
|
48
|
+
let ffmpegFile = "";
|
|
49
|
+
let cached;
|
|
50
|
+
let nwCached;
|
|
51
|
+
let built;
|
|
52
|
+
let releaseInfo = {};
|
|
53
|
+
let files = [];
|
|
54
|
+
let manifest = {};
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
// Parse options
|
|
58
|
+
options = await parse(options, manifest);
|
|
59
|
+
|
|
60
|
+
if (options.mode !== "get") {
|
|
61
|
+
files = options.glob ? await getFiles(options.srcDir) : options.srcDir;
|
|
62
|
+
manifest = await getVersionManifest(files, options.glob);
|
|
63
|
+
if (typeof manifest?.nwbuild === "object") {
|
|
64
|
+
options = manifest.nwbuild;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
options = await parse(options, manifest);
|
|
69
|
+
|
|
70
|
+
// Create cacheDir if it does not exist
|
|
71
|
+
cached = await isCached(options.cacheDir);
|
|
72
|
+
if (cached === false) {
|
|
73
|
+
await mkdir(options.cacheDir, { recursive: true });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (options.mode !== "get" && options.mode !== "run") {
|
|
77
|
+
// Create outDir if it does not exist
|
|
78
|
+
built = await isCached(options.outDir);
|
|
79
|
+
if (built === false) {
|
|
80
|
+
await mkdir(options.outDir, { recursive: true });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Validate options.version to get the version specific release info
|
|
85
|
+
releaseInfo = await getReleaseInfo(
|
|
86
|
+
options.version,
|
|
87
|
+
options.platform,
|
|
88
|
+
options.arch,
|
|
89
|
+
options.cacheDir,
|
|
90
|
+
options.manifestUrl
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
await validate(options, releaseInfo);
|
|
94
|
+
|
|
95
|
+
// Remove leading "v" from version string
|
|
96
|
+
options.version = releaseInfo.version.slice(1);
|
|
97
|
+
|
|
98
|
+
// Variable to store nwDir file path
|
|
99
|
+
nwDir = resolve(
|
|
100
|
+
options.cacheDir,
|
|
101
|
+
`nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${
|
|
102
|
+
options.platform
|
|
103
|
+
}-${options.arch}`
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
nwCached = await isCached(nwDir);
|
|
107
|
+
// Remove cached NW binary
|
|
108
|
+
if (options.cache === false && nwCached === true) {
|
|
109
|
+
log.debug("Remove cached NW binary");
|
|
110
|
+
await rm(nwDir, { force: true, recursive: true });
|
|
111
|
+
}
|
|
112
|
+
// Download relevant NW.js binaries
|
|
113
|
+
if (nwCached === false) {
|
|
114
|
+
log.debug("Download relevant NW.js binaries");
|
|
115
|
+
await download(
|
|
116
|
+
options.version,
|
|
117
|
+
options.flavor,
|
|
118
|
+
options.platform,
|
|
119
|
+
options.arch,
|
|
120
|
+
options.downloadUrl,
|
|
121
|
+
options.cacheDir
|
|
122
|
+
);
|
|
123
|
+
await decompress(options.platform, options.cacheDir, options.downloadUrl);
|
|
124
|
+
await remove(options.platform, options.cacheDir, options.downloadUrl);
|
|
125
|
+
} else {
|
|
126
|
+
log.debug("Using cached NW.js binaries");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (options.ffmpeg === true) {
|
|
130
|
+
log.warn(
|
|
131
|
+
"Using MP3 and H.264 codecs requires you to pay attention to the patent royalties and the license of the source code. Consult a lawyer if you do not understand the licensing constraints and using patented media formats in your app. See https://chromium.googlesource.com/chromium/third_party/ffmpeg.git/+/master/CREDITS.chromium for more information."
|
|
132
|
+
);
|
|
133
|
+
if (options.platform === "win") {
|
|
134
|
+
ffmpegFile = "libffmpeg.dll";
|
|
135
|
+
} else if (options.platform === "osx") {
|
|
136
|
+
ffmpegFile = "libffmpeg.dylib";
|
|
137
|
+
} else if (options.platform === "linux") {
|
|
138
|
+
ffmpegFile = "libffmpeg.so";
|
|
139
|
+
}
|
|
140
|
+
ffmpegFile = resolve(options.cacheDir, ffmpegFile);
|
|
141
|
+
const ffmpegCached = await isCached(ffmpegFile);
|
|
142
|
+
// Remove cached ffmpeg binary
|
|
143
|
+
if (options.cache === false && ffmpegCached === true) {
|
|
144
|
+
log.debug("Remove cached ffmpeg binary");
|
|
145
|
+
await rm(ffmpegFile, { force: true, recursive: true });
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Download relevant ffmpeg binaries
|
|
149
|
+
if (ffmpegCached === false) {
|
|
150
|
+
log.debug("Download relevant ffmpeg binaries");
|
|
151
|
+
await download(
|
|
152
|
+
options.version,
|
|
153
|
+
options.flavor,
|
|
154
|
+
options.platform,
|
|
155
|
+
options.arch,
|
|
156
|
+
"https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download",
|
|
157
|
+
options.cacheDir
|
|
158
|
+
);
|
|
159
|
+
await decompress(
|
|
160
|
+
options.platform,
|
|
161
|
+
options.cacheDir,
|
|
162
|
+
"https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download"
|
|
163
|
+
);
|
|
164
|
+
await remove(
|
|
165
|
+
options.platform,
|
|
166
|
+
options.cacheDir,
|
|
167
|
+
"https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download"
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
await replaceFfmpeg(options.platform, nwDir, ffmpegFile);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
await xattr(options.platform, options.arch, nwDir);
|
|
175
|
+
|
|
176
|
+
// Downloading binaries is required for run and build modes
|
|
177
|
+
// If mode is get, exit function since we have gotten the binaries
|
|
178
|
+
if (options.mode === "get") {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (options.mode === "run") {
|
|
183
|
+
await develop(
|
|
184
|
+
options.srcDir,
|
|
185
|
+
nwDir,
|
|
186
|
+
options.platform,
|
|
187
|
+
options.argv,
|
|
188
|
+
options.glob
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
if (options.mode === "build") {
|
|
192
|
+
await build(
|
|
193
|
+
options.glob === true ? files : options.srcDir,
|
|
194
|
+
nwDir,
|
|
195
|
+
options.outDir,
|
|
196
|
+
options.platform,
|
|
197
|
+
options.zip,
|
|
198
|
+
releaseInfo,
|
|
199
|
+
options.app,
|
|
200
|
+
manifest
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
} catch (error) {
|
|
204
|
+
log.error(error);
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export default nwbuild;
|
package/src/run/develop.js
CHANGED
package/src/util/cache.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Check if NW binaries are cached
|
|
@@ -9,7 +9,7 @@ import { access, constants } from "node:fs/promises";
|
|
|
9
9
|
export const isCached = async (nwDir) => {
|
|
10
10
|
let exists = true;
|
|
11
11
|
try {
|
|
12
|
-
await
|
|
12
|
+
await readdir(nwDir);
|
|
13
13
|
} catch (e) {
|
|
14
14
|
exists = false;
|
|
15
15
|
}
|
package/src/util/ffmpeg.js
CHANGED
package/src/util/files.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
{
|
|
2
|
-
"latest": "v0.
|
|
3
|
-
"stable": "v0.
|
|
4
|
-
"lts": "v0.
|
|
2
|
+
"latest": "v0.75.0",
|
|
3
|
+
"stable": "v0.75.0",
|
|
4
|
+
"lts": "v0.75.0",
|
|
5
5
|
"versions": [
|
|
6
|
+
{
|
|
7
|
+
"version": "v0.75.0",
|
|
8
|
+
"date": "2023/04/15",
|
|
9
|
+
"files": ["osx-arm64"],
|
|
10
|
+
"flavors": ["normal", "sdk"],
|
|
11
|
+
"components": {
|
|
12
|
+
"node": "19.7.0",
|
|
13
|
+
"chromium": "112.0.5615.49"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
6
16
|
{
|
|
7
17
|
"version": "v0.70.0",
|
|
8
18
|
"date": "2022/11/30",
|
package/src/util/parse.js
CHANGED
|
@@ -7,7 +7,7 @@ import { getPlatform } from "./platform.js";
|
|
|
7
7
|
/**
|
|
8
8
|
* Parse options
|
|
9
9
|
*
|
|
10
|
-
* @param {import("../../index.js").
|
|
10
|
+
* @param {import("../../index.js").Options} options Options
|
|
11
11
|
* @param {object} pkg Package.json as JSON
|
|
12
12
|
* @return {Promise<object>} Options
|
|
13
13
|
*/
|
|
@@ -21,7 +21,7 @@ export const parse = async (options, pkg) => {
|
|
|
21
21
|
options.arch = options.arch ?? getArch(arch);
|
|
22
22
|
options.downloadUrl = options.downloadUrl ?? "https://dl.nwjs.io";
|
|
23
23
|
options.manifestUrl = options.manifestUrl ?? "https://nwjs.io/versions";
|
|
24
|
-
options.cacheDir =
|
|
24
|
+
options.cacheDir = options.cacheDir ?? "./cache";
|
|
25
25
|
options.cache = options.cache ?? true;
|
|
26
26
|
options.ffmpeg = options.ffmpeg ?? false;
|
|
27
27
|
|
|
@@ -31,7 +31,7 @@ export const parse = async (options, pkg) => {
|
|
|
31
31
|
|
|
32
32
|
options.argv = options.argv ?? [];
|
|
33
33
|
options.glob = options.glob ?? true;
|
|
34
|
-
options.srcDir =
|
|
34
|
+
options.srcDir = options.srcDir ?? (options.glob ? "./*" : ".");
|
|
35
35
|
|
|
36
36
|
if (options.mode === "run") {
|
|
37
37
|
return { ...options };
|
|
@@ -42,7 +42,7 @@ export const parse = async (options, pkg) => {
|
|
|
42
42
|
|
|
43
43
|
options.app = options.app ?? {};
|
|
44
44
|
|
|
45
|
-
// TODO: move this out to
|
|
45
|
+
// TODO: move this out to
|
|
46
46
|
if (options.platform === "linux") {
|
|
47
47
|
// linux desktop entry file configurations options
|
|
48
48
|
options.app.name = options.app.name ?? pkg.name;
|
|
@@ -73,7 +73,8 @@ export const parse = async (options, pkg) => {
|
|
|
73
73
|
// windows configuration options
|
|
74
74
|
options.app.comments = options.app.comments ?? undefined;
|
|
75
75
|
options.app.company = options.app.company ?? pkg.author;
|
|
76
|
-
options.app.fileDescription =
|
|
76
|
+
options.app.fileDescription =
|
|
77
|
+
options.app.fileDescription ?? pkg.description;
|
|
77
78
|
options.app.fileVersion = options.app.fileVersion ?? pkg.version;
|
|
78
79
|
options.app.internalName = options.app.internalName ?? pkg.name;
|
|
79
80
|
options.app.legalCopyright = options.app.legalCopyright ?? undefined;
|
package/src/util/platform.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Get user's computer platform
|
|
3
3
|
*
|
|
4
|
-
* @param {string}
|
|
5
|
-
* @return {"osx"| "win" | "linux" |
|
|
4
|
+
* @param {string} platform Node's process.platform
|
|
5
|
+
* @return {"osx"| "win" | "linux" | string} Platform types
|
|
6
6
|
*/
|
|
7
7
|
export const getPlatform = (platform) => {
|
|
8
8
|
switch (platform) {
|
package/src/util/validate.js
CHANGED
|
@@ -11,15 +11,17 @@ import { readdir } from "node:fs/promises";
|
|
|
11
11
|
export const validate = async (options, releaseInfo) => {
|
|
12
12
|
if (!["get", "run", "build"].includes(options.mode)) {
|
|
13
13
|
throw new Error(
|
|
14
|
-
`Unknown mode ${options.mode}. Expected "get", "run" or "build"
|
|
14
|
+
`Unknown mode ${options.mode}. Expected "get", "run" or "build".`
|
|
15
15
|
);
|
|
16
16
|
}
|
|
17
17
|
if (typeof releaseInfo === "undefined") {
|
|
18
|
-
throw new Error(
|
|
18
|
+
throw new Error(
|
|
19
|
+
"The specified version does not exist in the version manifest. Disable cache to redownload the version manifest. If you still get this error, that means the version you've specified is incorrect."
|
|
20
|
+
);
|
|
19
21
|
}
|
|
20
22
|
if (!releaseInfo.flavors.includes(options.flavor)) {
|
|
21
23
|
throw new Error(
|
|
22
|
-
`${options.flavor} flavor is not supported by this download server
|
|
24
|
+
`${options.flavor} flavor is not supported by this download server.`
|
|
23
25
|
);
|
|
24
26
|
}
|
|
25
27
|
if (
|
|
@@ -28,7 +30,7 @@ export const validate = async (options, releaseInfo) => {
|
|
|
28
30
|
!releaseInfo.files.includes(`${options.platform}-${options.arch}`)
|
|
29
31
|
) {
|
|
30
32
|
throw new Error(
|
|
31
|
-
`Platform ${options.platform} and architecture ${options.arch} is not supported by this download server
|
|
33
|
+
`Platform ${options.platform} and architecture ${options.arch} is not supported by this download server.`
|
|
32
34
|
);
|
|
33
35
|
}
|
|
34
36
|
// if (typeof options.cacheDir !== "string") {
|
|
@@ -36,12 +38,12 @@ export const validate = async (options, releaseInfo) => {
|
|
|
36
38
|
// }
|
|
37
39
|
if (typeof options.cache !== "boolean") {
|
|
38
40
|
return new Error(
|
|
39
|
-
"Expected options.cache to be a boolean. Got " + typeof options.cache
|
|
41
|
+
"Expected options.cache to be a boolean. Got " + typeof options.cache
|
|
40
42
|
);
|
|
41
43
|
}
|
|
42
44
|
if (typeof options.ffmpeg !== "boolean") {
|
|
43
45
|
return new Error(
|
|
44
|
-
"Expected options.ffmpeg to be a boolean. Got " + typeof options.ffmpeg
|
|
46
|
+
"Expected options.ffmpeg to be a boolean. Got " + typeof options.ffmpeg
|
|
45
47
|
);
|
|
46
48
|
}
|
|
47
49
|
|
|
@@ -50,12 +52,12 @@ export const validate = async (options, releaseInfo) => {
|
|
|
50
52
|
}
|
|
51
53
|
if (Array.isArray(options.argv)) {
|
|
52
54
|
return new Error(
|
|
53
|
-
"Expected options.argv to be an array. Got " + typeof options.argv
|
|
55
|
+
"Expected options.argv to be an array. Got " + typeof options.argv
|
|
54
56
|
);
|
|
55
57
|
}
|
|
56
58
|
if (typeof options.glob !== "boolean") {
|
|
57
59
|
return new Error(
|
|
58
|
-
"Expected options.glob to be a boolean. Got " + typeof options.glob
|
|
60
|
+
"Expected options.glob to be a boolean. Got " + typeof options.glob
|
|
59
61
|
);
|
|
60
62
|
}
|
|
61
63
|
|
package/index.js
DELETED
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import { mkdir, rm } from "node:fs/promises";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
|
|
4
|
-
import { decompress } from "./src/get/decompress.js";
|
|
5
|
-
import { download } from "./src/get/download.js";
|
|
6
|
-
import { getReleaseInfo } from "./src/get/getReleaseInfo.js";
|
|
7
|
-
import { remove } from "./src/get/remove.js";
|
|
8
|
-
import { build } from "./src/bld/build.js";
|
|
9
|
-
import { develop } from "./src/run/develop.js";
|
|
10
|
-
import { isCached } from "./src/util/cache.js";
|
|
11
|
-
import { replaceFfmpeg } from "./src/util/ffmpeg.js";
|
|
12
|
-
import { getFiles } from "./src/util/files.js";
|
|
13
|
-
import { getVersionManifest } from "./src/util/versionManifest.js";
|
|
14
|
-
import { parse } from "./src/util/parse.js";
|
|
15
|
-
import { validate } from "./src/util/validate.js";
|
|
16
|
-
import { xattr } from "./src/util/xattr.js";
|
|
17
|
-
|
|
18
|
-
import { log } from "./src/log.js";
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @typedef {object} APP
|
|
22
|
-
* @property {string} name Name of the application
|
|
23
|
-
* Linux configuration options
|
|
24
|
-
* @property {string} genericName Generic name of the application
|
|
25
|
-
* @property {boolean} noDisplay If true the application is not displayed
|
|
26
|
-
* @property {string} comment Tooltip for the entry, for example "View sites on the Internet".
|
|
27
|
-
* @property {string} icon Icon to display in file manager, menus, etc.
|
|
28
|
-
* @property {boolean} hidden TBD
|
|
29
|
-
* @property {string[]} onlyShowIn A list of strings identifying the desktop environments that should (/not) display a given desktop entry
|
|
30
|
-
* @property {string[]} notShowIn A list of strings identifying the desktop environments that should (/not) display a given desktop entry
|
|
31
|
-
* @property {boolean} dBusActivatable A boolean value specifying if D-Bus activation is supported for this application
|
|
32
|
-
* @property {string} tryExec Path to an executable file on disk used to determine if the program is actually installed
|
|
33
|
-
* @property {string} exec Program to execute, possibly with arguments.
|
|
34
|
-
* @property {string} path If entry is of type Application, the working directory to run the program in.
|
|
35
|
-
* @property {boolean} terminal Whether the program runs in a terminal window.
|
|
36
|
-
* @property {string[]} actions Identifiers for application actions.
|
|
37
|
-
* @property {string[]} mimeType The MIME type(s) supported by this application.
|
|
38
|
-
* @property {string[]} categories Categories in which the entry should be shown in a menu
|
|
39
|
-
* @property {string[]} implements A list of interfaces that this application implements.
|
|
40
|
-
* @property {string[]} keywords A list of strings which may be used in addition to other metadata to describe this entry.
|
|
41
|
-
* @property {boolean} startupNotify If true, it is KNOWN that the application will send a "remove" message when started with the DESKTOP_STARTUP_ID environment variable set. If false, it is KNOWN that the application does not work with startup notification at all.
|
|
42
|
-
* @property {string} startupWMClass If specified, it is known that the application will map at least one window with the given string as its WM class or WM name hin
|
|
43
|
-
* @property {boolean} prefersNonDefaultGPU If true, the application prefers to be run on a more powerful discrete GPU if available.
|
|
44
|
-
* @property {string} singleMainWindow If true, the application has a single main window, and does not support having an additional one opened.
|
|
45
|
-
* Windows configuration options
|
|
46
|
-
* @property {string} comments Additional information that should be displayed for diagnostic purposes.
|
|
47
|
-
* @property {string} company Company that produced the file—for example, Microsoft Corporation or Standard Microsystems Corporation, Inc. This string is required.
|
|
48
|
-
* @property {string} fileDescription File description to be presented to users. This string may be displayed in a list box when the user is choosing files to install. For example, Keyboard Driver for AT-Style Keyboards. This string is required.
|
|
49
|
-
* @property {string} fileVersion Version number of the file. For example, 3.10 or 5.00.RC2. This string is required.
|
|
50
|
-
* @property {string} internalName Internal name of the file, if one exists—for example, a module name if the file is a dynamic-link library. If the file has no internal name, this string should be the original filename, without extension. This string is required.
|
|
51
|
-
* @property {string} legalCopyright Copyright notices that apply to the file. This should include the full text of all notices, legal symbols, copyright dates, and so on. This string is optional.
|
|
52
|
-
* @property {string} legalTrademark Trademarks and registered trademarks that apply to the file. This should include the full text of all notices, legal symbols, trademark numbers, and so on. This string is optional.
|
|
53
|
-
* @property {string} originalFilename Original name of the file, not including a path. This information enables an application to determine whether a file has been renamed by a user. The format of the name depends on the file system for which the file was created. This string is required.
|
|
54
|
-
* @property {string} privateBuild Information about a private version of the file—for example, Built by TESTER1 on \\TESTBED. This string should be present only if VS_FF_PRIVATEBUILD is specified in the fileflags parameter of the root block.
|
|
55
|
-
* @property {string} productName Name of the product with which the file is distributed. This string is required.
|
|
56
|
-
* @property {string} productVersion Version of the product with which the file is distributed—for example, 3.10 or 5.00.RC2. This string is required.
|
|
57
|
-
* @property {string} specialBuild Text that specifies how this version of the file differs from the standard version—for example, Private build for TESTER1 solving mouse problems on M250 and M250E computers. This string should be present only if VS_FF_SPECIALBUILD is specified in the fileflags parameter of the root block.
|
|
58
|
-
*/
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @typedef {object} OPTIONS
|
|
62
|
-
* @property {string} [srcDir="./"] String of space separated glob patterns which correspond to NW app code
|
|
63
|
-
* @property {"get" | "run" | "build"} [mode="build"] Run or build application
|
|
64
|
-
* @property {"latest" | "stable" | string} [version="latest"] NW runtime version
|
|
65
|
-
* @property {"normal" | "sdk"} [flavor="normal"] NW runtime build flavor
|
|
66
|
-
* @property {"linux" | "osx" | "win"} platform NW supported platforms
|
|
67
|
-
* @property {"ia32" | "x64" | "arm64"} arch NW supported architectures
|
|
68
|
-
* @property {string} [outDir="./out"] Directory to store build artifacts
|
|
69
|
-
* @property {"./cache" | string} [cacheDir="./cache"] Directory to store NW binaries
|
|
70
|
-
* @property {"https://dl.nwjs.io" | "https://npmmirror.com/mirrors/nwjs" | "https://npm.taobao.org/mirrors/nwjs"} [downloadUrl="https://dl.nwjs.io"] URI to download NW binaries from
|
|
71
|
-
* @property {"https://nwjs.io/versions"} [manifestUrl="https://nwjs.io/versions"] URI to download manifest from
|
|
72
|
-
* @property {APP} app Multi platform configuration options
|
|
73
|
-
* @property {boolean} [cache=true] If true the existing cache is used. Otherwise it removes and redownloads it.
|
|
74
|
-
* @property {boolean} [zip=false] If true the outDir directory is zipped
|
|
75
|
-
* @property {boolean} [cli=false] If true the CLI is used to glob srcDir and parse other options
|
|
76
|
-
* @property {boolean} [ffmpeg=false] If true the chromium ffmpeg is replaced by community version
|
|
77
|
-
* @property {boolean} [glob=true] If true globbing is enabled
|
|
78
|
-
*/
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Automates building an NW.js application.
|
|
82
|
-
*
|
|
83
|
-
* @param {OPTIONS} options NW-Builder user options
|
|
84
|
-
* @return {Promise<undefined>}
|
|
85
|
-
*/
|
|
86
|
-
const nwbuild = async (options) => {
|
|
87
|
-
let nwDir = "";
|
|
88
|
-
let ffmpegFile = "";
|
|
89
|
-
let cached;
|
|
90
|
-
let nwCached;
|
|
91
|
-
let built;
|
|
92
|
-
let releaseInfo = {};
|
|
93
|
-
let files = [];
|
|
94
|
-
let manifest = {};
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
// Parse options
|
|
98
|
-
options = await parse(options, manifest);
|
|
99
|
-
|
|
100
|
-
if (options.mode !== "get") {
|
|
101
|
-
files = options.glob ? await getFiles(options.srcDir) : options.srcDir;
|
|
102
|
-
manifest = await getVersionManifest(files, options.glob);
|
|
103
|
-
if (typeof manifest?.nwbuild === "object") {
|
|
104
|
-
options = manifest.nwbuild;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
options = await parse(options, manifest);
|
|
109
|
-
|
|
110
|
-
// Create cacheDir if it does not exist
|
|
111
|
-
cached = await isCached(options.cacheDir);
|
|
112
|
-
if (cached === false) {
|
|
113
|
-
await mkdir(options.cacheDir, { recursive: true });
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (options.mode !== "get" && options.mode !== "run") {
|
|
117
|
-
// Create outDir if it does not exist
|
|
118
|
-
built = await isCached(options.outDir);
|
|
119
|
-
if (built === false) {
|
|
120
|
-
await mkdir(options.outDir, { recursive: true });
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Validate options.version to get the version specific release info
|
|
125
|
-
releaseInfo = await getReleaseInfo(
|
|
126
|
-
options.version,
|
|
127
|
-
options.platform,
|
|
128
|
-
options.arch,
|
|
129
|
-
options.cacheDir,
|
|
130
|
-
options.manifestUrl,
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
await validate(options, releaseInfo);
|
|
134
|
-
|
|
135
|
-
// Remove leading "v" from version string
|
|
136
|
-
options.version = releaseInfo.version.slice(1);
|
|
137
|
-
|
|
138
|
-
// Variable to store nwDir file path
|
|
139
|
-
nwDir = resolve(
|
|
140
|
-
options.cacheDir,
|
|
141
|
-
`nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform
|
|
142
|
-
}-${options.arch}`,
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
nwCached = await isCached(nwDir);
|
|
146
|
-
// Remove cached NW binary
|
|
147
|
-
if (options.cache === false && nwCached === true) {
|
|
148
|
-
log.debug("Remove cached NW binary");
|
|
149
|
-
await rm(nwDir, { force: true, recursive: true });
|
|
150
|
-
}
|
|
151
|
-
// Download relevant NW.js binaries
|
|
152
|
-
if (nwCached === false) {
|
|
153
|
-
log.debug("Download relevant NW.js binaries");
|
|
154
|
-
await download(
|
|
155
|
-
options.version,
|
|
156
|
-
options.flavor,
|
|
157
|
-
options.platform,
|
|
158
|
-
options.arch,
|
|
159
|
-
options.downloadUrl,
|
|
160
|
-
options.cacheDir,
|
|
161
|
-
);
|
|
162
|
-
await decompress(options.platform, options.cacheDir, options.downloadUrl);
|
|
163
|
-
await remove(options.platform, options.cacheDir, options.downloadUrl);
|
|
164
|
-
} else {
|
|
165
|
-
log.debug("Using cached NW.js binaries");
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (options.ffmpeg === true) {
|
|
169
|
-
log.warn(
|
|
170
|
-
"Using MP3 and H.264 codecs requires you to pay attention to the patent royalties and the license of the source code. Consult a lawyer if you do not understand the licensing constraints and using patented media formats in your app. See https://chromium.googlesource.com/chromium/third_party/ffmpeg.git/+/master/CREDITS.chromium for more information.",
|
|
171
|
-
);
|
|
172
|
-
if (options.platform === "win") {
|
|
173
|
-
ffmpegFile = "libffmpeg.dll";
|
|
174
|
-
} else if (options.platform === "osx") {
|
|
175
|
-
ffmpegFile = "libffmpeg.dylib";
|
|
176
|
-
} else if (options.platform === "linux") {
|
|
177
|
-
ffmpegFile = "libffmpeg.so";
|
|
178
|
-
}
|
|
179
|
-
ffmpegFile = resolve(options.cacheDir, ffmpegFile);
|
|
180
|
-
const ffmpegCached = await isCached(ffmpegFile);
|
|
181
|
-
// Remove cached ffmpeg binary
|
|
182
|
-
if (options.cache === false && ffmpegCached === true) {
|
|
183
|
-
log.debug("Remove cached ffmpeg binary");
|
|
184
|
-
await rm(ffmpegFile, { force: true, recursive: true });
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Download relevant ffmpeg binaries
|
|
188
|
-
if (ffmpegCached === false) {
|
|
189
|
-
log.debug("Download relevant ffmpeg binaries");
|
|
190
|
-
await download(
|
|
191
|
-
options.version,
|
|
192
|
-
options.flavor,
|
|
193
|
-
options.platform,
|
|
194
|
-
options.arch,
|
|
195
|
-
"https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download",
|
|
196
|
-
options.cacheDir,
|
|
197
|
-
);
|
|
198
|
-
await decompress(
|
|
199
|
-
options.platform,
|
|
200
|
-
options.cacheDir,
|
|
201
|
-
"https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download",
|
|
202
|
-
);
|
|
203
|
-
await remove(
|
|
204
|
-
options.platform,
|
|
205
|
-
options.cacheDir,
|
|
206
|
-
"https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download",
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
await replaceFfmpeg(options.platform, nwDir, ffmpegFile);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
await xattr(options.platform, options.arch, nwDir);
|
|
214
|
-
|
|
215
|
-
// Downloading binaries is required for run and build modes
|
|
216
|
-
// If mode is get, exit function since we have gotten the binaries
|
|
217
|
-
if (options.mode === "get") {
|
|
218
|
-
return undefined;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (options.mode === "run") {
|
|
222
|
-
await develop(
|
|
223
|
-
options.srcDir,
|
|
224
|
-
nwDir,
|
|
225
|
-
options.platform,
|
|
226
|
-
options.argv,
|
|
227
|
-
options.glob,
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
if (options.mode === "build") {
|
|
231
|
-
await build(
|
|
232
|
-
options.glob === true ? files : options.srcDir,
|
|
233
|
-
nwDir,
|
|
234
|
-
options.outDir,
|
|
235
|
-
options.platform,
|
|
236
|
-
options.zip,
|
|
237
|
-
releaseInfo,
|
|
238
|
-
options.app,
|
|
239
|
-
manifest,
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
} catch (error) {
|
|
243
|
-
log.error(error);
|
|
244
|
-
throw error;
|
|
245
|
-
}
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
export default nwbuild;
|
package/src/util/arch.test.js
DELETED
package/src/util/cache.test.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { getPlatform } from "./platform.js";
|
|
2
|
-
|
|
3
|
-
test("linux platform support", () => {
|
|
4
|
-
expect(getPlatform("linux")).toBe("linux");
|
|
5
|
-
});
|
|
6
|
-
|
|
7
|
-
test("macos platform support", () => {
|
|
8
|
-
expect(getPlatform("darwin")).toBe("osx");
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
test("windows platform support", () => {
|
|
12
|
-
expect(getPlatform("win32")).toBe("win");
|
|
13
|
-
});
|