mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-11 10:09:59 +00:00
Cleanup app build script and add more detailed documentation
This commit is contained in:
197
app/bin/build.js
197
app/bin/build.js
@@ -7,9 +7,9 @@ const minimist = require("minimist");
|
|||||||
const glob = require("glob");
|
const glob = require("glob");
|
||||||
const mustache = require("mustache");
|
const mustache = require("mustache");
|
||||||
const makensis = require("makensis");
|
const makensis = require("makensis");
|
||||||
|
const pkg = require("pkg");
|
||||||
|
|
||||||
const { spawnSync } = require("child_process");
|
const { spawnSync } = require("child_process");
|
||||||
const { exec: pkgExec } = require("pkg");
|
|
||||||
|
|
||||||
const { __applicationName: applicationName
|
const { __applicationName: applicationName
|
||||||
, __applicationVersion: applicationVersion } = require("../package.json");
|
, __applicationVersion: applicationVersion } = require("../package.json");
|
||||||
@@ -25,6 +25,7 @@ const { executableName
|
|||||||
, WIN_REGISTRY_KEY } = require("./lib/paths");
|
, WIN_REGISTRY_KEY } = require("./lib/paths");
|
||||||
|
|
||||||
|
|
||||||
|
// Command line args
|
||||||
const argv = minimist(process.argv.slice(2), {
|
const argv = minimist(process.argv.slice(2), {
|
||||||
boolean: [ "package" ]
|
boolean: [ "package" ]
|
||||||
, string: [ "platform", "arch", "packageType" ]
|
, string: [ "platform", "arch", "packageType" ]
|
||||||
@@ -42,11 +43,12 @@ const SRC_PATH = path.join(ROOT_PATH, "src");
|
|||||||
const BUILD_PATH = path.join(ROOT_PATH, "build");
|
const BUILD_PATH = path.join(ROOT_PATH, "build");
|
||||||
|
|
||||||
|
|
||||||
// Clean
|
/**
|
||||||
|
* Shouldn't exist, but cleanup and re-create any existing
|
||||||
|
* build directories, just in case.
|
||||||
|
*/
|
||||||
fs.removeSync(BUILD_PATH);
|
fs.removeSync(BUILD_PATH);
|
||||||
fs.removeSync(DIST_PATH);
|
fs.removeSync(DIST_PATH);
|
||||||
|
|
||||||
// Make directories
|
|
||||||
fs.ensureDirSync(BUILD_PATH);
|
fs.ensureDirSync(BUILD_PATH);
|
||||||
fs.ensureDirSync(DIST_PATH, { recursive: true });
|
fs.ensureDirSync(DIST_PATH, { recursive: true });
|
||||||
|
|
||||||
@@ -72,66 +74,91 @@ async function build () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Create app manifest
|
/**
|
||||||
|
* Native app manifest
|
||||||
|
* https://mdn.io/Native_manifests#Native_messaging_manifests
|
||||||
|
*/
|
||||||
const manifest = {
|
const manifest = {
|
||||||
"name": applicationName
|
"name": applicationName
|
||||||
, "description": ""
|
, "description": ""
|
||||||
, "type": "stdio"
|
, "type": "stdio"
|
||||||
, "allowed_extensions": [ extensionId ]
|
, "allowed_extensions": [ extensionId ]
|
||||||
, "path": argv.package
|
|
||||||
// Add either installed path or dist path
|
|
||||||
? (argv.platform === "win32" ? path.win32 : path)
|
|
||||||
.join(executablePath[argv.platform]
|
|
||||||
, executableName[argv.platform])
|
|
||||||
: path.join(DIST_PATH, executableName[argv.platform])
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write manifest
|
/**
|
||||||
|
* If packaging, add the installed executable path, otherwise
|
||||||
|
* add the path to the built executable in the dist folder.
|
||||||
|
*/
|
||||||
|
if (argv.package) {
|
||||||
|
// If packaging for windows, use win32 path helpers.
|
||||||
|
manifest.path = (argv.platform === "win32" ? path.win32 : path)
|
||||||
|
.join(executablePath[argv.platform]
|
||||||
|
, executableName[argv.platform]);
|
||||||
|
} else {
|
||||||
|
manifest.path = path.join(DIST_PATH, executableName[argv.platform]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write app manifest
|
||||||
fs.writeFileSync(path.join(BUILD_PATH, manifestName)
|
fs.writeFileSync(path.join(BUILD_PATH, manifestName)
|
||||||
, JSON.stringify(manifest, null, 4));
|
, JSON.stringify(manifest, null, 4));
|
||||||
|
|
||||||
|
|
||||||
// File permissions
|
// Ensure file permissions are correct
|
||||||
for (const file of fs.readdirSync(BUILD_PATH)) {
|
for (const file of fs.readdirSync(BUILD_PATH)) {
|
||||||
fs.chmodSync(path.resolve(BUILD_PATH, file), 0o755);
|
fs.chmodSync(path.resolve(BUILD_PATH, file), 0o755);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Need a minimal package.json for pkg.
|
||||||
const pkgManifest = {
|
const pkgManifest = {
|
||||||
bin: "main.js"
|
bin: "main.js"
|
||||||
, pkg: {
|
, pkg: {
|
||||||
// Workaround for pkg asset detection
|
/**
|
||||||
// https://github.com/thibauts/node-castv2/issues/46
|
* Workaround for pkg asset detection
|
||||||
|
* https://github.com/thibauts/node-castv2/issues/46
|
||||||
|
*/
|
||||||
"assets": "../node_modules/castv2/lib/cast_channel.proto"
|
"assets": "../node_modules/castv2/lib/cast_channel.proto"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Write pkg manifest
|
||||||
fs.writeFileSync(path.join(BUILD_PATH, "package.json")
|
fs.writeFileSync(path.join(BUILD_PATH, "package.json")
|
||||||
, JSON.stringify(pkgManifest))
|
, JSON.stringify(pkgManifest))
|
||||||
|
|
||||||
// Package executable
|
// Run pkg to create a single executable
|
||||||
await pkgExec([
|
await pkg.exec([
|
||||||
BUILD_PATH
|
BUILD_PATH
|
||||||
, "--target", `${pkgPlatform[argv.platform]}-${argv.arch}`
|
, "--target", `${pkgPlatform[argv.platform]}-${argv.arch}`
|
||||||
, "--output", path.join(BUILD_PATH, executableName[argv.platform])
|
, "--output", path.join(BUILD_PATH, executableName[argv.platform])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If packaging, create an installer package and move it to
|
||||||
|
* dist, otherwise move the built executable and app manifest
|
||||||
|
* to dist.
|
||||||
|
*/
|
||||||
if (argv.package) {
|
if (argv.package) {
|
||||||
const installerName = await packageApp(argv.platform);
|
const installerName = await packageApp(argv.platform);
|
||||||
|
|
||||||
if (installerName) {
|
if (installerName) {
|
||||||
// Move installer to dist
|
// Move installer to dist
|
||||||
fs.moveSync(path.join(BUILD_PATH, installerName)
|
fs.moveSync(
|
||||||
|
path.join(BUILD_PATH, installerName)
|
||||||
, path.join(DIST_PATH, path.basename(installerName))
|
, path.join(DIST_PATH, path.basename(installerName))
|
||||||
, { overwrite: true });
|
, { overwrite: true });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Move binary / app manifest
|
const builtExecutableName = executableName[argv.platform];
|
||||||
fs.moveSync(path.join(BUILD_PATH, manifestName)
|
|
||||||
|
// Move executable and app manifest to dist
|
||||||
|
fs.moveSync(
|
||||||
|
path.join(BUILD_PATH, manifestName)
|
||||||
, path.join(DIST_PATH, manifestName)
|
, path.join(DIST_PATH, manifestName)
|
||||||
, { overwrite: true });
|
, { overwrite: true });
|
||||||
fs.moveSync(path.join(BUILD_PATH, executableName[argv.platform])
|
fs.moveSync(
|
||||||
, path.join(DIST_PATH, executableName[argv.platform])
|
path.join(BUILD_PATH, builtExecutableName)
|
||||||
|
, path.join(DIST_PATH, builtExecutableName)
|
||||||
, { overwrite: true });
|
, { overwrite: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,29 +166,60 @@ async function build () {
|
|||||||
fs.removeSync(BUILD_PATH);
|
fs.removeSync(BUILD_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a platform and returns the path of the created
|
||||||
|
* install package.
|
||||||
|
*/
|
||||||
function packageApp (platform) {
|
function packageApp (platform) {
|
||||||
|
const packageFunctionArgs = [
|
||||||
|
executableName[platform] // platformExecutableName
|
||||||
|
, executablePath[platform] // platformExecutablePath
|
||||||
|
, manifestPath[platform] // platformManifestPath
|
||||||
|
];
|
||||||
|
|
||||||
switch (platform) {
|
switch (platform) {
|
||||||
case "darwin":
|
case "win32": return packageWin32(...packageFunctionArgs);
|
||||||
return packageDarwin(platform);
|
case "darwin": return packageDarwin(...packageFunctionArgs);
|
||||||
|
|
||||||
case "linux":
|
case "linux":
|
||||||
|
/**
|
||||||
|
* Get manifest path from package type sub key for Linux
|
||||||
|
* platforms.
|
||||||
|
*/
|
||||||
|
packageFunctionArgs.push(
|
||||||
|
packageFunctionArgs.pop()[argv.packageType]);
|
||||||
|
|
||||||
switch (argv.packageType) {
|
switch (argv.packageType) {
|
||||||
case "deb":
|
case "deb": return packageLinuxDeb(...packageFunctionArgs);
|
||||||
return packageLinuxDeb(platform, argv.packageType);
|
case "rpm": return packageLinuxRpm(...packageFunctionArgs);
|
||||||
case "rpm":
|
|
||||||
return packageLinuxRpm(platform, argv.packageType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case "win32":
|
break;
|
||||||
return packageWin32(platform);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.log("Cannot build installer package for this platform");
|
console.log("Cannot build installer package for this platform");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function packageDarwin (platform) {
|
/**
|
||||||
|
* Builds a macOS Installer package.
|
||||||
|
*
|
||||||
|
* Creates a root directory with the installed file system
|
||||||
|
* structure for package files, bundles the postinstall
|
||||||
|
* script (packaging/mac/scripts/postinstall), then creates
|
||||||
|
* a component package.
|
||||||
|
* Distribution package is built from the component package
|
||||||
|
* and distribution file (packaging/mac/distribution.xml).
|
||||||
|
*
|
||||||
|
* Requires the pkgbuild and productbuild command line
|
||||||
|
* utilities. Only possible on macOS.
|
||||||
|
*/
|
||||||
|
function packageDarwin (
|
||||||
|
platformExecutableName
|
||||||
|
, platformExecutablePath
|
||||||
|
, platformManifestPath) {
|
||||||
|
|
||||||
const installerName = `${applicationName}.pkg`;
|
const installerName = `${applicationName}.pkg`;
|
||||||
const componentName = `${applicationName}_component.pkg`;
|
const componentName = `${applicationName}_component.pkg`;
|
||||||
|
|
||||||
@@ -170,16 +228,16 @@ function packageDarwin (platform) {
|
|||||||
|
|
||||||
// Create pkgbuild root
|
// Create pkgbuild root
|
||||||
const rootPath = path.join(BUILD_PATH, "root");
|
const rootPath = path.join(BUILD_PATH, "root");
|
||||||
const rootExecutablePath = path.join(rootPath, executablePath[platform]);
|
const rootExecutablePath = path.join(rootPath, platformExecutablePath);
|
||||||
const rootManifestPath = path.join(rootPath, manifestPath[platform]);
|
const rootManifestPath = path.join(rootPath, platformManifestPath);
|
||||||
|
|
||||||
// Create install locations
|
// Create install locations
|
||||||
fs.ensureDirSync(rootExecutablePath, { recursive: true });
|
fs.ensureDirSync(rootExecutablePath, { recursive: true });
|
||||||
fs.ensureDirSync(rootManifestPath, { recursive: true });
|
fs.ensureDirSync(rootManifestPath, { recursive: true });
|
||||||
|
|
||||||
// Move files to root
|
// Move files to root
|
||||||
fs.moveSync(path.join(BUILD_PATH, executableName[platform])
|
fs.moveSync(path.join(BUILD_PATH, platformExecutableName)
|
||||||
, path.join(rootExecutablePath, executableName[platform]));
|
, path.join(rootExecutablePath, platformExecutableName));
|
||||||
fs.moveSync(path.join(BUILD_PATH, manifestName)
|
fs.moveSync(path.join(BUILD_PATH, manifestName)
|
||||||
, path.join(rootManifestPath, manifestName));
|
, path.join(rootManifestPath, manifestName));
|
||||||
|
|
||||||
@@ -192,8 +250,8 @@ function packageDarwin (platform) {
|
|||||||
, manifestName
|
, manifestName
|
||||||
, componentName
|
, componentName
|
||||||
, packageId: `tf.matt.${applicationName}`
|
, packageId: `tf.matt.${applicationName}`
|
||||||
, executablePath: executablePath[platform]
|
, executablePath: platformExecutablePath
|
||||||
, manifestPath: manifestPath[platform]
|
, manifestPath: platformManifestPath
|
||||||
};
|
};
|
||||||
|
|
||||||
// Template paths
|
// Template paths
|
||||||
@@ -229,24 +287,36 @@ function packageDarwin (platform) {
|
|||||||
, { shell: true });
|
, { shell: true });
|
||||||
|
|
||||||
return installerName;
|
return installerName;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function packageLinuxDeb (platform, packageType) {
|
/**
|
||||||
|
* Builds a DEB package for Debian, Ubuntu, Mint, etc...
|
||||||
|
*
|
||||||
|
* Creates a root directory with the installed file system
|
||||||
|
* structure for package files, copies control file
|
||||||
|
* (packaging/linux/deb/DEBIAN/control) to root, then builds
|
||||||
|
* package from root.
|
||||||
|
* Requires the dpkg-deb command line utility.
|
||||||
|
*/
|
||||||
|
function packageLinuxDeb (
|
||||||
|
platformExecutableName
|
||||||
|
, platformExecutablePath
|
||||||
|
, platformManifestPath) {
|
||||||
|
|
||||||
const installerName = `${applicationName}.deb`;
|
const installerName = `${applicationName}.deb`;
|
||||||
|
|
||||||
// Create root
|
// Create root
|
||||||
const rootPath = path.join(BUILD_PATH, "root");
|
const rootPath = path.join(BUILD_PATH, "root");
|
||||||
const rootExecutablePath = path.join(rootPath, executablePath[platform]);
|
const rootExecutablePath = path.join(rootPath, platformExecutablePath);
|
||||||
const rootManifestPath = path.join(rootPath
|
const rootManifestPath = path.join(rootPath
|
||||||
, manifestPath[platform][packageType]);
|
, platformManifestPath);
|
||||||
|
|
||||||
fs.ensureDirSync(rootExecutablePath, { recursive: true });
|
fs.ensureDirSync(rootExecutablePath, { recursive: true });
|
||||||
fs.ensureDirSync(rootManifestPath, { recursive: true });
|
fs.ensureDirSync(rootManifestPath, { recursive: true });
|
||||||
|
|
||||||
// Move files to root
|
// Move files to root
|
||||||
fs.moveSync(path.join(BUILD_PATH, executableName[platform])
|
fs.moveSync(path.join(BUILD_PATH, platformExecutableName)
|
||||||
, path.join(rootExecutablePath, executableName[platform]));
|
, path.join(rootExecutablePath, platformExecutableName));
|
||||||
fs.moveSync(path.join(BUILD_PATH, manifestName)
|
fs.moveSync(path.join(BUILD_PATH, manifestName)
|
||||||
, path.join(rootManifestPath, manifestName));
|
, path.join(rootManifestPath, manifestName));
|
||||||
|
|
||||||
@@ -280,7 +350,18 @@ function packageLinuxDeb (platform, packageType) {
|
|||||||
return installerName;
|
return installerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
function packageLinuxRpm (platform, packageType) {
|
/**
|
||||||
|
* Builds an RPM package for Fedora, openSUSE, etc...
|
||||||
|
*
|
||||||
|
* Templates and uses the spec file
|
||||||
|
* (packaging/linux/rpm/package.spec) to build the package.
|
||||||
|
* Requires the rpmbuild command line utility.
|
||||||
|
*/
|
||||||
|
function packageLinuxRpm (
|
||||||
|
platformExecutableName
|
||||||
|
, platformExecutablePath
|
||||||
|
, platformManifestPath) {
|
||||||
|
|
||||||
const specPath = path.join(__dirname
|
const specPath = path.join(__dirname
|
||||||
, "../packaging/linux/rpm/package.spec");
|
, "../packaging/linux/rpm/package.spec");
|
||||||
|
|
||||||
@@ -290,9 +371,9 @@ function packageLinuxRpm (platform, packageType) {
|
|||||||
packageName: applicationName
|
packageName: applicationName
|
||||||
, applicationName
|
, applicationName
|
||||||
, applicationVersion
|
, applicationVersion
|
||||||
, executablePath: executablePath[platform]
|
, executablePath: platformExecutablePath
|
||||||
, manifestPath: manifestPath[platform][packageType]
|
, manifestPath: platformManifestPath
|
||||||
, executableName: executableName[platform]
|
, executableName: platformExecutableName
|
||||||
, manifestName
|
, manifestName
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -312,7 +393,17 @@ function packageLinuxRpm (platform, packageType) {
|
|||||||
return glob.sync("**/*.rpm", { cwd: BUILD_PATH })[0];
|
return glob.sync("**/*.rpm", { cwd: BUILD_PATH })[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
function packageWin32 (platform) {
|
/**
|
||||||
|
* Builds a Windows installer.
|
||||||
|
*
|
||||||
|
* Uses NSIS to create a GUI installer with an installer
|
||||||
|
* script (packaging/win/installer.nsi). Requires the
|
||||||
|
* makensis command line utility.
|
||||||
|
*/
|
||||||
|
function packageWin32 (
|
||||||
|
platformExecutableName
|
||||||
|
, platformExecutablePath) {
|
||||||
|
|
||||||
const scriptPath = path.join(__dirname, "../packaging/win/installer.nsi");
|
const scriptPath = path.join(__dirname, "../packaging/win/installer.nsi");
|
||||||
const scriptOutputPath = path.join(BUILD_PATH, path.basename(scriptPath));
|
const scriptOutputPath = path.join(BUILD_PATH, path.basename(scriptPath));
|
||||||
|
|
||||||
@@ -321,18 +412,20 @@ function packageWin32 (platform) {
|
|||||||
const view = {
|
const view = {
|
||||||
applicationName
|
applicationName
|
||||||
, applicationVersion
|
, applicationVersion
|
||||||
, executableName: executableName[platform]
|
, executableName: platformExecutableName
|
||||||
, executablePath: executablePath[platform]
|
, executablePath: platformExecutablePath
|
||||||
, manifestName
|
, manifestName
|
||||||
, winRegistryKey: WIN_REGISTRY_KEY
|
, winRegistryKey: WIN_REGISTRY_KEY
|
||||||
, outFile
|
, outFile
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Write templated script to build dir
|
||||||
fs.writeFileSync(scriptOutputPath
|
fs.writeFileSync(scriptOutputPath
|
||||||
, mustache.render(
|
, mustache.render(
|
||||||
fs.readFileSync(scriptPath).toString()
|
fs.readFileSync(scriptPath).toString()
|
||||||
, view));
|
, view));
|
||||||
|
|
||||||
|
|
||||||
const output = makensis.compileSync(scriptOutputPath);
|
const output = makensis.compileSync(scriptOutputPath);
|
||||||
|
|
||||||
if (output.status === 0) {
|
if (output.status === 0) {
|
||||||
|
|||||||
2
ext/package-lock.json
generated
2
ext/package-lock.json
generated
@@ -6915,7 +6915,7 @@
|
|||||||
},
|
},
|
||||||
"pretty-format": {
|
"pretty-format": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
|
"resolved": "http://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
|
||||||
"integrity": "sha1-v77VbV6ad2ZF9LH/eqGjrE+jw4U=",
|
"integrity": "sha1-v77VbV6ad2ZF9LH/eqGjrE+jw4U=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user