| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919 |
- import { dirname, basename, resolve } from 'path';
- import * as semver from 'semver';
- import { ensureDir, emptyDir, readFile, readJson, writeFile, copy, remove, rename, chmod, createReadStream, createWriteStream, readdir } from 'fs-extra';
- import * as Bluebird from 'bluebird';
- const debug = require('debug')('build:builder');
- const globby = require('globby');
- const rcedit = require('rcedit');
- const plist = require('plist');
- import { Downloader } from './Downloader';
- import { FFmpegDownloader } from './FFmpegDownloader';
- import { BuildConfig } from './config';
- import { NsisVersionInfo, DownloaderBase } from './common';
- import { NsisComposer, NsisDiffer, Nsis7Zipper, nsisBuild } from './nsis-gen';
- import { mergeOptions, findExecutable, findFFmpeg, findRuntimeRoot, findExcludableDependencies, tmpName, tmpFile, tmpDir, fixWindowsVersion, copyFileAsync, extractGeneric, compress } from './util';
- export interface IParseOutputPatternOptions {
- name: string;
- version: string;
- platform: string;
- arch: string;
- }
- export interface IBuilderOptions {
- win?: boolean;
- mac?: boolean;
- linux?: boolean;
- x86?: boolean;
- x64?: boolean;
- tasks?: string[];
- chromeApp?: boolean;
- mirror?: string;
- concurrent?: boolean;
- mute?: boolean;
- destination?: string;
- }
- export class Builder {
- public static DEFAULT_OPTIONS: IBuilderOptions = {
- win: false,
- mac: false,
- linux: false,
- x86: false,
- x64: false,
- tasks: [],
- chromeApp: false,
- mirror: Downloader.DEFAULT_OPTIONS.mirror,
- concurrent: false,
- mute: true,
- destination: DownloaderBase.DEFAULT_DESTINATION,
- };
- public options: IBuilderOptions;
- constructor(options: IBuilderOptions = {}, public dir: string) {
- this.options = mergeOptions(Builder.DEFAULT_OPTIONS, options);
- debug('in constructor', 'dir', dir);
- debug('in constructor', 'options', this.options);
- }
- public async build() {
- const tasks: string[][] = [];
- [ 'win', 'mac', 'linux' ].map((platform) => {
- [ 'x86', 'x64' ].map((arch) => {
- if((<any>this.options)[platform] && (<any>this.options)[arch]) {
- tasks.push([ platform, arch ]);
- }
- });
- });
- for(const task of this.options.tasks) {
- const [ platform, arch ] = task.split('-');
- if([ 'win', 'mac', 'linux' ].indexOf(platform) >= 0) {
- if([ 'x86', 'x64' ].indexOf(arch) >= 0) {
- tasks.push([ platform, arch ]);
- }
- }
- }
- if(!this.options.mute) {
- console.info('Starting building tasks...', {
- tasks,
- concurrent: this.options.concurrent,
- });
- }
- if(tasks.length == 0) {
- throw new Error('ERROR_NO_TASK');
- }
- if(this.options.concurrent) {
- await Bluebird.map(tasks, async ([ platform, arch ]) => {
- const options: any = {};
- options[platform] = true;
- options[arch] = true;
- options.mirror = this.options.mirror;
- options.concurrent = false;
- options.mute = true;
- const builder = new Builder(options, this.dir);
- const started = Date.now();
- if(!this.options.mute) {
- console.info(`Building for ${ platform }, ${ arch } starts...`);
- }
- await builder.build();
- if(!this.options.mute) {
- console.info(`Building for ${ platform }, ${ arch } ends within ${ this.getTimeDiff(started) }s.`);
- }
- });
- }
- else {
- const pkg: any = await readJson(resolve(this.dir, this.options.chromeApp ? 'manifest.json' : 'package.json'));
- const config = new BuildConfig(pkg);
- debug('in build', 'config', config);
- for(const [ platform, arch ] of tasks) {
- const started = Date.now();
- if(!this.options.mute) {
- console.info(`Building for ${ platform }, ${ arch } starts...`);
- }
- try {
- await this.buildTask(platform, arch, pkg, config);
- }
- catch(err) {
- console.warn(err);
- }
- if(!this.options.mute) {
- console.info(`Building for ${ platform }, ${ arch } ends within ${ this.getTimeDiff(started) }s.`);
- }
- }
- }
- }
- protected getTimeDiff(started: number) {
- return ((Date.now() - started) / 1000).toFixed(2);
- }
- protected async writeStrippedManifest(path: string, pkg: any, config: BuildConfig) {
- const json: any = {};
- for(const key in pkg) {
- if(pkg.hasOwnProperty(key) && config.strippedProperties.indexOf(key) === -1) {
- if (config.overriddenProperties && config.overriddenProperties.hasOwnProperty(key) ) {
- json[key] = config.overriddenProperties[key];
- } else {
- json[key] = pkg[key];
- }
- }
- }
- await writeFile(path, JSON.stringify(json));
- }
- protected parseOutputPattern(pattern: string, options: IParseOutputPatternOptions, pkg: any, config: BuildConfig) {
- return pattern.replace(/\$\{\s*(\w+)\s*\}/g, (match: string, key: string) => {
- switch(key.toLowerCase()) {
- case 'name':
- return options.name;
- case 'version':
- return options.version;
- case 'platform':
- return options.platform;
- case 'arch':
- return options.arch;
- default:
- throw new Error('ERROR_KEY_UNKNOWN');
- }
- });
- }
- protected combineExecutable(executable: string, nwFile: string) {
- return new Promise((resolve, reject) => {
- const nwStream = createReadStream(nwFile);
- const stream = createWriteStream(executable, {
- flags: 'a',
- });
- nwStream.on('error', reject);
- stream.on('error', reject);
- stream.on('finish', resolve);
- nwStream.pipe(stream);
- });
- }
- protected readPlist(path: string): Promise<any> {
- return readFile(path, {
- encoding: 'utf-8',
- })
- .then(data => plist.parse(data));
- }
- protected writePlist(path: string, p: any) {
- return writeFile(path, plist.build(p));
- }
- protected updateWinResources(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- const pathResolve = resolve;
- return new Promise((resolve, reject) => {
- const path = pathResolve(targetDir, 'nw.exe');
- const rc = {
- 'product-version': fixWindowsVersion(config.win.productVersion),
- 'file-version': fixWindowsVersion(config.win.fileVersion),
- 'version-string': {
- ProductName: config.win.productName,
- CompanyName: config.win.companyName,
- FileDescription: config.win.fileDescription,
- LegalCopyright: config.win.copyright,
- ...config.win.versionStrings,
- },
- 'icon': config.win.icon ? pathResolve(this.dir, config.win.icon) : undefined,
- };
- rcedit(path, rc, (err: Error) => err ? reject(err) : resolve());
- });
- }
- protected renameWinApp(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- const src = resolve(targetDir, 'nw.exe');
- const dest = resolve(targetDir, `${ config.win.productName }.exe`);
- return rename(src, dest);
- }
- protected async updatePlist(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- const path = resolve(targetDir, './nwjs.app/Contents/Info.plist');
- const plist = await this.readPlist(path);
- plist.CFBundleIdentifier = config.appId;
- plist.CFBundleName = config.mac.name;
- plist.CFBundleExecutable = config.mac.displayName;
- plist.CFBundleDisplayName = config.mac.displayName;
- plist.CFBundleVersion = config.mac.version;
- plist.CFBundleShortVersionString = config.mac.version;
- for(const key in config.mac.plistStrings) {
- if(config.mac.plistStrings.hasOwnProperty(key)) {
- plist[key] = config.mac.plistStrings[key];
- }
- }
- await this.writePlist(path, plist);
- }
- protected async updateHelperPlist(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- if (!this.canRenameMacHelperApp(pkg, config)) {
- return;
- }
- const helperPath = await this.findMacHelperApp(targetDir);
- const path = resolve(helperPath, 'Contents/Info.plist');
- const plist = await this.readPlist(path);
- const bin = pkg.product_string + ' Helper';
- plist.CFBundleIdentifier = config.appId + '.helper';
- plist.CFBundleDisplayName = bin;
- plist.CFBundleExecutable = bin;
- plist.CFBundleName = bin;
- await this.writePlist(path, plist);
- }
- protected async updateMacIcons(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- const copyIcon = async (iconPath: string, dest: string) => {
- if(!iconPath) {
- // use the default
- return;
- }
- await copy(resolve(this.dir, iconPath), dest);
- };
- await copyIcon(config.mac.icon, resolve(targetDir, './nwjs.app/Contents/Resources/app.icns'));
- await copyIcon(config.mac.documentIcon, resolve(targetDir, './nwjs.app/Contents/Resources/document.icns'));
- }
- protected async fixMacMeta(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- const files = await globby([ '**/InfoPlist.strings' ], {
- cwd: targetDir,
- });
- for(const file of files) {
- const path = resolve(targetDir, file);
- // Different versions has different encodings for `InforPlist.strings`.
- // We determine encoding by evaluating bytes of `CF` here.
- const data = await readFile(path);
- const encoding = data.indexOf(Buffer.from('43004600', 'hex')) >= 0
- ? 'ucs2' : 'utf-8';
- const strings = data.toString(encoding);
- const newStrings = strings.replace(/([A-Za-z]+)\s+=\s+"(.+?)";/g, (match: string, key: string, value: string) => {
- switch(key) {
- case 'CFBundleName':
- return `${ key } = "${ config.mac.name }";`;
- case 'CFBundleDisplayName':
- return `${ key } = "${ config.mac.displayName }";`;
- case 'CFBundleGetInfoString':
- return `${ key } = "${ config.mac.version }";`;
- case 'NSContactsUsageDescription':
- return `${ key } = "${ config.mac.description }";`;
- case 'NSHumanReadableCopyright':
- return `${ key } = "${ config.mac.copyright }";`;
- default:
- return `${ key } = "${ value }";`;
- }
- });
- await writeFile(path, Buffer.from(newStrings, encoding));
- }
- }
- protected async renameMacApp(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- const app = resolve(targetDir, 'nwjs.app');
- const bin = resolve(app, './Contents/MacOS/nwjs');
- let dest = bin.replace(/nwjs$/, config.mac.displayName);
- await rename(bin, dest);
- dest = app.replace(/nwjs\.app$/, `${config.mac.displayName}.app`);
- return rename(app, dest);
- }
- protected async renameMacHelperApp(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- if (!this.canRenameMacHelperApp(pkg, config)) {
- return;
- }
- const app = await this.findMacHelperApp(targetDir);
- const bin = resolve(app, './Contents/MacOS/nwjs Helper');
- let dest = bin.replace(/nwjs Helper$/, `${pkg.product_string} Helper`);
- await rename(bin, dest);
- dest = app.replace(/nwjs Helper\.app$/, `${pkg.product_string} Helper.app`);
- return rename(app, dest);
- }
- protected canRenameMacHelperApp(pkg: any, config: BuildConfig): boolean {
- if (semver.lt(config.nwVersion, '0.24.4')) {
- // this version doesn't support Helper app renaming.
- return false;
- }
- if (!pkg.product_string) {
- // we can't rename the Helper app as we don't have a new name.
- return false;
- }
- return true;
- }
- protected async findMacHelperApp(targetDir: string): Promise<string> {
- const path = resolve(targetDir, './nwjs.app/Contents/Versions');
- // what version are we actually dealing with?
- const versions = await readdir(path);
- if (!versions || versions.length !== 1) {
- throw new Error("Can't rename the Helper as we can't find it");
- }
- return resolve(path, versions[0], 'nwjs Helper.app');
- }
- protected async fixLinuxMode(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- const path = resolve(targetDir, 'nw');
- await chmod(path, 0o744);
- }
- protected renameLinuxApp(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- const src = resolve(targetDir, 'nw');
- const dest = resolve(targetDir, `${ pkg.name }`);
- return rename(src, dest);
- }
- protected async prepareWinBuild(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- await this.updateWinResources(targetDir, appRoot, pkg, config);
- }
- protected async prepareMacBuild(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- await this.updateHelperPlist(targetDir, appRoot, pkg, config);
- await this.updatePlist(targetDir, appRoot, pkg, config);
- await this.updateMacIcons(targetDir, appRoot, pkg, config);
- await this.fixMacMeta(targetDir, appRoot, pkg, config);
- }
- protected async prepareLinuxBuild(targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- await this.fixLinuxMode(targetDir, appRoot, pkg, config);
- }
- protected async copyFiles(platform: string, targetDir: string, appRoot: string, pkg: any, config: BuildConfig) {
- const generalExcludes = [
- '**/node_modules/.bin',
- '**/node_modules/*/{ example, examples, test, tests }',
- '**/{ .DS_Store, .git, .hg, .svn, *.log }',
- ];
- const dependenciesExcludes = await findExcludableDependencies(this.dir, pkg)
- .then((excludable) => {
- return excludable.map(excludable => [ excludable, `${ excludable }/**/*` ]);
- })
- .then((excludes) => {
- return Array.prototype.concat.apply([], excludes);
- });
- debug('in copyFiles', 'dependenciesExcludes', dependenciesExcludes);
- const ignore = [
- ...config.excludes,
- ...generalExcludes,
- ...dependenciesExcludes,
- ...[ config.output, `${ config.output }/**/*` ]
- ];
- debug('in copyFiles', 'ignore', ignore);
- const files: string[] = await globby(config.files, {
- cwd: this.dir,
- // TODO: https://github.com/isaacs/node-glob#options, warn for cyclic links.
- follow: true,
- mark: true,
- ignore,
- });
- debug('in copyFiles', 'config.files', config.files);
- debug('in copyFiles', 'files', files);
- if(config.packed) {
- switch(platform) {
- case 'win32':
- case 'win':
- case 'linux':
- const nwFile = await tmpName({
- postfix: '.zip',
- });
- await compress(this.dir, files.filter((file) => !file.endsWith('/')), 'zip', nwFile);
- const { path: tempDir } = await tmpDir();
- await this.writeStrippedManifest(resolve(tempDir, 'package.json'), pkg, config);
- await compress(tempDir, [ './package.json' ], 'zip', nwFile);
- await remove(tempDir);
- const executable = await findExecutable(platform, targetDir);
- await this.combineExecutable(executable, nwFile);
- await remove(nwFile);
- break;
- case 'darwin':
- case 'osx':
- case 'mac':
- for(const file of files) {
- await copyFileAsync(resolve(this.dir, file), resolve(appRoot, file));
- }
- await this.writeStrippedManifest(resolve(appRoot, 'package.json'), pkg, config);
- break;
- default:
- throw new Error('ERROR_UNKNOWN_PLATFORM');
- }
- }
- else {
- for(const file of files) {
- await copyFileAsync(resolve(this.dir, file), resolve(appRoot, file));
- }
- await this.writeStrippedManifest(resolve(appRoot, 'package.json'), pkg, config);
- }
- }
- protected async integrateFFmpeg(platform: string, arch: string, targetDir: string, pkg: any, config: BuildConfig) {
- const downloader = new FFmpegDownloader({
- platform, arch,
- version: config.nwVersion,
- useCaches: true,
- showProgress: this.options.mute ? false : true,
- destination: this.options.destination,
- });
- if(!this.options.mute) {
- console.info('Fetching FFmpeg prebuilt...', {
- platform: downloader.options.platform,
- arch: downloader.options.arch,
- version: downloader.options.version,
- });
- }
- const ffmpegDir = await downloader.fetchAndExtract();
- const src = await findFFmpeg(platform, ffmpegDir);
- const dest = await findFFmpeg(platform, targetDir);
- await copy(src, dest);
- }
- protected async buildNsisDiffUpdater(platform: string, arch: string, versionInfo: NsisVersionInfo, fromVersion: string, toVersion: string, pkg: any, config: BuildConfig) {
- const diffNsis = resolve(this.dir, config.output, `${ pkg.name }-${ toVersion }-from-${ fromVersion }-${ platform }-${ arch }-Update.exe`);
- const fromDir = resolve(this.dir, config.output, (await versionInfo.getVersion(fromVersion)).source);
- const toDir = resolve(this.dir, config.output, (await versionInfo.getVersion(toVersion)).source);
- const data = await (new NsisDiffer(fromDir, toDir, {
- // Basic.
- appName: config.win.productName,
- companyName: config.win.companyName,
- description: config.win.fileDescription,
- version: fixWindowsVersion(config.win.productVersion),
- copyright: config.win.copyright,
- icon: config.nsis.icon ? resolve(this.dir, config.nsis.icon) : undefined,
- unIcon: config.nsis.unIcon ? resolve(this.dir, config.nsis.unIcon) : undefined,
- // Compression.
- compression: 'lzma',
- solid: true,
- languages: config.nsis.languages,
- installDirectory: config.nsis.installDirectory,
- // Output.
- output: diffNsis,
- })).make();
- const script = await tmpName();
- await writeFile(script, data);
- await nsisBuild(toDir, script, {
- mute: this.options.mute,
- });
- await remove(script);
- await versionInfo.addUpdater(toVersion, fromVersion, arch, diffNsis);
- }
- protected async buildDirTarget(platform: string, arch: string, runtimeDir: string, pkg: any, config: BuildConfig): Promise<string> {
- const targetDir = resolve(this.dir, config.output, this.parseOutputPattern(config.outputPattern, {
- name: pkg.name,
- version: pkg.version,
- platform, arch,
- }, pkg, config));
- const runtimeRoot = await findRuntimeRoot(platform, runtimeDir);
- const appRoot = resolve(targetDir, (() => {
- switch(platform) {
- case 'win32':
- case 'win':
- case 'linux':
- return './';
- case 'darwin':
- case 'osx':
- case 'mac':
- return './nwjs.app/Contents/Resources/app.nw/';
- default:
- throw new Error('ERROR_UNKNOWN_PLATFORM');
- }
- })());
- await emptyDir(targetDir);
- await copy(runtimeRoot, targetDir, {
- //dereference: true,
- });
- if(config.ffmpegIntegration) {
- await this.integrateFFmpeg(platform, arch, targetDir, pkg, config);
- }
- await ensureDir(appRoot);
- // Copy before refining might void the effort.
- switch(platform) {
- case 'win32':
- case 'win':
- await this.prepareWinBuild(targetDir, appRoot, pkg, config);
- await this.copyFiles(platform, targetDir, appRoot, pkg, config);
- await this.renameWinApp(targetDir, appRoot, pkg, config);
- break;
- case 'darwin':
- case 'osx':
- case 'mac':
- await this.prepareMacBuild(targetDir, appRoot, pkg, config);
- await this.copyFiles(platform, targetDir, appRoot, pkg, config);
- // rename Helper before main app rename.
- await this.renameMacHelperApp(targetDir, appRoot, pkg, config);
- await this.renameMacApp(targetDir, appRoot, pkg, config);
- break;
- case 'linux':
- await this.prepareLinuxBuild(targetDir, appRoot, pkg, config);
- await this.copyFiles(platform, targetDir, appRoot, pkg, config);
- await this.renameLinuxApp(targetDir, appRoot, pkg, config);
- break;
- default:
- throw new Error('ERROR_UNKNOWN_PLATFORM');
- }
- return targetDir;
- }
- protected async buildArchiveTarget(type: string, sourceDir: string) {
- const targetArchive = resolve(dirname(sourceDir), `${ basename(sourceDir) }.${ type }`);
- await remove(targetArchive);
- const files = await globby([ '**/*' ], {
- cwd: sourceDir,
- });
- await compress(sourceDir, files, type, targetArchive);
- return targetArchive;
- }
- protected async buildNsisTarget(platform: string, arch: string, sourceDir: string, pkg: any, config: BuildConfig) {
- if(platform != 'win') {
- if(!this.options.mute) {
- console.info(`Skip building nsis target for ${ platform }.`);
- }
- return;
- }
- const versionInfo = new NsisVersionInfo(resolve(this.dir, config.output, 'versions.nsis.json'));
- const targetNsis = resolve(dirname(sourceDir), `${ basename(sourceDir) }-Setup.exe`);
- const data = await (new NsisComposer({
- // Basic.
- appName: config.win.productName,
- companyName: config.win.companyName,
- description: config.win.fileDescription,
- version: fixWindowsVersion(config.win.productVersion),
- copyright: config.win.copyright,
- icon: config.nsis.icon ? resolve(this.dir, config.nsis.icon) : undefined,
- unIcon: config.nsis.unIcon ? resolve(this.dir, config.nsis.unIcon) : undefined,
- // Compression.
- compression: 'lzma',
- solid: true,
- languages: config.nsis.languages,
- installDirectory: config.nsis.installDirectory,
- // Output.
- output: targetNsis,
- })).make();
- const script = await tmpName();
- await writeFile(script, data);
- await nsisBuild(sourceDir, script, {
- mute: this.options.mute,
- });
- await remove(script);
- await versionInfo.addVersion(pkg.version, '', sourceDir);
- await versionInfo.addInstaller(pkg.version, arch, targetNsis);
- if(config.nsis.diffUpdaters) {
- for(const version of await versionInfo.getVersions()) {
- if(semver.gt(pkg.version, version)) {
- await this.buildNsisDiffUpdater(platform, arch, versionInfo, version, pkg.version, pkg, config);
- }
- }
- }
- await versionInfo.save();
- }
- protected async buildNsis7zTarget(platform: string, arch: string, sourceDir: string, pkg: any, config: BuildConfig) {
- if(platform != 'win') {
- if(!this.options.mute) {
- console.info(`Skip building nsis7z target for ${ platform }.`);
- }
- return;
- }
- const sourceArchive = await this.buildArchiveTarget('7z', sourceDir);
- const versionInfo = new NsisVersionInfo(resolve(this.dir, config.output, 'versions.nsis.json'));
- const targetNsis = resolve(dirname(sourceDir), `${ basename(sourceDir) }-Setup.exe`);
- const data = await (new Nsis7Zipper(sourceArchive, {
- // Basic.
- appName: config.win.productName,
- companyName: config.win.companyName,
- description: config.win.fileDescription,
- version: fixWindowsVersion(config.win.productVersion),
- copyright: config.win.copyright,
- icon: config.nsis.icon ? resolve(this.dir, config.nsis.icon) : undefined,
- unIcon: config.nsis.unIcon ? resolve(this.dir, config.nsis.unIcon) : undefined,
- // Compression.
- compression: 'lzma',
- solid: true,
- languages: config.nsis.languages,
- installDirectory: config.nsis.installDirectory,
- // Output.
- output: targetNsis,
- })).make();
- const script = await tmpName();
- await writeFile(script, data);
- await nsisBuild(sourceDir, script, {
- mute: this.options.mute,
- });
- await remove(script);
- await versionInfo.addVersion(pkg.version, '', sourceDir);
- await versionInfo.addInstaller(pkg.version, arch, targetNsis);
- if(config.nsis.diffUpdaters) {
- for(const version of await versionInfo.getVersions()) {
- if(semver.gt(pkg.version, version)) {
- await this.buildNsisDiffUpdater(platform, arch, versionInfo, version, pkg.version, pkg, config);
- }
- }
- }
- await versionInfo.save();
- }
- protected async buildTask(platform: string, arch: string, pkg: any, config: BuildConfig) {
- if(platform === 'mac' && arch === 'x86' && !config.nwVersion.includes('0.12.3')) {
- if(!this.options.mute) {
- console.info(`The NW.js binary for ${ platform }, ${ arch } isn't available for ${ config.nwVersion }, skipped.`);
- }
- throw new Error('ERROR_TASK_MAC_X86_SKIPPED');
- }
- const downloader = new Downloader({
- platform, arch,
- version: config.nwVersion,
- flavor: config.nwFlavor,
- mirror: this.options.mirror,
- useCaches: true,
- showProgress: this.options.mute ? false : true,
- destination: this.options.destination,
- });
- if(!this.options.mute) {
- console.info('Fetching NW.js binary...', {
- platform: downloader.options.platform,
- arch: downloader.options.arch,
- version: downloader.options.version,
- flavor: downloader.options.flavor,
- });
- }
- const runtimeDir = await downloader.fetchAndExtract();
- if(!this.options.mute) {
- console.info('Building targets...');
- }
- const started = Date.now();
- if(!this.options.mute) {
- console.info(`Building directory target starts...`);
- }
- const targetDir = await this.buildDirTarget(platform, arch, runtimeDir, pkg, config);
- if(!this.options.mute) {
- console.info(`Building directory target ends within ${ this.getTimeDiff(started) }s.`);
- }
- // TODO: Consider using `Bluebird.map` to enable concurrent target building.
- for(const target of config.targets) {
- const started = Date.now();
- switch(target) {
- case 'zip':
- case '7z':
- if(!this.options.mute) {
- console.info(`Building ${ target } archive target starts...`);
- }
- await this.buildArchiveTarget(target, targetDir);
- if(!this.options.mute) {
- console.info(`Building ${ target } archive target ends within ${ this.getTimeDiff(started) }s.`);
- }
- break;
- case 'nsis':
- if(!this.options.mute) {
- console.info(`Building nsis target starts...`);
- }
- await this.buildNsisTarget(platform, arch, targetDir, pkg, config);
- if(!this.options.mute) {
- console.info(`Building nsis target ends within ${ this.getTimeDiff(started) }s.`);
- }
- break;
- case 'nsis7z':
- if(!this.options.mute) {
- console.info(`Building nsis7z target starts...`);
- }
- await this.buildNsis7zTarget(platform, arch, targetDir, pkg, config);
- if(!this.options.mute) {
- console.info(`Building nsis7z target ends within ${ this.getTimeDiff(started) }s.`);
- }
- break;
- default:
- throw new Error('ERROR_UNKNOWN_TARGET');
- }
- }
- }
- }
|