From 0022b8696c13fa9de7df5e378007ef9aa85cc7b5 Mon Sep 17 00:00:00 2001 From: develar Date: Tue, 12 Jul 2016 19:54:01 +0200 Subject: [PATCH] refactor: merge electron-packager --- package.json | 19 ++-- src/appInfo.ts | 5 +- src/linuxPackager.ts | 2 +- src/macPackager.ts | 10 +-- src/metadata.ts | 8 +- src/packager.ts | 2 +- src/packager/common.ts | 39 +++++++++ src/packager/dirPackager.ts | 64 ++++++++++++++ src/packager/linux.ts | 12 +++ src/packager/mac.ts | 124 +++++++++++++++++++++++++++ src/packager/win32.ts | 24 ++++++ src/platformPackager.ts | 29 +++---- src/targets/nsis.ts | 4 +- src/targets/squirrelWindows.ts | 4 +- src/util/deepAssign.ts | 24 +++--- src/util/filter.ts | 2 +- src/util/log.ts | 3 +- src/util/util.ts | 6 +- src/winPackager.ts | 5 +- test/src/BuildTest.ts | 4 +- test/src/helpers/avaEx.ts | 4 - test/src/helpers/fileAssert.ts | 12 ++- test/src/helpers/packTester.ts | 4 +- test/src/macPackagerTest.ts | 6 +- test/src/winPackagerTest.ts | 6 +- typings/electron-packager.d.ts | 84 ------------------ {test/typings => typings}/plist.d.ts | 1 + 27 files changed, 338 insertions(+), 169 deletions(-) create mode 100644 src/packager/common.ts create mode 100644 src/packager/dirPackager.ts create mode 100644 src/packager/linux.ts create mode 100644 src/packager/mac.ts create mode 100644 src/packager/win32.ts delete mode 100644 typings/electron-packager.d.ts rename {test/typings => typings}/plist.d.ts (62%) diff --git a/package.json b/package.json index 453cf5a3c21..c5e25913e24 100644 --- a/package.json +++ b/package.json @@ -17,13 +17,13 @@ "compile": "npm run compile-production && npm run compile-test", "compile-production": "ts-babel", "compile-test": "ts-babel test", - "lint": "tslint src/*.ts test/src/*.ts", + "lint": "tslint src/**/*.ts test/src/**/*.ts", "pretest": "npm run compile && npm run lint", "test": "node ./test/out/helpers/runTests.js", "semantic-release": "semantic-release pre && npm publish && semantic-release post", "//": "Update wiki if docs changed. Update only if functionalily are generally available (latest release, not next)", "update-wiki": "git subtree split -b wiki --prefix docs/ && git push -f wiki wiki:master", - "whitespace": "whitespace src/*.ts", + "whitespace": "whitespace src/**/*.ts", "docker-images": "docker/build.sh" }, "repository": { @@ -65,9 +65,10 @@ "chalk": "^1.1.3", "cli-cursor": "^1.0.2", "debug": "^2.2.0", + "electron-download": "^2.1.2", "electron-osx-sign": "^0.4.0-beta4", - "electron-packager-tf": "~7.5.3", - "electron-winstaller-fixed": "~2.11.7", + "electron-winstaller-fixed": "~3.0.0", + "extract-zip": "^1.5.0", "fs-extra-p": "^1.0.5", "hosted-git-info": "^2.1.5", "image-size": "^0.5.0", @@ -75,9 +76,11 @@ "mime": "^1.3.4", "minimatch": "^3.0.2", "path-sort": "^0.1.0", + "plist": "^1.2.0", "pretty-ms": "^2.1.0", "progress": "^1.1.8", "progress-stream": "^1.2.0", + "rcedit": "^0.5.1", "read-package-json": "^2.0.4", "sanitize-filename": "^1.6.0", "semver": "^5.2.0", @@ -100,6 +103,7 @@ ] }, "devDependencies": { + "@develar/semantic-release": "^6.3.1", "@types/debug": "0.0.27-alpha", "@types/mime": "0.0.27-alpha", "@types/progress": "^1.1.26-alpha", @@ -108,19 +112,16 @@ "ava-tf": "^0.15.3", "babel-plugin-array-includes": "^2.0.3", "babel-plugin-transform-es2015-destructuring": "^6.9.0", - "babel-plugin-transform-es2015-parameters": "^6.9.0", + "babel-plugin-transform-es2015-parameters": "^6.11.3", "babel-plugin-transform-es2015-spread": "^6.8.0", "decompress-zip": "^0.3.0", "diff": "^2.2.3", - "electron-download": "^2.1.2", "json8": "^0.9.0", - "plist": "^1.2.0", "pre-git": "^3.10.0", - "@develar/semantic-release": "^6.3.1", "should": "^9.0.2", "ts-babel": "^1.0.3", "tslint": "3.13.0", - "typescript": "2.0.0-dev.20160620-1.0", + "typescript": "^2.1.0-dev.20160712", "whitespace": "^2.0.0" }, "babel": { diff --git a/src/appInfo.ts b/src/appInfo.ts index 6dfca99a948..fe8059b7be6 100644 --- a/src/appInfo.ts +++ b/src/appInfo.ts @@ -1,4 +1,3 @@ -import { ElectronPackagerOptions } from "electron-packager-tf" import { DevMetadata, AppMetadata } from "./metadata" import { warn } from "./util/log" import { smarten } from "./platformPackager" @@ -30,7 +29,7 @@ export class AppInfo { constructor(public metadata: AppMetadata, private devMetadata: DevMetadata, buildVersion?: string | null) { this.version = metadata.version! - this.buildNumber = this.devMetadata.build["build-version"] || process.env.TRAVIS_BUILD_NUMBER || process.env.APPVEYOR_BUILD_NUMBER || process.env.CIRCLE_BUILD_NUM || process.env.BUILD_NUMBER + this.buildNumber = (this.devMetadata.build)["build-version"] || process.env.TRAVIS_BUILD_NUMBER || process.env.APPVEYOR_BUILD_NUMBER || process.env.CIRCLE_BUILD_NUM || process.env.BUILD_NUMBER if (isEmptyOrSpaces(buildVersion)) { buildVersion = this.version @@ -75,7 +74,7 @@ export class AppInfo { } get copyright(): string { - const copyright = (this.devMetadata.build)["app-copyright"] + const copyright = (this.devMetadata.build)["app-copyright"] if (copyright != null) { return copyright } diff --git a/src/linuxPackager.ts b/src/linuxPackager.ts index e71a6ede022..b107bc2e2e8 100755 --- a/src/linuxPackager.ts +++ b/src/linuxPackager.ts @@ -61,7 +61,7 @@ export class LinuxPackager extends PlatformPackager { async pack(outDir: string, arch: Arch, targets: Array, postAsyncTasks: Array>): Promise { const appOutDir = this.computeAppOutDir(outDir, arch) - await this.doPack(await this.computePackOptions(outDir, appOutDir, arch), outDir, appOutDir, arch, this.platformSpecificBuildOptions) + await this.doPack(await this.computePackOptions(), outDir, appOutDir, this.platform.nodeName, arch, this.platformSpecificBuildOptions) postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, arch, targets)) } diff --git a/src/macPackager.ts b/src/macPackager.ts index 0981496da6d..1473b7dc295 100644 --- a/src/macPackager.ts +++ b/src/macPackager.ts @@ -69,14 +69,14 @@ export default class MacPackager extends PlatformPackager { } async pack(outDir: string, arch: Arch, targets: Array, postAsyncTasks: Array>): Promise { - const packOptions = await this.computePackOptions(outDir, this.computeAppOutDir(outDir, arch), arch) + const packOptions = await this.computePackOptions() let nonMasPromise: Promise | null = null const hasMas = targets.length !== 0 && targets.some(it => it.name === "mas") if (!hasMas || targets.length > 1) { const appOutDir = this.computeAppOutDir(outDir, arch) - nonMasPromise = this.doPack(packOptions, outDir, appOutDir, arch, this.platformSpecificBuildOptions) + nonMasPromise = this.doPack(packOptions, outDir, appOutDir, this.platform.nodeName, arch, this.platformSpecificBuildOptions) .then(() => this.sign(appOutDir, null)) .then(() => { this.packageInDistributableFormat(appOutDir, targets, postAsyncTasks) @@ -88,11 +88,7 @@ export default class MacPackager extends PlatformPackager { const appOutDir = path.join(outDir, "mas") const masBuildOptions = deepAssign({}, this.platformSpecificBuildOptions, (this.devMetadata.build)["mas"]) //noinspection JSUnusedGlobalSymbols - await this.doPack(Object.assign({}, packOptions, { - platform: "mas", - "osx-sign": false, - generateFinalBasename: function () { return "mas" } - }), outDir, appOutDir, arch, masBuildOptions) + await this.doPack(packOptions, outDir, appOutDir, "mas", arch, masBuildOptions) await this.sign(appOutDir, masBuildOptions) } diff --git a/src/metadata.ts b/src/metadata.ts index b147bb8737b..1f40cfb4e7f 100755 --- a/src/metadata.ts +++ b/src/metadata.ts @@ -1,5 +1,5 @@ -import { ElectronPackagerOptions } from "electron-packager-tf" import { AsarOptions } from "asar" +import { ElectronPackagerOptions } from "./packager/dirPackager" export interface Metadata { readonly repository?: string | RepositoryInfo | null @@ -185,8 +185,6 @@ export interface BuildMetadata { */ readonly compression?: CompressionLevel | null - readonly "build-version"?: string | null - /* *programmatic API only* The function to be run after pack (but before pack into distributable format and sign). Promise must be returned. */ @@ -535,6 +533,10 @@ export enum Arch { ia32, x64 } +export function archToString(arch: Arch): string { + return arch === Arch.ia32 ? "ia32" : "x64" +} + export function archFromString(name: string): Arch { if (name === "x64") { return Arch.x64 diff --git a/src/packager.ts b/src/packager.ts index 07ec80452a7..bfb4d9a1534 100644 --- a/src/packager.ts +++ b/src/packager.ts @@ -250,7 +250,7 @@ export function normalizePlatforms(rawPlatforms: Array | stri } function checkConflictingOptions(options: any) { - for (let name of ["all", "out", "tmpdir", "version", "platform", "dir", "arch", "name"]) { + for (let name of ["all", "out", "tmpdir", "version", "platform", "dir", "arch", "name", "extra-resource"]) { if (name in options) { throw new Error(`Option ${name} is ignored, do not specify it.`) } diff --git a/src/packager/common.ts b/src/packager/common.ts new file mode 100644 index 00000000000..c08ccc47e8b --- /dev/null +++ b/src/packager/common.ts @@ -0,0 +1,39 @@ +import * as path from "path" +import { ElectronPackagerOptions } from "./dirPackager" + +export function userIgnoreFilter(opts: ElectronPackagerOptions, appDir: string) { + let ignore = opts.ignore || [] + let ignoreFunc: any + + if (typeof (ignore) === "function") { + ignoreFunc = function (file: string) { return !ignore(file) } + } + else { + if (!Array.isArray(ignore)) { + ignore = [ignore] + } + + ignoreFunc = function (file: string) { + for (let i = 0; i < ignore.length; i++) { + if (file.match(ignore[i])) { + return false + } + } + + return true + } + } + + return function filter(file: string) { + let name = file.split(path.resolve(appDir))[1] + if (path.sep === "\\") { + // convert slashes so unix-format ignores work + name = name.replace(/\\/g, "/") + } + return ignoreFunc(name) + } +} + +export function initializeApp(opts: any, buildDir: string, appRelativePath: string) { + return opts.initializeApp(opts, buildDir, appRelativePath) +} \ No newline at end of file diff --git a/src/packager/dirPackager.ts b/src/packager/dirPackager.ts new file mode 100644 index 00000000000..09b838182b0 --- /dev/null +++ b/src/packager/dirPackager.ts @@ -0,0 +1,64 @@ +import { Promise as BluebirdPromise } from "bluebird" +import { emptyDir } from "fs-extra-p" +import { warn } from "../util/log" +import { AppInfo } from "../appInfo" + +const downloadElectron: (options: any) => Promise = BluebirdPromise.promisify(require("electron-download")) +const extract: any = BluebirdPromise.promisify(require("extract-zip")) + +//noinspection JSUnusedLocalSymbols +const __awaiter = require("../util/awaiter") + +export interface ElectronPackagerOptions { + "extend-info"?: string + "app-category-type"?: string + appBundleId: string + + protocols?: any + + appInfo: AppInfo + + icon?: string; + + "app-bundle-id"?: string | null; + + "helper-bundle-id"?: string | null; + + ignore?: any + + initializeApp?: (opts: ElectronPackagerOptions, buildDir: string, appRelativePath: string) => Promise +} + +const supportedPlatforms: any = { + // Maps to module ID for each platform (lazy-required if used) + darwin: "./mac", + linux: "./linux", + mas: "./mac", // map to darwin + win32: "./win32" +} + +function createDownloadOpts(opts: any, platform: string, arch: string, electronVersion: string) { + const downloadOpts = Object.assign({ + cache: opts.cache, + strictSSL: opts["strict-ssl"] + }, opts.download) + + subOptionWarning(downloadOpts, "download", "platform", platform) + subOptionWarning(downloadOpts, "download", "arch", arch) + subOptionWarning(downloadOpts, "download", "version", electronVersion) + return downloadOpts +} + +function subOptionWarning (properties: any, optionName: any, parameter: any, value: any) { + if (properties.hasOwnProperty(parameter)) { + warn(`${optionName}.${parameter} will be inferred from the main options`) + } + properties[parameter] = value +} + +export async function pack(opts: ElectronPackagerOptions, out: string, platform: string, arch: string, electronVersion: string) { + const zipPath = await downloadElectron(createDownloadOpts(opts, platform, arch, electronVersion)) + await emptyDir(out) + await extract(zipPath, {dir: out}) + await require(supportedPlatforms[platform]).createApp(opts, out) +} \ No newline at end of file diff --git a/src/packager/linux.ts b/src/packager/linux.ts new file mode 100644 index 00000000000..cc627242e37 --- /dev/null +++ b/src/packager/linux.ts @@ -0,0 +1,12 @@ +import { rename } from "fs-extra-p" +import * as path from "path" +import { initializeApp } from "./common" +import { ElectronPackagerOptions } from "./dirPackager" +import { Promise as BluebirdPromise } from "bluebird" + +export function createApp(opts: ElectronPackagerOptions, buildDir: string) { + return BluebirdPromise.all([ + initializeApp(opts, buildDir, path.join("resources", "app")), + rename(path.join(buildDir, "electron"), path.join(buildDir, opts.appInfo.productFilename)) + ]) +} \ No newline at end of file diff --git a/src/packager/mac.ts b/src/packager/mac.ts new file mode 100644 index 00000000000..89e6ad353df --- /dev/null +++ b/src/packager/mac.ts @@ -0,0 +1,124 @@ +import { ElectronPackagerOptions } from "./dirPackager" +import { rename, readFile, writeFile, copy } from "fs-extra-p" +import * as path from "path" +import { parse as parsePlist, build as buildPlist } from "plist" +import { Promise as BluebirdPromise } from "bluebird" +import { initializeApp } from "./common" + +//noinspection JSUnusedLocalSymbols +const __awaiter = require("../util/awaiter") + +function doRename (basePath: string, oldName: string, newName: string) { + return rename(path.join(basePath, oldName), path.join(basePath, newName)) +} + +function moveHelpers (frameworksPath: string, appName: string) { + return BluebirdPromise.map([" Helper", " Helper EH", " Helper NP"], suffix => { + const executableBasePath = path.join(frameworksPath, `Electron${suffix}.app`, "Contents", "MacOS") + return doRename(executableBasePath, `Electron${suffix}`, appName + suffix) + .then(() => doRename(frameworksPath, `Electron${suffix}.app`, `${appName}${suffix}.app`)) + }) +} + +function filterCFBundleIdentifier(identifier: string) { + // Remove special characters and allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.) + // Apple documentation: https://developer.apple.com/library/mac/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/20001431-102070 + return identifier.replace(/ /g, "-").replace(/[^a-zA-Z0-9.-]/g, "") +} + +export async function createApp(opts: ElectronPackagerOptions, tempPath: string) { + const appFilename = opts.appInfo.productFilename + + const finalAppPath = path.join(tempPath, `${appFilename}.app`) + const contentsPath = path.join(tempPath, "Electron.app", "Contents") + const frameworksPath = path.join(contentsPath, "Frameworks") + + const appPlistFilename = path.join(contentsPath, "Info.plist") + const helperPlistFilename = path.join(frameworksPath, "Electron Helper.app", "Contents", "Info.plist") + const helperEHPlistFilename = path.join(frameworksPath, "Electron Helper EH.app", "Contents", "Info.plist") + const helperNPPlistFilename = path.join(frameworksPath, "Electron Helper NP.app", "Contents", "Info.plist") + + const result = await BluebirdPromise.all([ + initializeApp(opts, tempPath, path.join("Electron.app", "Contents", "Resources", "app")), + BluebirdPromise.map([appPlistFilename, helperPlistFilename, helperEHPlistFilename, helperNPPlistFilename, opts["extend-info"]], it => it == null ? it : readFile(it, "utf8")) + ]) + const fileContents: Array = result[1]! + const appPlist = parsePlist(fileContents[0]) + const helperPlist = parsePlist(fileContents[1]) + const helperEHPlist = parsePlist(fileContents[2]) + const helperNPPlist = parsePlist(fileContents[3]) + + // If an extend-info file was supplied, copy its contents in first + if (fileContents[4] != null) { + Object.assign(appPlist, parsePlist(fileContents[4])) + } + + // Now set fields based on explicit options + + const appBundleIdentifier = filterCFBundleIdentifier(opts.appBundleId) + const helperBundleIdentifier = filterCFBundleIdentifier(opts["helper-bundle-id"] || `${appBundleIdentifier}.helper`) + + const appVersion = opts.appInfo.version + const buildVersion = opts.appInfo.buildVersion + const appCategoryType = opts["app-category-type"] + const humanReadableCopyright = opts.appInfo.copyright + + appPlist.CFBundleDisplayName = opts.appInfo.productName + appPlist.CFBundleIdentifier = appBundleIdentifier + appPlist.CFBundleName = opts.appInfo.productName + helperPlist.CFBundleDisplayName = `${opts.appInfo.productName} Helper` + helperPlist.CFBundleIdentifier = helperBundleIdentifier + appPlist.CFBundleExecutable = appFilename + helperPlist.CFBundleName = opts.appInfo.productName + helperPlist.CFBundleExecutable = `${appFilename} Helper` + helperEHPlist.CFBundleDisplayName = `${appFilename} Helper EH` + helperEHPlist.CFBundleIdentifier = `${helperBundleIdentifier}.EH` + helperEHPlist.CFBundleName = `${opts.appInfo.productName} Helper EH` + helperEHPlist.CFBundleExecutable = `${appFilename} Helper EH` + helperNPPlist.CFBundleDisplayName = `${opts.appInfo.productName} Helper NP` + helperNPPlist.CFBundleIdentifier = `${helperBundleIdentifier}.NP` + helperNPPlist.CFBundleName = `${opts.appInfo.productName} Helper NP` + helperNPPlist.CFBundleExecutable = `${appFilename} Helper NP` + + if (appVersion != null) { + appPlist.CFBundleShortVersionString = appPlist.CFBundleVersion = appVersion + } + + if (buildVersion != null) { + appPlist.CFBundleVersion = buildVersion + } + + if (opts.protocols && opts.protocols.length) { + appPlist.CFBundleURLTypes = opts.protocols.map(function (protocol: any) { + return { + CFBundleURLName: protocol.name, + CFBundleURLSchemes: [].concat(protocol.schemes) + } + }) + } + + if (appCategoryType) { + appPlist.LSApplicationCategoryType = appCategoryType + } + + if (humanReadableCopyright) { + appPlist.NSHumanReadableCopyright = humanReadableCopyright + } + + const promises: Array> = [ + writeFile(appPlistFilename, buildPlist(appPlist)), + writeFile(helperPlistFilename, buildPlist(helperPlist)), + writeFile(helperEHPlistFilename, buildPlist(helperEHPlist)), + writeFile(helperNPPlistFilename, buildPlist(helperNPPlist)), + doRename(path.join(contentsPath, "MacOS"), "Electron", appPlist.CFBundleExecutable) + ] + + if (opts.icon != null) { + promises.push(copy(opts.icon, path.join(contentsPath, "Resources", appPlist.CFBundleIconFile))) + } + + await BluebirdPromise.all(promises) + + await moveHelpers(frameworksPath, appFilename) + await rename(path.dirname(contentsPath), finalAppPath) +} \ No newline at end of file diff --git a/src/packager/win32.ts b/src/packager/win32.ts new file mode 100644 index 00000000000..db966a0b087 --- /dev/null +++ b/src/packager/win32.ts @@ -0,0 +1,24 @@ +import * as path from "path" +import { Promise as BluebirdPromise } from "bluebird" +import { rename } from "fs-extra-p" +import { ElectronPackagerOptions } from "./dirPackager" +import { initializeApp } from "./common" + +const rcedit: any = BluebirdPromise.promisify(require("rcedit")) + +export function createApp(opts: ElectronPackagerOptions, buildDir: string) { + const newExePath = path.join(buildDir, `${opts.appInfo.productFilename}.exe`) + return BluebirdPromise.all([ + initializeApp(opts, buildDir, path.join("resources", "app")), + rename(path.join(buildDir, "electron.exe"), newExePath) + .then(() => { + const appInfo = opts.appInfo + return rcedit(newExePath, { + "version-string": appInfo.versionString, + "file-version": appInfo.buildVersion, + "product-version": appInfo.version, + icon: opts.icon + }) + }) + ]) +} \ No newline at end of file diff --git a/src/platformPackager.ts b/src/platformPackager.ts index 8569f93aeda..1c9ae630776 100644 --- a/src/platformPackager.ts +++ b/src/platformPackager.ts @@ -1,8 +1,7 @@ -import { AppMetadata, DevMetadata, Platform, PlatformSpecificBuildOptions, Arch } from "./metadata" +import { AppMetadata, DevMetadata, Platform, PlatformSpecificBuildOptions, Arch, archToString } from "./metadata" import EventEmitter = NodeJS.EventEmitter import { Promise as BluebirdPromise } from "bluebird" import * as path from "path" -import { pack, ElectronPackagerOptions, userIgnoreFilter } from "electron-packager-tf" import { readdir, remove, realpath } from "fs-extra-p" import { statOrNull, use, unlinkIfExists, isEmptyOrSpaces } from "./util/util" import { Packager } from "./packager" @@ -14,6 +13,8 @@ import { deepAssign } from "./util/deepAssign" import { warn, log, task } from "./util/log" import { AppInfo } from "./appInfo" import { listDependencies, createFilter, copyFiltered, hasMagic } from "./util/filter" +import { ElectronPackagerOptions, pack } from "./packager/dirPackager" +import { userIgnoreFilter } from "./packager/common" //noinspection JSUnusedLocalSymbols const __awaiter = require("./util/awaiter") @@ -154,7 +155,7 @@ export abstract class PlatformPackager abstract pack(outDir: string, arch: Arch, targets: Array, postAsyncTasks: Array>): Promise - protected async doPack(options: ElectronPackagerOptions, outDir: string, appOutDir: string, arch: Arch, platformSpecificBuildOptions: DC) { + protected async doPack(options: ElectronPackagerOptions, outDir: string, appOutDir: string, platformName: string, arch: Arch, platformSpecificBuildOptions: DC) { const asarOptions = this.computeAsarOptions(platformSpecificBuildOptions) options.initializeApp = async (opts, buildDir, appRelativePath) => { const appPath = path.join(buildDir, appRelativePath) @@ -195,7 +196,7 @@ export abstract class PlatformPackager else { warn(`"ignore is deprecated, please use "files", see https://github.com/electron-userland/electron-builder/wiki/Options#BuildMetadata-files`) } - rawFilter = userIgnoreFilter(opts) + rawFilter = userIgnoreFilter(opts, this.info.appDir) } const filter = createFilter(this.info.appDir, this.getParsedPatterns(patterns, arch), ignoreFiles, rawFilter) @@ -211,7 +212,8 @@ export abstract class PlatformPackager await BluebirdPromise.all(promises) } - await task(`Packaging for platform ${this.platform.name} ${options.arch} using electron ${options.version} to ${path.relative(this.projectDir, appOutDir)}`, pack(options)) + await task(`Packaging for platform ${this.platform.name} ${archToString(arch)} using electron ${this.info.electronVersion} to ${path.relative(this.projectDir, appOutDir)}`, + pack(options, appOutDir, platformName, archToString(arch), this.info.electronVersion)) await this.doCopyExtraFiles(true, appOutDir, arch, platformSpecificBuildOptions) await this.doCopyExtraFiles(false, appOutDir, arch, platformSpecificBuildOptions) @@ -227,25 +229,16 @@ export abstract class PlatformPackager await this.sanityCheckPackage(appOutDir, asarOptions != null) } - protected async computePackOptions(outDir: string, appOutDir: string, arch: Arch): Promise { + protected async computePackOptions(): Promise { //noinspection JSUnusedGlobalSymbols const appInfo = this.appInfo const options: any = deepAssign({ - dir: this.info.appDir, - "app-bundle-id": appInfo.id, - out: outDir, + appBundleId: appInfo.id, name: appInfo.productName, productName: appInfo.productName, platform: this.platform.nodeName, - arch: Arch[arch], - version: this.info.electronVersion, icon: await this.getIconPath(), - overwrite: true, - "app-version": appInfo.version, - "app-copyright": appInfo.copyright, - "build-version": appInfo.buildVersion, - tmpdir: false, - generateFinalBasename: () => path.basename(appOutDir), + appInfo: appInfo, }, this.devMetadata.build) if (this.platform === Platform.WINDOWS) { @@ -275,7 +268,7 @@ export abstract class PlatformPackager return null } - const buildMetadata = this.devMetadata.build + const buildMetadata = this.devMetadata.build if (buildMetadata["asar-unpack"] != null) { warn("asar-unpack is deprecated, please set as asar.unpack") } diff --git a/src/targets/nsis.ts b/src/targets/nsis.ts index 049f3e19f4a..430fd64ab9f 100644 --- a/src/targets/nsis.ts +++ b/src/targets/nsis.ts @@ -1,5 +1,5 @@ import { WinPackager } from "../winPackager" -import { Arch, NsisOptions } from "../metadata" +import { Arch, NsisOptions, archToString } from "../metadata" import { exec, debug } from "../util/util" import * as path from "path" import { Promise as BluebirdPromise } from "bluebird" @@ -36,7 +36,7 @@ export default class NsisTarget extends Target { async build(arch: Arch, appOutDir: string) { const packager = this.packager - const archSuffix = arch == Arch.x64 ? "x64": "ia32" + const archSuffix = archToString(arch) const archiveFile = path.join(this.outDir, `${packager.appInfo.name}-${packager.appInfo.version}-${archSuffix}.nsis.7z`) this.archs.set(arch, task(`Creating NSIS ${archSuffix} package`, archiveApp(packager.devMetadata.build.compression, "7z", archiveFile, appOutDir, true))) } diff --git a/src/targets/squirrelWindows.ts b/src/targets/squirrelWindows.ts index 3a7130a8bf5..4996f020a46 100644 --- a/src/targets/squirrelWindows.ts +++ b/src/targets/squirrelWindows.ts @@ -4,7 +4,6 @@ import { Arch, WinBuildOptions } from "../metadata" import { createWindowsInstaller, convertVersion } from "electron-winstaller-fixed" import * as path from "path" import { warn } from "../util/log" -import { emptyDir } from "fs-extra-p" import { getRepositoryInfo } from "../repositoryInfo" //noinspection JSUnusedLocalSymbols @@ -23,10 +22,9 @@ export default class SquirrelWindowsTarget extends Target { const appInfo = this.packager.appInfo const version = appInfo.version const archSuffix = getArchSuffix(arch) - const setupFileName = `${appInfo.productFilename} Setup ${version}${archSuffix}.exe` + const setupFileName = `${appInfo.productFilename} Setup ${version}${archSuffix}.exe` const installerOutDir = path.join(appOutDir, "..", `win${getArchSuffix(arch)}`) - await emptyDir(installerOutDir) const distOptions = await this.computeEffectiveDistOptions(appOutDir, installerOutDir, setupFileName) await createWindowsInstaller(distOptions) diff --git a/src/util/deepAssign.ts b/src/util/deepAssign.ts index 56c50a4aef4..2d0683c8689 100644 --- a/src/util/deepAssign.ts +++ b/src/util/deepAssign.ts @@ -1,17 +1,17 @@ function isObject(x: any) { - const type = typeof x - return type === 'object' || type === 'function' + const type = typeof x + return type === "object" || type === "function" } function assignKey(to: any, from: any, key: string) { - const value = from[key] + const value = from[key] // https://github.com/electron-userland/electron-builder/pull/562 - if (value === undefined) { - return - } + if (value === undefined) { + return + } const prevValue = to[key] - if (prevValue == null || value === null || typeof prevValue !== 'object' || !isObject(value)) { + if (prevValue == null || value === null || typeof prevValue !== "object" || !isObject(value)) { to[key] = value } else { @@ -25,14 +25,14 @@ function assign(to: any, from: any) { assignKey(to, from, key) } } - return to + return to } export function deepAssign(target: any, ...objects: Array) { - for (let o of objects) { - if (o != null) { + for (let o of objects) { + if (o != null) { assign(target, o) } - } - return target + } + return target } \ No newline at end of file diff --git a/src/util/filter.ts b/src/util/filter.ts index 37239167014..8d039bc83af 100644 --- a/src/util/filter.ts +++ b/src/util/filter.ts @@ -21,7 +21,7 @@ export function hasMagic(pattern: Minimatch) { } for (let i of set[0]) { - if (typeof i !== 'string') { + if (typeof i !== "string") { return true } } diff --git a/src/util/log.ts b/src/util/log.ts index 69ad5272b0f..4b5a3897ec2 100644 --- a/src/util/log.ts +++ b/src/util/log.ts @@ -138,5 +138,4 @@ export function subTask(title: string, promise: BluebirdPromise | Promise | Promise): BluebirdPromise { return logger.task(title, promise) -} - +} \ No newline at end of file diff --git a/src/util/util.ts b/src/util/util.ts index c6dff900b64..a87bd5d6473 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -66,7 +66,7 @@ export interface ExecOptions extends BaseExecOptions { export function removePassword(input: string): string { return input.replace(/(-P |pass:)([^ ]+)/, function (match, p1, p2) { - return `${p1}${createHash('sha256').update(p2).digest('hex')} (sha256 hash)` + return `${p1}${createHash("sha256").update(p2).digest("hex")} (sha256 hash)` }) } @@ -237,5 +237,7 @@ export function isEmptyOrSpaces(s: string | n) { export function unlinkIfExists(file: string) { return unlink(file) - .catch(() => {}) + .catch(() => { + // ignore + }) } \ No newline at end of file diff --git a/src/winPackager.ts b/src/winPackager.ts index d70b2cbaefc..e5ad3fa8add 100644 --- a/src/winPackager.ts +++ b/src/winPackager.ts @@ -99,10 +99,9 @@ export class WinPackager extends PlatformPackager { } async pack(outDir: string, arch: Arch, targets: Array, postAsyncTasks: Array>): Promise { + const packOptions = await this.computePackOptions() const appOutDir = this.computeAppOutDir(outDir, arch) - const packOptions = await this.computePackOptions(outDir, appOutDir, arch) - - await this.doPack(packOptions, outDir, appOutDir, arch, this.platformSpecificBuildOptions) + await this.doPack(packOptions, outDir, appOutDir, this.platform.nodeName, arch, this.platformSpecificBuildOptions) await this.sign(path.join(appOutDir, `${this.appInfo.productFilename}.exe`)) this.packageInDistributableFormat(outDir, appOutDir, arch, targets, postAsyncTasks) } diff --git a/test/src/BuildTest.ts b/test/src/BuildTest.ts index 67c6c824589..aea852dad2d 100755 --- a/test/src/BuildTest.ts +++ b/test/src/BuildTest.ts @@ -174,14 +174,14 @@ test("afterPack", t => { build: { afterPack: () => { called++ - return Promise.resolve() + return BluebirdPromise.resolve() } } } }, { packed: () => { t.is(called, targets.size) - return Promise.resolve() + return BluebirdPromise.resolve() } }) }) diff --git a/test/src/helpers/avaEx.ts b/test/src/helpers/avaEx.ts index bb447fb23f8..7e4e10d440d 100644 --- a/test/src/helpers/avaEx.ts +++ b/test/src/helpers/avaEx.ts @@ -12,10 +12,6 @@ declare module "ava-tf" { export const ifDevOrLinuxCi: typeof test; export const ifNotTravis: typeof test; } - - interface AssertContext { - throws(value: (() => void) | Promise, error?: ErrorValidator, message?: string): void - } } Object.defineProperties(test, { diff --git a/test/src/helpers/fileAssert.ts b/test/src/helpers/fileAssert.ts index 88ae3cb7968..686a0e6c175 100644 --- a/test/src/helpers/fileAssert.ts +++ b/test/src/helpers/fileAssert.ts @@ -67,10 +67,14 @@ class Assertions { function prettyDiff(actual: any, expected: any): string { const diffJson2 = diffJson(expected, actual) const diff = diffJson2.map(part => { - if (part.added) return green(part.value.replace(/.+/g, ' - $&')) - if (part.removed) return red(part.value.replace(/.+/g, ' + $&')) - return gray(part.value.replace(/.+/g, ' | $&')) - }).join('') + if (part.added) { + return green(part.value.replace(/.+/g, " - $&")) + } + if (part.removed) { + return red(part.value.replace(/.+/g, " + $&")) + } + return gray(part.value.replace(/.+/g, " | $&")) + }).join("") return `\n${diff}\n` } diff --git a/test/src/helpers/packTester.ts b/test/src/helpers/packTester.ts index 14f76492ffb..5d975238827 100755 --- a/test/src/helpers/packTester.ts +++ b/test/src/helpers/packTester.ts @@ -191,7 +191,7 @@ function parseDebControl(info: string): any { value += match[3] } - if (value[value.length - 1] == "\n") { + if (value[value.length - 1] === "\n") { value = value.substring(0, value.length - 1) } metadata[match[1]] = value @@ -286,7 +286,7 @@ async function checkWindowsResult(packager: Packager, checkOptions: AssertPackOp if (appInfo.productFilename === "Test App ßW") { return `lib/net45/Test%20App%20%C3%9FW.exe` } - return `lib/net45/${encodeURI(appInfo.productFilename).replace(/%5B/g, '[').replace(/%5D/g, ']')}.exe` + return `lib/net45/${encodeURI(appInfo.productFilename).replace(/%5B/g, "[").replace(/%5D/g, "]")}.exe` } else { return it diff --git a/test/src/macPackagerTest.ts b/test/src/macPackagerTest.ts index c635615141d..00d8a04e55f 100644 --- a/test/src/macPackagerTest.ts +++ b/test/src/macPackagerTest.ts @@ -6,7 +6,7 @@ import * as path from "path" import { BuildInfo, PackagerOptions } from "out/platformPackager" import { Promise as BluebirdPromise } from "bluebird" import * as assertThat from "should/as-function" -import { ElectronPackagerOptions } from "electron-packager-tf" +import { ElectronPackagerOptions } from "out/packager/dirPackager" import { Platform, MacOptions, createTargets } from "out" import { SignOptions, FlatOptions } from "electron-osx-sign" import { Arch } from "out" @@ -205,7 +205,7 @@ test.ifOsx("disable dmg icon, bundleVersion", () => { packed: () => { assertThat(platformPackager.effectiveDistOptions.icon).equal(null) assertThat(platformPackager.effectivePackOptions.icon).not.equal(null) - assertThat(platformPackager.effectivePackOptions["build-version"]).equal("50") + assertThat(platformPackager.appInfo.buildVersion).equal("50") return BluebirdPromise.resolve(null) }, }) @@ -232,7 +232,7 @@ class CheckingMacPackager extends OsXPackager { return await super.pack(outDir, arch, targets, postAsyncTasks) } - async doPack(options: ElectronPackagerOptions, outDir: string, appOutDir: string, arch: Arch, customBuildOptions: MacOptions, postAsyncTasks: Array> = null) { + async doPack(options: ElectronPackagerOptions, outDir: string, appOutDir: string, platformName: string, arch: Arch, customBuildOptions: MacOptions, postAsyncTasks: Array> = null) { this.effectivePackOptions = options } diff --git a/test/src/winPackagerTest.ts b/test/src/winPackagerTest.ts index cd2f6dea635..14362d6802d 100755 --- a/test/src/winPackagerTest.ts +++ b/test/src/winPackagerTest.ts @@ -9,7 +9,7 @@ import { assertThat } from "./helpers/fileAssert" import { SignOptions } from "signcode-tf" import SquirrelWindowsTarget from "out/targets/squirrelWindows" import { Target } from "out/platformPackager" -import { ElectronPackagerOptions } from "electron-packager-tf" +import { ElectronPackagerOptions } from "out/packager/dirPackager" //noinspection JSUnusedLocalSymbols const __awaiter = require("out/util/awaiter") @@ -132,7 +132,7 @@ test.ifNotCiOsx("nsis boring, MUI_HEADER as option", () => { }) // very slow -test.ifWinCi("delta and msi", () => assertPack("test-app-one", { +test.skip("delta and msi", () => assertPack("test-app-one", { targets: Platform.WINDOWS.createTarget(null, Arch.ia32), devMetadata: { build: { @@ -243,7 +243,7 @@ class CheckingWinPackager extends WinPackager { // skip pack const appOutDir = this.computeAppOutDir(outDir, arch) - this.effectivePackOptions = await this.computePackOptions(outDir, appOutDir, arch) + this.effectivePackOptions = await this.computePackOptions() const helperClass: typeof SquirrelWindowsTarget = require("out/targets/squirrelWindows").default this.effectiveDistOptions = await (new helperClass(this).computeEffectiveDistOptions(appOutDir, "foo", "Foo.exe")) diff --git a/typings/electron-packager.d.ts b/typings/electron-packager.d.ts deleted file mode 100644 index 264793cd0ac..00000000000 --- a/typings/electron-packager.d.ts +++ /dev/null @@ -1,84 +0,0 @@ -declare module "electron-packager-tf" { - /** Electron-packager Options. */ - export interface ElectronPackagerOptions { - /** The source directory. */ - dir?: string; - /** The application name. */ - name?: string; - /** - * Allowed values: linux, win32, darwin, all. Not required if `all` is used. - * Arbitrary combinations of individual platforms are also supported via a comma-delimited string or array of strings. - */ - platform?: string | string[]; - /** Allowed values: ia32, x64, all Not required if `all` is used. */ - arch?: string; - /** Electron version (without the "v"). See https://github.com/atom/electron/releases. */ - version?: string; - - /** Shortcut for `--arch=all --platform=all`. */ - all?: boolean; - /** The output directory. */ - out?: string; - /** - * Currently you must look for conversion tools in order to supply an icon in the format required by the platform: - * - MacOS: `.icns` - * - Windows: `.ico` - * - * For Linux builds, this option is not required, as the dock/window list icon is set via the icon option in the BrowserWindow contructor. - * Setting the icon in the file manager is not currently supported. - * - * If the file extension is omitted, it is auto-completed to the correct extension based on the platform, - * including when `--platform=all` is in effect. - */ - icon?: string; - - /** The bundle identifier to use in the app plist. */ - "app-bundle-id"?: string | null; - /** The release version to set for the app. */ - "app-version"?: string; - /** The build version to set for the app (MacOS only). */ - "build-version"?: string | null; - /** The bundle identifier to use in the app helper plist. */ - "helper-bundle-id"?: string | null; - /** Object hash of application metadata to embed into the executable (Windows only). */ - "version-string"?: VersionString; - - /** The directory of cached electron downloads. Defaults to "$HOME/.electron". */ - cache?: string; - /** Do not copy files into App whose filenames regex .match this string. */ - ignore?: RegExp | Array; - /** Runs `npm prune --production` on the app. */ - prune?: boolean; - /** If output directory for a platform already exists, replaces it rather than skipping it. */ - overwrite?: boolean; - /** Packages the source code within your app into an archive. */ - asar?: boolean; - /** Unpacks the files to app.asar.unpacked directory whose filenames regex .match this string. */ - "asar-unpack"?: string; - "asar-unpack-dir"?: string; - /** Should contain the identity to be used when running `codesign` (MacOS only). */ - sign?: string; - - "app-copyright"?: string - - generateFinalBasename?: (context: any) => void - - initializeApp?: (opts: ElectronPackagerOptions, buildDir: string, appRelativePath: string) => Promise - } - - /** Object hash of application metadata to embed into the executable (Windows only). */ - export interface VersionString { - CompanyName?: string; - LegalCopyright?: string; - FileDescription?: string; - OriginalFilename?: string; - FileVersion?: string; - ProductVersion?: string; - ProductName?: string; - InternalName?: string; - } - - export function userIgnoreFilter(opts: ElectronPackagerOptions): any - - export function pack(opts: ElectronPackagerOptions): Promise -} \ No newline at end of file diff --git a/test/typings/plist.d.ts b/typings/plist.d.ts similarity index 62% rename from test/typings/plist.d.ts rename to typings/plist.d.ts index 3803dc20955..1a7f9b1a45a 100644 --- a/test/typings/plist.d.ts +++ b/typings/plist.d.ts @@ -1,4 +1,5 @@ declare module "plist" { export function parse(data: string): any + export function build(data: string): any } \ No newline at end of file