diff --git a/.idea/dictionaries/develar.xml b/.idea/dictionaries/develar.xml index 77bbf8f6852..634f0bacb07 100644 --- a/.idea/dictionaries/develar.xml +++ b/.idea/dictionaries/develar.xml @@ -64,6 +64,7 @@ winstaller xamarin xenial + yargs \ No newline at end of file diff --git a/README.md b/README.md index fb20e1f4a39..f353887eb0d 100755 --- a/README.md +++ b/README.md @@ -63,14 +63,11 @@ It costs only $59 (and 2 weeks), see [Where to buy code signing certificate](htt ```json "scripts": { "postinstall": "install-app-deps", - "pack": "build", + "pack": "build --target dir", "dist": "build" } ``` - And then you can run `npm run pack` or `npm run dist` (to package in a distributable format (e.g. dmg, windows installer, deb package)). - Both scripts are the same because If script named `dist` or name has prefix `dist:`, flag `--dist` is implied. - - Please note — if you don't name your script `dist` or prefix it with `dist:` and you don't pass `--dist` flag, application will be not packed in a distributable format. + And then you can run `npm run dist` (to package in a distributable format (e.g. dmg, windows installer, deb package)) or `npm run pack`. 5. Install [required system packages](https://github.com/electron-userland/electron-builder/wiki/Multi-Platform-Build). diff --git a/docker/Dockerfile b/docker/Dockerfile index 2dc7460dbf3..3ca510cae9b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -103,11 +103,7 @@ ENV BUNDLE_PATH="$GEM_HOME" \ ENV PATH $BUNDLE_BIN:$PATH RUN mkdir -p "$GEM_HOME" "$BUNDLE_BIN" \ && chmod 777 "$GEM_HOME" "$BUNDLE_BIN" \ - && mkdir -p /tmp/fpm && curl -L https://github.com/jordansissel/fpm/archive/6e2514df27664912826b4fcd89affa19df0e713b.tar.gz | tar -xz -C /tmp/fpm --strip-components 1 && cd /tmp/fpm && bundle install && make install && cd .. && rm -rf /tmp/fpm - -# use fpm commit https://github.com/jordansissel/fpm/commit/6e2514df27664912826b4fcd89affa19df0e713b because of some important unreleased fixes: -# https://github.com/jordansissel/fpm/commit/94be82c0a23c8cd641ab9e60f3eb4a8db445fff0 -# https://github.com/jordansissel/fpm/commit/77b95747b9cc01ca420ee24084a449b3ac19e6d5 + && mkdir -p /tmp/fpm && curl -L https://github.com/jordansissel/fpm/archive/5719990e1bbc3deeaea8a196d6aaa51421a058bd.tar.gz | tar -xz -C /tmp/fpm --strip-components 1 && cd /tmp/fpm && bundle install && make install && cd .. && rm -rf /tmp/fpm # we don't use our bundled fpm because it is better to build ruby & tools for specific platform - not generic. And easy to maintain (update ruby and so on). ENV USE_SYSTEM_FPM true diff --git a/docs/Options.md b/docs/Options.md index 5f54f3f0508..c27a224d339 100644 --- a/docs/Options.md +++ b/docs/Options.md @@ -71,7 +71,7 @@ See all [appdmg options](https://www.npmjs.com/package/appdmg#json-specification | --- | --- | icon | The path to icon, which will be shown when mounted (default: `build/icon.icns`). | background |

The path to background (default: build/background.png if exists). The resolution of this file determines the resolution of the installer window. If background is not specified, use window.size, see [specification](https://github.com/LinusU/node-appdmg#json-specification).

-| target | Target package type: list of `default`, `dmg`, `zip`, `mas`, `7z`, `tar.xz`, `tar.gz`, `tar.bz2`, `tar.7z`. Defaults to `default` (dmg and zip for Squirrel.Mac). +| target | Target package type: list of `default`, `dmg`, `mas`, `7z`, `zip`, `tar.xz`, `tar.lz`, `tar.gz`, `tar.bz2`. Defaults to `default` (dmg and zip for Squirrel.Mac). | identity |

The name of certificate to use when signing. Consider using environment variables [CSC_LINK or CSC_NAME](https://github.com/electron-userland/electron-builder/wiki/Code-Signing). MAS installer identity is specified in the [.build.mas](#MasBuildOptions-identity).

| entitlements |

The path to entitlements file for signing the app. build/osx.entitlements will be used if exists (it is a recommended way to set). MAS entitlements is specified in the [.build.mas](#MasBuildOptions-entitlements).

| entitlementsInherit |

The path to child entitlements which inherit the security settings for signing frameworks and bundles of a distribution. build/osx.inherit.entitlements will be used if exists (it is a recommended way to set). Otherwise [default](https://github.com/electron-userland/electron-osx-sign/blob/master/default.darwin.inherit.entitlements).

This option only applies when signing with entitlements provided.

diff --git a/package.json b/package.json index d74dfd25d17..f6a261c2c22 100644 --- a/package.json +++ b/package.json @@ -61,11 +61,10 @@ "asar": "^0.11.0", "bluebird": "^3.4.0", "chalk": "^1.1.3", - "command-line-args": "^2.1.6", "compare-versions": "^2.0.1", "debug": "^2.2.0", "deep-assign": "^2.0.0", - "electron-osx-sign-tf": "0.4.0-beta.0", + "electron-osx-sign-tf": "0.5.1", "electron-packager-tf": "~7.2.0", "electron-winstaller-fixed": "~2.9.3", "fs-extra-p": "^1.0.1", @@ -78,7 +77,8 @@ "progress-stream": "^1.2.0", "read-package-json": "^2.0.4", "signcode-tf": "~0.7.3", - "source-map-support": "^0.4.0" + "source-map-support": "^0.4.0", + "yargs": "^4.7.1" }, "optionalDependencies": { "appdmg": "^0.4.5" @@ -102,7 +102,7 @@ "path-sort": "^0.1.0", "plist": "^1.2.0", "pre-git": "^3.8.4", - "semantic-release": "^6.2.2", + "semantic-release": "^6.3.0", "should": "^8.4.0", "ts-babel": "^0.8.6", "tsconfig-glob": "^0.4.3", diff --git a/src/build-cli.ts b/src/build-cli.ts index 11818948fa4..fa1d4b49f95 100644 --- a/src/build-cli.ts +++ b/src/build-cli.ts @@ -1,47 +1,97 @@ #! /usr/bin/env node -import { PackagerOptions } from "./platformPackager" +import { PackagerOptions, commonTargets } from "./platformPackager" +import { normalizePlatforms } from "./packager" import { build } from "./builder" import { PublishOptions } from "./gitHubPublisher" import { printErrorAndExit } from "./promise" -import cla = require("command-line-args") -import { readFileSync } from "fs" -import * as path from "path" -import { warn } from "./util" +import yargs = require("yargs") +import { underline } from "chalk" +import { Platform } from "./metadata" //noinspection JSUnusedLocalSymbols const __awaiter = require("./awaiter") interface CliOptions extends PackagerOptions, PublishOptions { - help: boolean + osx?: Array + linux?: Array + win?: Array + + arch?: string + + x64?: boolean + ia32?: boolean +} + +const args = (yargs + .version() + .option("osx", { + alias: "o", + describe: "Build for OS X", + type: "array", + }) + .option("linux", { + alias: "l", + describe: "Build for Linux", + type: "array", + }) + .option("win", { + alias: ["w", "windows"], + describe: "Build for Windows", + type: "array", + }) + .option("x64", { + describe: "Build for x64", + type: "boolean", + }) + .option("ia32", { + describe: "Build for ia32", + type: "boolean", + }) + .option("target", { + alias: "t", + describe: "Target package types", + choices: commonTargets, + }) + .option("publish", { + alias: "p", + describe: `Publish artifacts (to GitHub Releases), see ${underline("https://goo.gl/WMlr4n")}`, + choices: ["onTag", "onTagOrDraft", "always", "never"], + }) + .option("platform", { + choices: ["osx", "win", "linux", "darwin", "win32", "all"], + }) + .option("arch", { + choices: ["ia32", "x64", "all"], + }) + .strict() + .help() + .epilog(`Project home: ${underline("https://github.com/electron-userland/electron-builder")}`) + .argv) + +const platforms = normalizePlatforms(args.platform) +if (args.osx != null && !platforms.includes(Platform.OSX)) { + platforms.push(Platform.OSX) } +if (args.linux != null && !platforms.includes(Platform.LINUX)) { + platforms.push(Platform.LINUX) +} +if (args.win != null && !platforms.includes(Platform.WINDOWS)) { + platforms.push(Platform.WINDOWS) +} + +const archAsProp = args.arch +const archs = archAsProp === "all" ? ["ia32", "x64"] : (archAsProp == null ? [] : [archAsProp]) -const cli = cla([ - {name: "dist", type: Boolean, alias: "d", description: "Whether to package in a distributable format (e.g. DMG, windows installer, NuGet package)."}, - {name: "publish", type: String, alias: "p", description: "Publish artifacts (to GitHub Releases): onTag (on tag push only) or onTagOrDraft (on tag push or if draft release exists)."}, - {name: "platform", type: String, multiple: true, description: "darwin, linux, win32 or all. Current platform (" + process.platform + ") by default."}, - {name: "arch", type: String, description: "ia32, x64 or all. Defaults to architecture you're running on."}, - {name: "sign", type: String}, - {name: "help", alias: "h", type: Boolean, description: "Display this usage guide."}, - {name: "appDir", type: String} -]) - -const args: CliOptions = cli.parse() - -if (args.help) { - const version = process.env.npm_package_version || JSON.parse(readFileSync(path.join(__dirname, "..", "package.json"), "utf8")).version - console.log(cli.getUsage({ - title: "electron-builder " + version, - footer: "Project home: [underline]{https://github.com/electron-userland/electron-builder}", - hide: ["appDir"], - })) +if (args.x64 && !archs.includes("x64")) { + archs.push("x64") } -else { - if (args.appDir) { - warn(`-appDir CLI parameter is deprecated, please configure build.directories.app instead -See https://github.com/electron-userland/electron-builder/wiki/Options#MetadataDirectories-app`) - } - - build(args) - .catch(printErrorAndExit) -} \ No newline at end of file +if (args.ia32 && !archs.includes("ia32")) { + archs.push("ia32") +} + +build(Object.assign({}, args, { + platform: platforms, + arch: archs, +})) + .catch(printErrorAndExit) \ No newline at end of file diff --git a/src/builder.ts b/src/builder.ts index 107108e2039..3dac1bb7acc 100644 --- a/src/builder.ts +++ b/src/builder.ts @@ -36,17 +36,9 @@ export async function build(originalOptions?: BuildOptions): Promise { options.platform = normalizePlatforms(options.platform) - const lifecycleEvent = process.env.npm_lifecycle_event - if (options.publish) { - options.dist = true - } - else if (options.dist === undefined) { - options.dist = lifecycleEvent === "dist" || lifecycleEvent === "build" || (lifecycleEvent != null && lifecycleEvent.startsWith("dist:")) - } - let isPublishOptionGuessed = false if (options.publish === undefined) { - if (lifecycleEvent === "release") { + if (process.env.npm_lifecycle_event === "release") { options.publish = "always" } else if (options.githubToken != null) { diff --git a/src/index.ts b/src/index.ts index 459e4a31fba..025d8655b3e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ export { Packager } from "./packager" -export { PackagerOptions, ArtifactCreated } from "./platformPackager" +export { PackagerOptions, ArtifactCreated, DIR_TARGET } from "./platformPackager" export { BuildOptions, build, createPublisher } from "./builder" export { PublishOptions, Publisher } from "./gitHubPublisher" export { AppMetadata, DevMetadata, Platform, getProductName, BuildMetadata, OsXBuildOptions, WinBuildOptions, LinuxBuildOptions } from "./metadata" \ No newline at end of file diff --git a/src/install-app-deps.ts b/src/install-app-deps.ts index 3c28ea53497..90864873578 100644 --- a/src/install-app-deps.ts +++ b/src/install-app-deps.ts @@ -3,14 +3,17 @@ import { computeDefaultAppDirectory, installDependencies, getElectronVersion, readPackageJson, use } from "./util" import { printErrorAndExit } from "./promise" import * as path from "path" -import cla = require("command-line-args") import { Promise as BluebirdPromise } from "bluebird" -import { DevMetadata } from "./metadata"; +import { DevMetadata } from "./metadata" +import yargs = require("yargs") //noinspection JSUnusedLocalSymbols const __awaiter = require("./awaiter") -const args = cla([{name: "arch", type: String}, {name: "appDir", type: String}]).parse() +const args: any = yargs + .option("arch", { + choices: ["ia32", "x64", "all"], + }).argv const projectDir = process.cwd() const devPackageFile = path.join(projectDir, "package.json") @@ -18,7 +21,7 @@ const devPackageFile = path.join(projectDir, "package.json") async function main() { const devMetadata: DevMetadata = await readPackageJson(devPackageFile) const results: Array = await BluebirdPromise.all([ - computeDefaultAppDirectory(projectDir, use(devMetadata.directories, it => it!.app) || args.appDir), + computeDefaultAppDirectory(projectDir, use(devMetadata.directories, it => it!.app)), getElectronVersion(devMetadata, devPackageFile) ]) diff --git a/src/linuxPackager.ts b/src/linuxPackager.ts index 800cdd49a21..eec0416b4a7 100755 --- a/src/linuxPackager.ts +++ b/src/linuxPackager.ts @@ -29,7 +29,7 @@ export class LinuxPackager extends PlatformPackager { description: this.metadata.description, }, this.customBuildOptions) - if (this.options.dist) { + if (!this.hasOnlyDirTarget()) { const tempDir = path.join(tmpdir(), getTempName("electron-builder-linux")) const tempDirPromise = emptyDir(tempDir) .then(() => { @@ -73,17 +73,15 @@ export class LinuxPackager extends PlatformPackager { const appOutDir = this.computeAppOutDir(outDir, arch) await this.doPack(this.computePackOptions(outDir, appOutDir, arch), outDir, appOutDir, arch, this.customBuildOptions) - if (this.options.dist) { - for (let target of this.targets) { - if (target === "zip" || target === "7z" || target.startsWith("tar.")) { - const destination = path.join(outDir, `${this.metadata.name}-${this.metadata.version}${archSuffix(arch)}.${target}`) - postAsyncTasks.push(this.archiveApp(target, appOutDir, destination) - .then(() => this.dispatchArtifactCreated(destination))) - } + for (let target of this.targets) { + if (target === "zip" || target === "7z" || target.startsWith("tar.")) { + const destination = path.join(outDir, `${this.metadata.name}-${this.metadata.version}${archSuffix(arch)}.${target}`) + postAsyncTasks.push(this.archiveApp(target, appOutDir, destination) + .then(() => this.dispatchArtifactCreated(destination))) } - - postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, arch)) } + + postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, arch)) } private async computeDesktop(tempDir: string): Promise> { @@ -196,10 +194,10 @@ Icon=${this.metadata.name} // todo fix fpm - if we run in parallel, get strange tar errors for (let target of this.targets) { target = target === "default" ? "deb" : target - if (target !== "zip" && target !== "7z" && !target.startsWith("tar.")) { + if (target !== "dir" && target !== "zip" && target !== "7z" && !target.startsWith("tar.")) { const destination = path.join(outDir, `${this.metadata.name}-${this.metadata.version}${archSuffix(arch)}.${target}`) await this.buildPackage(destination, target, this.buildOptions, appOutDir, arch) - .then(() => this.dispatchArtifactCreated(destination)) + this.dispatchArtifactCreated(destination) } } } diff --git a/src/metadata.ts b/src/metadata.ts index 55cfa5251c5..9dcbba97fa4 100755 --- a/src/metadata.ts +++ b/src/metadata.ts @@ -171,7 +171,7 @@ export interface OsXBuildOptions extends PlatformSpecificBuildOptions { readonly background?: string | null /* - Target package type: list of `default`, `dmg`, `zip`, `mas`, `7z`, `tar.xz`, `tar.gz`, `tar.bz2`, `tar.7z`. Defaults to `default` (dmg and zip for Squirrel.Mac). + Target package type: list of `default`, `dmg`, `mas`, `7z`, `zip`, `tar.xz`, `tar.lz`, `tar.gz`, `tar.bz2`. Defaults to `default` (dmg and zip for Squirrel.Mac). */ readonly target?: Array | null diff --git a/src/osxPackager.ts b/src/osxPackager.ts index 7b40470606c..26fd12a60a5 100644 --- a/src/osxPackager.ts +++ b/src/osxPackager.ts @@ -6,7 +6,6 @@ import { log, debug, warn } from "./util" import { createKeychain, deleteKeychain, CodeSigningInfo, generateKeychainName } from "./codeSign" import deepAssign = require("deep-assign") import { sign, flat, BaseSignOptions, SignOptions, FlatOptions } from "electron-osx-sign-tf" -import { readdir } from "fs-extra-p" //noinspection JSUnusedLocalSymbols const __awaiter = require("./awaiter") @@ -14,8 +13,6 @@ const __awaiter = require("./awaiter") export default class OsXPackager extends PlatformPackager { codeSigningInfo: Promise - readonly resourceList: Promise> - constructor(info: BuildInfo, cleanupTasks: Array<() => Promise>) { super(info) @@ -27,14 +24,6 @@ export default class OsXPackager extends PlatformPackager { else { this.codeSigningInfo = BluebirdPromise.resolve(null) } - - this.resourceList = readdir(this.buildResourcesDir) - .catch(e => { - if (e.code !== "ENOENT") { - throw e - } - return [] - }) } get platform() { @@ -53,9 +42,7 @@ export default class OsXPackager extends PlatformPackager { nonMasPromise = this.doPack(packOptions, outDir, appOutDir, arch, this.customBuildOptions) .then(() => this.sign(appOutDir, null)) .then(() => { - if (this.options.dist) { - postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, arch)) - } + postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, arch)) }) } @@ -76,8 +63,8 @@ export default class OsXPackager extends PlatformPackager { let codeSigningInfo = await this.codeSigningInfo if (codeSigningInfo == null) { codeSigningInfo = { - name: this.options.sign || process.env.CSC_NAME || this.customBuildOptions.identity, - installerName: this.options.sign || process.env.CSC_INSTALLER_NAME || (masOptions == null ? null : masOptions.identity), + name: process.env.CSC_NAME || this.customBuildOptions.identity, + installerName: process.env.CSC_INSTALLER_NAME || (masOptions == null ? null : masOptions.identity), } } @@ -191,39 +178,14 @@ export default class OsXPackager extends PlatformPackager { packageInDistributableFormat(outDir: string, appOutDir: string, arch: string): Promise { const promises: Array> = [] - - if (this.targets.includes("dmg") || this.targets.includes("default")) { - const artifactPath = path.join(appOutDir, `${this.appName}-${this.metadata.version}.dmg`) - promises.push(new BluebirdPromise(async(resolve, reject) => { - log("Creating DMG") - const dmgOptions = { - target: artifactPath, - basepath: this.projectDir, - specification: await this.computeEffectiveDistOptions(appOutDir), - } - - if (debug.enabled) { - debug(`appdmg: ${JSON.stringify(dmgOptions, null, 2)}`) - } - - const emitter = require("appdmg")(dmgOptions) - emitter.on("error", reject) - emitter.on("finish", () => resolve()) - if (debug.enabled) { - emitter.on("progress", (info: any) => { - if (info.type === "step-begin") { - debug(`appdmg: [${info.current}] ${info.title}`) - } - }) - } - }) - .then(() => this.dispatchArtifactCreated(artifactPath, `${this.metadata.name}-${this.metadata.version}.dmg`))) - } - for (let target of this.targets) { + if (target === "dmg" || target === "default") { + promises.push(this.createDmg(appOutDir)) + } + if (target !== "mas" && target !== "dmg") { - const format = target === "default" ? "zip" : target! - log("Creating OS X " + format) + const format = target === "default" ? "zip" : target + log(`Creating OS X ${format}`) // for default we use mac to be compatible with Squirrel.Mac const classifier = target === "default" ? "mac" : "osx" // we use app name here - see https://github.com/electron-userland/electron-builder/pull/204 @@ -234,4 +196,33 @@ export default class OsXPackager extends PlatformPackager { } return BluebirdPromise.all(promises) } + + private async createDmg(appOutDir: string) { + const artifactPath = path.join(appOutDir, `${this.appName}-${this.metadata.version}.dmg`) + await new BluebirdPromise(async(resolve, reject) => { + log("Creating DMG") + const dmgOptions = { + target: artifactPath, + basepath: this.projectDir, + specification: await this.computeEffectiveDistOptions(appOutDir), + } + + if (debug.enabled) { + debug(`appdmg: ${JSON.stringify(dmgOptions, null, 2)}`) + } + + const emitter = require("appdmg")(dmgOptions) + emitter.on("error", reject) + emitter.on("finish", () => resolve()) + if (debug.enabled) { + emitter.on("progress", (info: any) => { + if (info.type === "step-begin") { + debug(`appdmg: [${info.current}] ${info.title}`) + } + }) + } + }) + + this.dispatchArtifactCreated(artifactPath, `${this.metadata.name}-${this.metadata.version}.dmg`) + } } \ No newline at end of file diff --git a/src/packager.ts b/src/packager.ts index 2fd0029b7c8..c0da5a425d2 100644 --- a/src/packager.ts +++ b/src/packager.ts @@ -55,7 +55,7 @@ export class Packager implements BuildInfo { const platforms = this.options.platform! this.devMetadata = deepAssign(await readPackageJson(devPackageFile), this.options.devMetadata) - this.appDir = await computeDefaultAppDirectory(this.projectDir, use(this.devMetadata.directories, it => it!.app) || this.options.appDir) + this.appDir = await computeDefaultAppDirectory(this.projectDir, use(this.devMetadata.directories, it => it!.app)) this.isTwoPackageJsonProjectLayoutUsed = this.appDir !== this.projectDir @@ -162,7 +162,7 @@ export class Packager implements BuildInfo { if (author == null) { reportError("author") } - else if (this.options.dist && author.email == null && platforms.includes(Platform.LINUX)) { + else if (author.email == null && platforms.includes(Platform.LINUX)) { throw new Error(util.format(errorMessages.authorEmailIsMissed, appPackageFile)) } diff --git a/src/platformPackager.ts b/src/platformPackager.ts index 58c7b4ffe8e..62a858604a5 100644 --- a/src/platformPackager.ts +++ b/src/platformPackager.ts @@ -5,7 +5,7 @@ import { Promise as BluebirdPromise } from "bluebird" import * as path from "path" import { pack, ElectronPackagerOptions } from "electron-packager-tf" import globby = require("globby") -import { copy, unlink } from "fs-extra-p" +import { readdir, copy, unlink } from "fs-extra-p" import { statOrNull, use, spawn, debug7zArgs, debug } from "./util" import { Packager } from "./packager" import deepAssign = require("deep-assign") @@ -27,18 +27,19 @@ const extToCompressionDescriptor: { [key: string]: CompressionDescriptor; } = { "tar.bz2": new CompressionDescriptor("--bzip2", "BZIP2", "-1"), } -export interface PackagerOptions { - arch?: string | null +export const commonTargets = ["dir", "zip", "7z", "tar.xz", "tar.lz", "tar.gz", "tar.bz2"] - dist?: boolean | null - githubToken?: string | null +// class Target { +// constructor(public platform: Platform, arch?: "ia32" | "x64") +// } +// +export const DIR_TARGET = "dir" - sign?: string | null +export interface PackagerOptions { + target?: Array | null platform?: Array | null - - // deprecated - appDir?: string | null + arch?: string | null projectDir?: string | null @@ -48,7 +49,7 @@ export interface PackagerOptions { cscInstallerLink?: string | null cscInstallerKeyPassword?: string | null - platformPackagerFactory?: ((packager: Packager, platform: Platform, cleanupTasks: Array<() => Promise>) => PlatformPackager) | n + platformPackagerFactory?: ((packager: Packager, platform: Platform, cleanupTasks: Array<() => Promise>) => PlatformPackager) | null /** * The same as [development package.json](https://github.com/electron-userland/electron-builder/wiki/Options#development-packagejson). @@ -87,6 +88,8 @@ export abstract class PlatformPackager readonly targets: Array + readonly resourceList: Promise> + public abstract get platform(): Platform constructor(protected info: BuildInfo) { @@ -99,16 +102,33 @@ export abstract class PlatformPackager this.customBuildOptions = (info.devMetadata.build)[this.platform.buildConfigurationKey] || Object.create(null) this.appName = getProductName(this.metadata, this.devMetadata) - const targets = normalizeTargets(this.customBuildOptions.target) + let targets = normalizeTargets(this.customBuildOptions.target) + const cliTargets = normalizeTargets(this.options.target) + if (cliTargets != null) { + targets = cliTargets + } + if (targets != null) { - const supportedTargets = this.supportedTargets.concat("default", "zip", "7z", "tar.xz", "tar.lz", "tar.gz", "tar.bz2") + const supportedTargets = this.supportedTargets.concat(commonTargets) for (let target of targets) { - if (!supportedTargets.includes(target)) { - throw new Error("Unknown target: " + target) + if (target !== "default" && !supportedTargets.includes(target)) { + throw new Error(`Unknown target: ${target}`) } } } this.targets = targets == null ? ["default"] : targets + + this.resourceList = readdir(this.buildResourcesDir) + .catch(e => { + if (e.code !== "ENOENT") { + throw e + } + return [] + }) + } + + protected hasOnlyDirTarget(): boolean { + return this.targets.length === 1 && this.targets[0] === "dir" } protected get relativeBuildResourcesDirname() { diff --git a/src/winPackager.ts b/src/winPackager.ts index 9011b95b6dc..217011689e9 100644 --- a/src/winPackager.ts +++ b/src/winPackager.ts @@ -3,7 +3,7 @@ import { Promise as BluebirdPromise } from "bluebird" import { PlatformPackager, BuildInfo, smarten, archSuffix } from "./platformPackager" import { Platform, WinBuildOptions } from "./metadata" import * as path from "path" -import { log, statOrNull, warn } from "./util" +import { log, warn } from "./util" import { deleteFile, emptyDir, open, close, read } from "fs-extra-p" import { sign } from "signcode-tf" import { ElectronPackagerOptions } from "electron-packager-tf" @@ -33,12 +33,6 @@ export class WinPackager extends PlatformPackager { } this.iconPath = this.getValidIconPath() - - if (this.options.dist && this.customBuildOptions.loadingGif == null) { - const installSpinnerPath = path.join(this.buildResourcesDir, "install-spinner.gif") - this.loadingGifStat = statOrNull(installSpinnerPath) - .then(it => it != null && !it.isDirectory() ? installSpinnerPath : null) - } } get platform() { @@ -66,21 +60,19 @@ export class WinPackager extends PlatformPackager { const appOutDir = this.computeAppOutDir(outDir, arch) const packOptions = this.computePackOptions(outDir, appOutDir, arch) - if (!this.options.dist) { + if (!this.targets.includes("default")) { await this.doPack(packOptions, outDir, appOutDir, arch, this.customBuildOptions) return } - const installerOut = this.options.dist ? computeDistOut(outDir, arch) : null + const installerOut = computeDistOut(outDir, arch) await BluebirdPromise.all([ this.packApp(packOptions, appOutDir), - installerOut == null ? BluebirdPromise.resolve() : emptyDir(installerOut) + emptyDir(installerOut) ]) await this.copyExtraResources(appOutDir, arch, this.customBuildOptions) - if (this.options.dist) { - postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, installerOut!, arch, packOptions)) - } + postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, installerOut!, arch, packOptions)) } protected computeAppOutDir(outDir: string, arch: string): string { @@ -160,8 +152,11 @@ export class WinPackager extends PlatformPackager { rcedit: rceditOptions, }, this.customBuildOptions) - if (this.loadingGifStat != null) { - options.loadingGif = await this.loadingGifStat + if (!("loadingGif" in options)) { + const resourceList = await this.resourceList + if (resourceList.includes("install-spinner.gif")) { + options.loadingGif = path.join(this.buildResourcesDir, "install-spinner.gif") + } } return options diff --git a/test/src/BuildTest.ts b/test/src/BuildTest.ts index 0619f8e8f98..781b8f440d7 100755 --- a/test/src/BuildTest.ts +++ b/test/src/BuildTest.ts @@ -5,7 +5,7 @@ import { move, outputFile, outputJson } from "fs-extra-p" import { Promise as BluebirdPromise } from "bluebird" import * as path from "path" import { assertThat } from "./helpers/fileAssert" -import { Platform, PackagerOptions } from "out" +import { Platform, PackagerOptions, DIR_TARGET } from "out" import pathSorter = require("path-sort") //noinspection JSUnusedLocalSymbols @@ -105,7 +105,7 @@ const electronVersion = "0.37.8" test("electron version from electron-prebuilt dependency", () => assertPack("test-app-one", { platform: [Platform.LINUX], - dist: false, + target: ["dir"], }, { tempDirCreated: projectDir => BluebirdPromise.all([ outputJson(path.join(projectDir, "node_modules", "electron-prebuilt", "package.json"), { @@ -119,7 +119,7 @@ test("electron version from electron-prebuilt dependency", () => assertPack("tes test("electron version from build", () => assertPack("test-app-one", { platform: [Platform.LINUX], - dist: false, + target: [DIR_TARGET], }, { tempDirCreated: projectDir => modifyPackageJson(projectDir, data => { data.devDependencies = {} @@ -137,7 +137,7 @@ test("afterPack", t => { return assertPack("test-app-one", { // linux pack is very fast, so, we use it :) platform: possiblePlatforms, - dist: false, + target: [DIR_TARGET], devMetadata: { build: { afterPack: () => { @@ -162,7 +162,7 @@ test("copy extra resource", async () => { await assertPack("test-app", { platform: [platform], // to check NuGet package - dist: platform === Platform.WINDOWS, + target: platform === Platform.WINDOWS ? null : [DIR_TARGET], }, { tempDirCreated: (projectDir) => { return BluebirdPromise.all([ @@ -220,20 +220,20 @@ test("copy extra resource", async () => { test("invalid platform", t => t.throws(assertPack("test-app-one", { platform: [null], - dist: false + target: [DIR_TARGET] }), "Unknown platform: null")) function allPlatforms(dist: boolean = true): PackagerOptions { return { platform: getPossiblePlatforms(), - dist: dist, + target: dist ? null : [DIR_TARGET], } } function currentPlatform(dist: boolean = true): PackagerOptions { return { platform: [Platform.fromString(process.platform)], - dist: dist, + target: dist ? null : [DIR_TARGET], } } diff --git a/test/src/helpers/packTester.ts b/test/src/helpers/packTester.ts index 43424dce2fc..4a5c63a39f8 100755 --- a/test/src/helpers/packTester.ts +++ b/test/src/helpers/packTester.ts @@ -62,7 +62,6 @@ export async function assertPack(fixtureName: string, packagerOptions: PackagerO await packAndCheck(projectDir, Object.assign({ projectDir: projectDir, - dist: true, }, packagerOptions), checkOptions) if (checkOptions != null && checkOptions.packed != null) { @@ -97,7 +96,7 @@ async function packAndCheck(projectDir: string, packagerOptions: PackagerOptions await packager.build() - if (!packagerOptions.dist || packagerOptions.platformPackagerFactory != null) { + if ((packagerOptions.target != null && packagerOptions.target.length === 1 && packagerOptions.target[0] === "dir") || packagerOptions.platformPackagerFactory != null) { return } diff --git a/test/tsconfig.json b/test/tsconfig.json index e332f4df41b..58adb9a2c39 100755 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -29,7 +29,6 @@ "files": [ "../typings/appdmg.d.ts", "../typings/asar.d.ts", - "../typings/command-line-args.d.ts", "../typings/compareVersions.d.ts", "../typings/deep-assign.d.ts", "../typings/electron-packager.d.ts", @@ -46,6 +45,7 @@ "../typings/progress-stream.d.ts", "../typings/read-package-json.d.ts", "../typings/signcode.d.ts", + "../typings/yargs.d.ts", "typings/ava.d.ts", "typings/decompress-zip.d.ts", "typings/json-parse-helpfulerror.d.ts", diff --git a/tsconfig.json b/tsconfig.json index e9723562e68..f19d3e04fa9 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -34,7 +34,6 @@ "files": [ "typings/appdmg.d.ts", "typings/asar.d.ts", - "typings/command-line-args.d.ts", "typings/compareVersions.d.ts", "typings/deep-assign.d.ts", "typings/electron-packager.d.ts", @@ -51,6 +50,7 @@ "typings/progress-stream.d.ts", "typings/read-package-json.d.ts", "typings/signcode.d.ts", + "typings/yargs.d.ts", "node_modules/fs-extra-p/index.d.ts", "node_modules/7zip-bin/index.d.ts", "node_modules/fs-extra-p/bluebird.d.ts", diff --git a/typings/command-line-args.d.ts b/typings/command-line-args.d.ts deleted file mode 100644 index 40829248b38..00000000000 --- a/typings/command-line-args.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -declare module "command-line-args" { - interface Options { - parse(): any - - getUsage(options?: UsageOptions): any - } - - interface UsageOptions { - hide?: Array - - title?: string - footer?: string - } - - function describe(options: Array): Options - - export = describe -} \ No newline at end of file diff --git a/typings/yargs.d.ts b/typings/yargs.d.ts new file mode 100644 index 00000000000..9f13b80edcf --- /dev/null +++ b/typings/yargs.d.ts @@ -0,0 +1,100 @@ +// Generated by typings +// Source: https://raw.githubusercontent.com/typed-typings/npm-yargs/1318e35095ddc705f62d180b6517fff2f6664301/index.d.ts +declare module 'yargs' { + interface Argv { + _: string[]; + '$0': string; + [key: string]: any; + } + + interface Yargs { + argv: Argv; + (args: string[]): T & Argv; + parse (args: string[]): T & Argv; + alias (key: string, alias: string): Yargs; + alias (aliases: { [key: string]: string | string[] }): Yargs; + array (key: string): Yargs; + boolean (key: string): Yargs; + check (fn: (argv: Argv, aliases: { [key: string]: string[] }) => any): Yargs; + choices (key: string, choices: (string | number)[]): Yargs; + command (command: string, description: string, fn?: (yargs: Yargs, argv: Argv) => void): Yargs; + completion (cmd: string, fn?: SyncCompletionFunction | AsyncCompletionFunction): Yargs; + completion (cmd: string, description?: string, fn?: SyncCompletionFunction | AsyncCompletionFunction): Yargs; + config (key: string, description?: string): Yargs; + count (key: string): Yargs; + default (key: string, value: any, description?: string): Yargs; + default (defaults: { [key: string]: any }): Yargs; + demand (key: string | string[], msg?: string): Yargs; + demand (key: string | string[], required?: boolean): Yargs; + demand (count: number, msg?: string): Yargs; + demand (count: number, max?: number, msg?: string): Yargs; + require (key: string | string[], msg?: string): Yargs; + require (key: string | string[], required?: boolean): Yargs; + require (count: number, msg?: string): Yargs; + require (count: number, max?: number, msg?: string): Yargs; + required (key: string | string[], msg?: string): Yargs; + required (key: string | string[], required?: boolean): Yargs; + required (count: number, msg?: string): Yargs; + required (count: number, max?: number, msg?: string): Yargs; + describe (key: string, description: string): Yargs; + detectLocale (enable: boolean): Yargs; + env (prefix?: string | boolean): Yargs; + epilog (str: string): Yargs; + epilogue (str: string): Yargs; + example (cmd: string, description: string): Yargs; + exitProcess (enable: boolean): Yargs; + fail (fn: (message: string) => any): Yargs; + group (keys: string | string[], groupName: string): Yargs; + help (option?: string, description?: string): Yargs; + implies (x: string, y: string): Yargs; + locale (): string; + locale (locale: string): Yargs; + nargs (key: string, count: number): Yargs; + option (key: string, options: Options): Yargs; + options (key: string, options: Options): Yargs; + option (options: { [key: string]: Options }): Yargs; + options (options: { [key: string]: Options }): Yargs; + requiresArg (key: string): Yargs; + reset (): Yargs; + showCompletionScript (): string; + showHelp (consoleLevel?: string): Yargs; + showHelpOnFail (enable: boolean, message?: string): Yargs; + strict (): Yargs; + string (key: string): Yargs; + updateLocale (obj: { [key: string]: string }): Yargs; + updateStrings (obj: { [key: string]: string }): Yargs; + usage (message: string, opts?: Options): Yargs; + version (version?: string | (() => string), option?: string, description?: string): Yargs; + wrap (columns: number | null): Yargs; + + terminalWidth(): number + } + + interface Options { + alias?: string | string[]; + array?: boolean; + boolean?: boolean; + choices?: (string | number)[]; + config?: boolean; + count?: boolean; + default?: any; + defaultDescription?: string; + demand?: boolean | string; + require?: boolean | string; + required?: boolean | string; + desc?: string; + describe?: string; + description?: string; + group?: string; + nargs?: number; + requiresArg?: boolean; + string?: boolean; + type?: string; + } + + type SyncCompletionFunction = (current: string, argv: any) => string[]; + type AsyncCompletionFunction = (current: string, argv: any, done: (completion: string[]) => void) => void; + + const yargs: Yargs; + export = yargs; +} \ No newline at end of file