UNPKG

neutralino-appimage-bundler

Version:

Bundles your Neutralino project in AppImage

267 lines (199 loc) 8.14 kB
import AppImageTool from './lib/AppImageTool.js'; import LinuxDeploy from './lib/LinuxDeploy.js'; import Desktop from './lib/Desktop.js'; import AppRun from './lib/AppRun.js'; import * as fs from 'fs-extra'; import * as path from 'path'; import { spawn } from 'child_process'; type Params = { /** * Application version */ version: string; desktop: { /** * Desktop name entry value */ name: string; /** * Path to the icon */ icon: string; /** * Desktop type entry value */ type?: string; /** * Desktop categories entry value */ categories?: string[]|string; }; binary: { /** * Project folder (and binaries) name */ name: string; /** * Path to the folder with binaries made by neutralino */ dist: string; }; /** * Should AppImage include neutralino's dependencies or not * * If specified as true - then AppImage will contain binary file shared libraries */ includeLibraries?: boolean; /** * Object of files or folders to copy * * "Relative path inside AppDir": "Absolute path to file or folder" */ copy?: Map<string, string>; /** * (optional) If set to true, the AppImage will run only with root privileges */ sudo?: boolean; /** * Output AppImage path */ output?: string; }; export class Bundler { public readonly appDir: string = path.join(__dirname, '../AppDir'); public params: Params; public constructor(params: Params) { this.params = params; } public bundle(): Promise<void> { return new Promise(async (resolve) => { if (!await AppImageTool.installed()) await this.downloadAppImageTool(); if (!await LinuxDeploy.installed()) await this.downloadLinuxDeploy(); if (fs.existsSync(this.appDir)) { console.log('Cleaning AppDir...'); fs.removeSync(this.appDir); } console.log('Copying project files to AppDir...'); fs.mkdirSync(this.appDir); fs.copyFileSync(path.join(this.params.binary.dist, this.params.binary.name, `${this.params.binary.name}-linux_x64`), path.join(this.appDir, this.params.binary.name)); fs.copyFileSync(path.join(this.params.binary.dist, this.params.binary.name, 'resources.neu'), path.join(this.appDir, 'resources.neu')); fs.copyFileSync(this.params.desktop.icon, path.join(this.appDir, path.basename(this.params.desktop.icon))); console.log('Copying specified files...'); if (this.params.copy) { Object.keys(this.params.copy).forEach((relative) => { const relativePath = path.join(this.appDir, relative); if (fs.lstatSync(this.params.copy![relative]).isDirectory()) fs.mkdirpSync(relativePath); else fs.createFileSync(relativePath); fs.copySync(this.params.copy![relative], relativePath); }); } console.log('Creating desktop file...'); const imageName = /(.*)\.[^\.]*|([^\.]*)/.exec(path.basename(this.params.desktop.icon))![1]; fs.writeFileSync(path.join(this.appDir, `${this.params.binary.name}.desktop`), Desktop.generate({ name: this.params.desktop.name, icon: imageName, exec: `AppRun`, type: this.params.desktop.type, categories: this.params.desktop.categories })); console.log('Creating AppRun file...'); fs.writeFileSync(path.join(this.appDir, 'AppRun'), AppRun.generate(`${this.params.binary.name}`, this.params.sudo)); fs.chmodSync(path.join(this.appDir, 'AppRun'), 0o755); console.log('Executing LinuxDeploy...'); let additionalOptions: string[] = []; if (this.params.includeLibraries) additionalOptions = ['-e', path.join(this.appDir, this.params.binary.name)]; // /linuxdeploy --appdir AppDir -d AppDir/app.desktop -i '[...]/test/public/icons/64x64.png' [-e AppDir/app] -o appimage const linuxDeployProcess = spawn(LinuxDeploy.file, [ '--appdir', this.appDir, '-d', path.join(this.appDir, `${this.params.binary.name}.desktop`), '-i', this.params.desktop.icon, ...additionalOptions, '-o', 'appimage' ], { env: { ...process.env, VERSION: this.params.version } }); linuxDeployProcess.stdout.on('data', (data) => console.log(data.toString())); linuxDeployProcess.stdout.on('data', (data) => console.log(data.toString())); linuxDeployProcess.on('close', () => { const filesBefore = fs.readdirSync('.').filter((file) => file.substring(file.length - 9) === '.AppImage'); console.log('Executing AppImageTool...\r\n'); // ./appimagetool AppDir const appImageToolProcess = spawn(AppImageTool.file, [this.appDir]); appImageToolProcess.stdout.on('data', (data) => console.log(data.toString())); appImageToolProcess.stdout.on('data', (data) => console.log(data.toString())); appImageToolProcess.on('close', () => { console.log('Project building finished'); const filesAfter = fs.readdirSync('.').filter((file) => file.substring(file.length - 9) === '.AppImage'); for (const file of filesAfter) if (filesBefore.includes(file)) { let savedPath = path.join('./', file); if (this.params.output) { if (fs.existsSync(this.params.output)) fs.removeSync(this.params.output); fs.moveSync(savedPath, this.params.output); if (fs.existsSync(savedPath)) fs.removeSync(savedPath); savedPath = this.params.output; } console.log(`Saved file: ${savedPath}`); break; } resolve(); }); }); }); } protected downloadAppImageTool(): Promise<void> { return new Promise(async (resolve) => { process.stdout.write('Downloading AppImageTool'); let downloading = true; const logger = () => { if (downloading) { process.stdout.write('.'); setTimeout(logger, 250); } } setTimeout(logger, 250); await AppImageTool.install(); downloading = false; process.stdout.write('\r\n'); resolve(); }); } protected downloadLinuxDeploy(): Promise<void> { return new Promise(async (resolve) => { process.stdout.write('Downloading LinuxDeploy'); let downloading = true; const logger = () => { if (downloading) { process.stdout.write('.'); setTimeout(logger, 250); } } setTimeout(logger, 250); await LinuxDeploy.install(); downloading = false; process.stdout.write('\r\n'); resolve(); }); } }; export type { Params };