diff --git a/.travis.yml b/.travis.yml
index b67443c5f67..06a77544fe6 100755
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,4 @@
-osx_image: xcode7
+osx_image: xcode7.3
matrix:
include:
@@ -13,7 +13,6 @@ language: c
cache:
directories:
- node_modules
- - test/testApp/node_modules
- $HOME/.electron
- $HOME/.cache/fpm
@@ -23,6 +22,7 @@ before_install:
install:
- nvm install $NODE_VERSION
+- nvm use --delete-prefix $NODE_VERSION
- if [[ "$TRAVIS_OS_NAME" == "osx" && "$NODE_VERSION" == "4" ]]; then npm install npm -g ; fi
- npm install
- npm prune
diff --git a/docs/Options.md b/docs/Options.md
index 2d13a61bf04..c79669d28e4 100644
--- a/docs/Options.md
+++ b/docs/Options.md
@@ -54,15 +54,15 @@ Here documented only `electron-builder` specific options:
| app-category-type | *OS X-only.* The application category type, as shown in the Finder via *View -> Arrange by Application Category* when viewing the Applications directory.
For example, app-category-type=public.app-category.developer-tools
will set the application category to *Developer Tools*.
Valid values are listed in [Apple’s documentation](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/TP40009250-SW8).
| asar | Whether to package the application’s source code into an archive, using [Electron’s archive format](https://github.com/electron/asar). Defaults to true
. Reasons why you may want to disable this feature are described in [an application packaging tutorial in Electron’s documentation](http://electron.atom.io/docs/latest/tutorial/application-packaging/#limitations-on-node-api/).
Or you can pass object of any asar options.
| productName | See [AppMetadata.productName](#AppMetadata-productName).
-| extraResources | A [glob expression](https://www.npmjs.com/package/glob#glob-primer), when specified, copy the file or directory with matching names directly into the app’s resources directory (Contents/Resources
for OS X, resources
for Linux/Windows).
You can use ${os}
(expanded to osx, linux or win according to current platform) and ${arch}
in the pattern.
If directory matched, all contents are copied. So, you can just specify foo
to copy <project_dir>/foo
directory.
May be specified in the platform options (i.e. in the build.osx
).
-| extraFiles | The same as [extraResources](#BuildMetadata-extraResources) but copy into the app's content directory (`Contents` for OS X, `` for Linux/Windows).
+| files | A [glob patterns](https://www.npmjs.com/package/glob#glob-primer) relative to the [app directory](#MetadataDirectories-app), which specifies which files to include when copying files to create the package. Defaults to \*\*\/\*
(i.e. [hidden files are ignored by default](https://www.npmjs.com/package/glob#dots)).
Development dependencies are never copied in any case. You don’t need to ignore it explicitly.
[Multiple patterns](#multiple-glob-patterns) are supported. You can use ${os}
(expanded to osx, linux or win according to current platform) and ${arch}
in the pattern. If directory matched, all contents are copied. So, you can just specify foo
to copy foo
directory.
Remember that default pattern \*\*\/\*
is not added to your custom, so, you have to add it explicitly — e.g. ["\*\*\/\*", "!ignoreMe${/\*}"]
.
May be specified in the platform options (e.g. in the build.osx
).
+| extraResources | A [glob patterns](https://www.npmjs.com/package/glob#glob-primer) relative to the project directory, when specified, copy the file or directory with matching names directly into the app’s resources directory (Contents/Resources
for OS X, resources
for Linux/Windows).
Glob rules the same as for [files](#BuildMetadata-files).
+| extraFiles | The same as [extraResources](#BuildMetadata-extraResources) but copy into the app's content directory (`Contents` for OS X, root directory for Linux/Windows).
| osx | See [.build.osx](#OsXBuildOptions).
| mas | See [.build.mas](#MasBuildOptions).
| win | See [.build.win](#LinuxBuildOptions).
| linux | See [.build.linux](#LinuxBuildOptions).
| compression | The compression level, one of `store`, `normal`, `maximum` (default: `normal`). If you want to rapidly test build, `store` can reduce build time significantly.
| afterPack | *programmatic API only* The function to be run after pack (but before pack into distributable format and sign). Promise must be returned.
-| npmRebuild | Whether to rebuild native dependencies (`npm rebuild`) before starting to package the app. Defaults to `true`.
### `.build.osx`
@@ -107,7 +107,7 @@ MAS (Mac Application Store) specific options (in addition to `build.osx`).
| synopsis | *deb-only.* The [short description](https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Description).
| maintainer | The maintainer. Defaults to [author](#AppMetadata-author).
| vendor | The vendor. Defaults to [author](#AppMetadata-author).
-| compression | *deb-only.* The compression type, one of `gz`, `bzip2`, `xz` (default: `xz`).
+| compression | *deb-only.* The compression type, one of `gz`, `bzip2`, `xz`. Defaults to `xz`.
| depends | Package dependencies. Defaults to `["libappindicator1", "libnotify-bin"]`.
| target | Target package type: list of default
, deb
, rpm
, freebsd
, pacman
, p5p
, apk
, 7z
, zip
, tar.xz
, tar.lz
, tar.gz
, tar.bz2
. Defaults to default
(deb
).
Only deb
is tested. Feel free to file issues for rpm
and other package formats.
@@ -115,8 +115,28 @@ MAS (Mac Application Store) specific options (in addition to `build.osx`).
## `.directories`
| Name | Description
| --- | ---
-| buildResources | The path to build resources, default `build`.
-| output | The output directory, default `dist`.
-| app | The application directory (containing the application package.json), default `app`, `www` or working directory.
+| buildResources | The path to build resources, defaults to `build`.
+| output | The output directory, defaults to `dist`.
+| app | The application directory (containing the application package.json), defaults to `app`, `www` or working directory.
+
+
+# Multiple Glob Patterns
+ ```js
+ [
+ // match all files
+ "**/*",
+
+ // except for js files in the foo/ directory
+ "!foo/*.js",
+
+ // unless it's foo/bar.js
+ "foo/bar.js",
+ ]
+ ```
+
+## Excluding directories
+
+Remember that `!doNotCopyMe/**/*` would match the files *in* the `doNotCopyMe` directory, but not the directory itself, so the [empty directory](https://github.com/gulpjs/gulp/issues/165#issuecomment-32613179) would be created.
+Solution — use macro `${/*}`, e.g. `!doNotCopyMe${/*}`.
\ No newline at end of file
diff --git a/package.json b/package.json
index a9a6aaf37ff..7c458049527 100644
--- a/package.json
+++ b/package.json
@@ -61,18 +61,19 @@
"asar": "^0.11.0",
"bluebird": "^3.4.0",
"chalk": "^1.1.3",
- "compare-versions": "^2.0.1",
+ "compare-versions": "^2.0.2",
"debug": "^2.2.0",
"deep-assign": "^2.0.0",
"electron-osx-sign-tf": "0.6.0",
- "electron-packager-tf": "~7.3.0",
+ "electron-packager-tf": "~7.3.2",
"electron-winstaller-fixed": "~2.9.6",
- "fs-extra-p": "^1.0.1",
+ "fs-extra-p": "^1.0.2",
"glob": "^7.0.3",
"hosted-git-info": "^2.1.5",
"image-size": "^0.5.0",
"lodash.template": "^4.2.5",
"mime": "^1.3.4",
+ "minimatch": "^3.0.0",
"progress": "^1.1.8",
"progress-stream": "^1.2.0",
"read-package-json": "^2.0.4",
@@ -106,10 +107,10 @@
"pre-git": "^3.8.4",
"semantic-release": "^6.3.0",
"should": "^9.0.0",
- "ts-babel": "^0.8.6",
+ "ts-babel": "^1.0.2",
"tsconfig-glob": "^0.4.3",
"tslint": "3.10.0-dev.2",
- "typescript": "1.9.0-dev.20160520-1.0",
+ "typescript": "1.9.0-dev.20160607-1.0",
"whitespace": "^2.0.0"
},
"babel": {
diff --git a/src/globby.ts b/src/globby.ts
deleted file mode 100644
index aa0025796b0..00000000000
--- a/src/globby.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { Promise as BluebirdPromise } from "bluebird"
-import { Glob, Options } from "glob"
-
-//noinspection JSUnusedLocalSymbols
-const __awaiter = require("./awaiter")
-
-function isNegative(pattern: string): boolean {
- return pattern[0] === "!"
-}
-
-function generateGlobTasks(patterns: Array, opts: Options): Array {
- opts = Object.assign({ignore: []}, opts)
-
- const globTasks: Array = []
- patterns.forEach(function (pattern, i) {
- if (isNegative(pattern)) {
- return
- }
-
- const ignore = patterns.slice(i).filter(isNegative).map(it => it.slice(1))
- globTasks.push({
- pattern: pattern,
- opts: Object.assign({}, opts, {
- ignore: (>opts.ignore).concat(ignore)
- })
- })
- })
- return globTasks
-}
-
-export function globby(patterns: Array, opts: Options): Promise> {
- let firstGlob: Glob | null = null
- return BluebirdPromise
- .map(generateGlobTasks(patterns, opts), task => new BluebirdPromise((resolve, reject) => {
- let glob = new Glob(task.pattern, task.opts, (error, matches) => {
- if (error == null) {
- resolve(matches)
- }
- else {
- reject(error)
- }
- })
-
- if (firstGlob == null) {
- firstGlob = glob
- }
- else {
- glob.statCache = firstGlob.statCache
- glob.symlinks = firstGlob.symlinks
- glob.realpathCache = firstGlob.realpathCache
- glob.cache = firstGlob.cache
- }
- }))
- .then(it => new Set([].concat(...it)))
-}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index 0ff481389b9..3779277901f 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,4 +2,4 @@ export { Packager } from "./packager"
export { PackagerOptions, ArtifactCreated, DIR_TARGET, BuildInfo } from "./platformPackager"
export { BuildOptions, build, createPublisher, CliOptions, createTargets } from "./builder"
export { PublishOptions, Publisher } from "./gitHubPublisher"
-export { AppMetadata, DevMetadata, Platform, Arch, archFromString, getProductName, BuildMetadata, OsXBuildOptions, WinBuildOptions, LinuxBuildOptions } from "./metadata"
\ No newline at end of file
+export { AppMetadata, DevMetadata, Platform, Arch, archFromString, getProductName, BuildMetadata, OsXBuildOptions, WinBuildOptions, LinuxBuildOptions, CompressionLevel } from "./metadata"
\ No newline at end of file
diff --git a/src/linuxPackager.ts b/src/linuxPackager.ts
index 9db79b78140..8fcf596bb5f 100755
--- a/src/linuxPackager.ts
+++ b/src/linuxPackager.ts
@@ -48,7 +48,7 @@ export class LinuxPackager extends PlatformPackager {
}
}
- protected get supportedTargets(): Array {
+ get supportedTargets(): Array {
return ["deb", "rpm", "sh", "freebsd", "pacman", "apk", "p5p"]
}
@@ -66,7 +66,7 @@ export class LinuxPackager extends PlatformPackager {
promises.push(this.computeDesktop(tempDir))
- return [].concat(...await BluebirdPromise.all(promises))
+ return Array.prototype.concat.apply([], await BluebirdPromise.all(promises))
}
async pack(outDir: string, arch: Arch, targets: Array, postAsyncTasks: Array>): Promise {
diff --git a/src/metadata.ts b/src/metadata.ts
index 6d7afb12815..06c7fa912a3 100755
--- a/src/metadata.ts
+++ b/src/metadata.ts
@@ -74,6 +74,8 @@ export interface AuthorMetadata {
readonly email: string
}
+export type CompressionLevel = "store" | "normal" | "maximum"
+
/*
## `.build`
*/
@@ -108,20 +110,30 @@ export interface BuildMetadata {
readonly productName?: string | null
/**
- A [glob expression](https://www.npmjs.com/package/glob#glob-primer), when specified, copy the file or directory with matching names directly into the app's resources directory (`Contents/Resources` for OS X, `resources` for Linux/Windows).
+ A [glob patterns](https://www.npmjs.com/package/glob#glob-primer) relative to the [app directory](#MetadataDirectories-app), which specifies which files to include when copying files to create the package. Defaults to `\*\*\/\*` (i.e. [hidden files are ignored by default](https://www.npmjs.com/package/glob#dots)).
+
+ Development dependencies are never copied in any case. You don't need to ignore it explicitly.
- You can use `${os}` (expanded to osx, linux or win according to current platform) and `${arch}` in the pattern.
+ [Multiple patterns](#multiple-glob-patterns) are supported. You can use `${os}` (expanded to osx, linux or win according to current platform) and `${arch}` in the pattern.
+ If directory matched, all contents are copied. So, you can just specify `foo` to copy `foo` directory.
- If directory matched, all contents are copied. So, you can just specify `foo` to copy `/foo` directory.
+ Remember that default pattern `\*\*\/\*` is not added to your custom, so, you have to add it explicitly — e.g. `["\*\*\/\*", "!ignoreMe${/\*}"]`.
- May be specified in the platform options (i.e. in the `build.osx`).
+ May be specified in the platform options (e.g. in the `build.osx`).
*/
- readonly extraResources?: Array | null
+ readonly files?: Array | string | null
/**
- The same as [extraResources](#BuildMetadata-extraResources) but copy into the app's content directory (`Contents` for OS X, `` for Linux/Windows).
+ A [glob patterns](https://www.npmjs.com/package/glob#glob-primer) relative to the project directory, when specified, copy the file or directory with matching names directly into the app's resources directory (`Contents/Resources` for OS X, `resources` for Linux/Windows).
+
+ Glob rules the same as for [files](#BuildMetadata-files).
*/
- readonly extraFiles?: Array | null
+ readonly extraResources?: Array | string | null
+
+ /**
+ The same as [extraResources](#BuildMetadata-extraResources) but copy into the app's content directory (`Contents` for OS X, root directory for Linux/Windows).
+ */
+ readonly extraFiles?: Array | string | null
/*
See [.build.osx](#OsXBuildOptions).
@@ -146,7 +158,7 @@ export interface BuildMetadata {
/*
The compression level, one of `store`, `normal`, `maximum` (default: `normal`). If you want to rapidly test build, `store` can reduce build time significantly.
*/
- readonly compression?: "store" | "normal" | "maximum" | null
+ readonly compression?: CompressionLevel | null
readonly "build-version"?: string | null
@@ -155,8 +167,16 @@ export interface BuildMetadata {
*/
readonly afterPack?: (context: AfterPackContext) => Promise | null
+ // /*
+ // Whether to [prune](https://docs.npmjs.com/cli/prune) dependencies (`npm prune --production`) before starting to package the app.
+ // Defaults to `false`.
+ // */
+ // readonly npmPrune?: boolean
+ // deprecated
+ // readonly prune?: boolean
+
/*
- Whether to rebuild native dependencies (`npm rebuild`) before starting to package the app. Defaults to `true`.
+ Whether to [rebuild](https://docs.npmjs.com/cli/rebuild) native dependencies (`npm rebuild`) before starting to package the app. Defaults to `true`.
*/
readonly npmRebuild?: boolean
}
@@ -307,7 +327,7 @@ export interface LinuxBuildOptions extends PlatformSpecificBuildOptions {
afterRemove?: string | null
/*
- *deb-only.* The compression type, one of `gz`, `bzip2`, `xz` (default: `xz`).
+ *deb-only.* The compression type, one of `gz`, `bzip2`, `xz`. Defaults to `xz`.
*/
readonly compression?: string | null
@@ -329,22 +349,23 @@ export interface LinuxBuildOptions extends PlatformSpecificBuildOptions {
*/
export interface MetadataDirectories {
/*
- The path to build resources, default `build`.
+ The path to build resources, defaults to `build`.
*/
readonly buildResources?: string | null
/*
- The output directory, default `dist`.
+ The output directory, defaults to `dist`.
*/
readonly output?: string | null
/*
- The application directory (containing the application package.json), default `app`, `www` or working directory.
+ The application directory (containing the application package.json), defaults to `app`, `www` or working directory.
*/
readonly app?: string | null
}
export interface PlatformSpecificBuildOptions {
+ readonly files?: Array | null
readonly extraFiles?: Array | null
readonly extraResources?: Array | null
@@ -354,9 +375,9 @@ export interface PlatformSpecificBuildOptions {
}
export class Platform {
- public static OSX = new Platform("osx", "osx", "darwin")
- public static LINUX = new Platform("linux", "linux", "linux")
- public static WINDOWS = new Platform("windows", "win", "win32")
+ static OSX = new Platform("osx", "osx", "darwin")
+ static LINUX = new Platform("linux", "linux", "linux")
+ static WINDOWS = new Platform("windows", "win", "win32")
constructor(public name: string, public buildConfigurationKey: string, public nodeName: string) {
}
@@ -369,19 +390,19 @@ export class Platform {
return this.name
}
- public createTarget(type?: string | null, ...archs: Array): Map>> {
+ createTarget(type?: string | Array | null, ...archs: Array): Map>> {
const archToType = new Map()
for (let arch of (archs == null || archs.length === 0 ? [archFromString(process.arch)] : archs)) {
- archToType.set(arch, type == null ? [] : [type])
+ archToType.set(arch, type == null ? [] : (Array.isArray(type) ? type : [type]))
}
return new Map([[this, archToType]])
}
- public static current(): Platform {
+ static current(): Platform {
return Platform.fromString(process.platform)
}
- public static fromString(name: string): Platform {
+ static fromString(name: string): Platform {
switch (name) {
case Platform.OSX.nodeName:
case Platform.OSX.name:
diff --git a/src/osxPackager.ts b/src/osxPackager.ts
index a60531ba9bc..05717c1661b 100644
--- a/src/osxPackager.ts
+++ b/src/osxPackager.ts
@@ -30,7 +30,7 @@ export default class OsXPackager extends PlatformPackager {
return Platform.OSX
}
- protected get supportedTargets(): Array {
+ get supportedTargets(): Array {
return ["dmg", "mas"]
}
@@ -42,7 +42,7 @@ export default class OsXPackager extends PlatformPackager {
nonMasPromise = this.doPack(packOptions, outDir, appOutDir, arch, this.customBuildOptions)
.then(() => this.sign(appOutDir, null))
.then(() => {
- postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, targets))
+ this.packageInDistributableFormat(appOutDir, targets, postAsyncTasks)
})
}
@@ -215,8 +215,7 @@ export default class OsXPackager extends PlatformPackager {
return specification
}
- protected packageInDistributableFormat(outDir: string, appOutDir: string, targets: Array): Promise {
- const promises: Array> = []
+ protected packageInDistributableFormat(appOutDir: string, targets: Array, promises: Array>): void {
for (let target of targets) {
if (target === "dmg" || target === "default") {
promises.push(this.createDmg(appOutDir))
@@ -233,7 +232,6 @@ export default class OsXPackager extends PlatformPackager {
.then(() => this.dispatchArtifactCreated(outFile, `${this.metadata.name}-${this.metadata.version}-${classifier}.${format}`)))
}
}
- return BluebirdPromise.all(promises)
}
private async createDmg(appOutDir: string) {
diff --git a/src/packager.ts b/src/packager.ts
index 05b8b5c5d51..32a11814b25 100644
--- a/src/packager.ts
+++ b/src/packager.ts
@@ -8,7 +8,7 @@ import { EventEmitter } from "events"
import { Promise as BluebirdPromise } from "bluebird"
import { InfoRetriever } from "./repositoryInfo"
import { AppMetadata, DevMetadata, Platform, Arch } from "./metadata"
-import { PackagerOptions, PlatformPackager, BuildInfo, ArtifactCreated } from "./platformPackager"
+import { PackagerOptions, PlatformPackager, BuildInfo, ArtifactCreated, computeEffectiveTargets, commonTargets } from "./platformPackager"
import OsXPackager from "./osxPackager"
import { WinPackager } from "./winPackager"
import * as errorMessages from "./errorMessages"
@@ -96,7 +96,15 @@ export class Packager implements BuildInfo {
}
// electron-packager uses productName in the directory name
- await helper.pack(outDir, arch, helper.computeEffectiveTargets(targets), distTasks)}
+ const effectiveTargets = computeEffectiveTargets(targets, helper.customBuildOptions.target)
+ const supportedTargets = helper.supportedTargets.concat(commonTargets)
+ for (let target of effectiveTargets) {
+ if (target !== "default" && !supportedTargets.includes(target)) {
+ throw new Error(`Unknown target: ${target}`)
+ }
+ }
+ await helper.pack(outDir, arch, effectiveTargets, distTasks)
+ }
}
return await BluebirdPromise.all(distTasks)
diff --git a/src/platformPackager.ts b/src/platformPackager.ts
index d391927f25c..262bf124c6c 100644
--- a/src/platformPackager.ts
+++ b/src/platformPackager.ts
@@ -3,31 +3,19 @@ import { AppMetadata, DevMetadata, Platform, PlatformSpecificBuildOptions, getPr
import EventEmitter = NodeJS.EventEmitter
import { Promise as BluebirdPromise } from "bluebird"
import * as path from "path"
-import { pack, ElectronPackagerOptions } from "electron-packager-tf"
-import { globby } from "./globby"
-import { readdir, copy, unlink, lstat, remove } from "fs-extra-p"
-import { statOrNull, use, spawn, debug7zArgs, debug, warn, log } from "./util"
+import { pack, ElectronPackagerOptions, userIgnoreFilter } from "electron-packager-tf"
+import { readdir, copy, unlink, lstat, remove, realpath } from "fs-extra-p"
+import { statOrNull, use, warn, log, exec } from "./util"
import { Packager } from "./packager"
import { listPackage, statFile, AsarFileMetadata, createPackageFromFiles, AsarOptions } from "asar"
-import { path7za } from "7zip-bin"
-import deepAssign = require("deep-assign")
+import { archiveApp } from "./targets/archive"
import { Glob } from "glob"
+import { Minimatch } from "minimatch"
+import deepAssign = require("deep-assign")
//noinspection JSUnusedLocalSymbols
const __awaiter = require("./awaiter")
-class CompressionDescriptor {
- constructor(public flag: string, public env: string, public minLevel: string, public maxLevel: string = "-9") {
- }
-}
-
-const extToCompressionDescriptor: { [key: string]: CompressionDescriptor; } = {
- "tar.xz": new CompressionDescriptor("--xz", "XZ_OPT", "-0", "-9e"),
- "tar.lz": new CompressionDescriptor("--lzip", "LZOP", "-0"),
- "tar.gz": new CompressionDescriptor("--gz", "GZIP", "-1"),
- "tar.bz2": new CompressionDescriptor("--bzip2", "BZIP2", "-1"),
-}
-
export const commonTargets = ["dir", "zip", "7z", "tar.xz", "tar.lz", "tar.gz", "tar.bz2"]
export const DIR_TARGET = "dir"
@@ -73,7 +61,7 @@ export abstract class PlatformPackager
protected readonly options: PackagerOptions
protected readonly projectDir: string
- protected readonly buildResourcesDir: string
+ readonly buildResourcesDir: string
readonly metadata: AppMetadata
readonly devMetadata: DevMetadata
@@ -86,7 +74,7 @@ export abstract class PlatformPackager
public abstract get platform(): Platform
- constructor(protected info: BuildInfo) {
+ constructor(public info: BuildInfo) {
this.options = info.options
this.projectDir = info.projectDir
this.metadata = info.metadata
@@ -116,19 +104,6 @@ export abstract class PlatformPackager
}
}
- public computeEffectiveTargets(rawList: Array): Array {
- let targets = normalizeTargets(rawList.length === 0 ? this.customBuildOptions.target : rawList)
- if (targets != null) {
- const supportedTargets = this.supportedTargets.concat(commonTargets)
- for (let target of targets) {
- if (target !== "default" && !supportedTargets.includes(target)) {
- throw new Error(`Unknown target: ${target}`)
- }
- }
- }
- return targets == null ? ["default"] : targets
- }
-
protected hasOnlyDirTarget(): boolean {
for (let targets of this.options.targets!.get(this.platform)!.values()) {
for (let t of targets) {
@@ -142,17 +117,17 @@ export abstract class PlatformPackager
return targets != null && targets.length === 1 && targets[0] === "dir"
}
- protected get relativeBuildResourcesDirname() {
+ get relativeBuildResourcesDirname() {
return use(this.devMetadata.directories, it => it!.buildResources) || "build"
}
- protected abstract get supportedTargets(): Array
+ abstract get supportedTargets(): Array
protected computeAppOutDir(outDir: string, arch: Arch): string {
return path.join(outDir, `${this.platform.buildConfigurationKey}${arch === Arch.x64 ? "" : `-${Arch[arch]}`}`)
}
- protected dispatchArtifactCreated(file: string, artifactName?: string) {
+ dispatchArtifactCreated(file: string, artifactName?: string) {
this.info.eventEmitter.emit("artifactCreated", {
file: file,
artifactName: artifactName,
@@ -163,17 +138,75 @@ 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, customBuildOptions: DC) {
- const asar = options.asar
- options.asar = false
- await pack(options)
- options.asar = asar
-
const asarOptions = this.computeAsarOptions(customBuildOptions)
- if (asarOptions != null) {
- await this.createAsarArchive(appOutDir, asarOptions)
+ options.initializeApp = async (opts, buildDir, appRelativePath) => {
+ const appPath = path.join(buildDir, appRelativePath)
+ const resourcesPath = path.dirname(appPath)
+
+ let promise: Promise | null = null
+ const deprecatedIgnore = (this.devMetadata.build).ignore
+ if (deprecatedIgnore) {
+ if (typeof deprecatedIgnore === "function") {
+ log(`"ignore is specified as function, may be new "files" option will be suit your needs? Please see https://github.com/electron-userland/electron-builder/wiki/Options#BuildMetadata-files`)
+ }
+ else {
+ warn(`"ignore is deprecated, please use "files", see https://github.com/electron-userland/electron-builder/wiki/Options#BuildMetadata-files`)
+ }
+
+ promise = copy(this.info.appDir, appPath, {filter: userIgnoreFilter(opts), dereference: true})
+ }
+ else {
+ const ignoreFiles = new Set([path.relative(this.info.appDir, opts.out!), path.relative(this.info.appDir, this.buildResourcesDir)])
+ if (!this.info.isTwoPackageJsonProjectLayoutUsed) {
+ const result = await BluebirdPromise.all([listDependencies(this.info.appDir, false), listDependencies(this.info.appDir, true)])
+ const productionDepsSet = new Set(result[1])
+
+ // npm returns real path, so, we should use relative path to avoid any mismatch
+ const realAppDirPath = await realpath(this.info.appDir)
+
+ for (let it of result[0]) {
+ if (!productionDepsSet.has(it)) {
+ if (it.startsWith(realAppDirPath)) {
+ it = it.substring(realAppDirPath.length + 1)
+ }
+ else if (it.startsWith(this.info.appDir)) {
+ it = it.substring(this.info.appDir.length + 1)
+ }
+ ignoreFiles.add(it)
+ }
+ }
+ }
+
+ let patterns = this.getFilePatterns("files", customBuildOptions)
+ if (patterns == null || patterns.length === 0) {
+ patterns = ["**/*"]
+ }
+ promise = copyFiltered(this.info.appDir, appPath, this.getParsedPatterns(patterns, arch), true, ignoreFiles)
+ }
+
+ const promises = [promise]
+ if (this.info.electronVersion[0] === "0") {
+ // electron release >= 0.37.4 - the default_app/ folder is a default_app.asar file
+ promises.push(remove(path.join(resourcesPath, "default_app.asar")), remove(path.join(resourcesPath, "default_app")))
+ }
+ else {
+ promises.push(unlink(path.join(resourcesPath, "default_app.asar")))
+ }
+
+ await BluebirdPromise.all(promises)
+
+ if (opts.prune != null) {
+ warn("prune is deprecated — development dependencies are never copied in any case")
+ }
+
+ if (asarOptions != null) {
+ await this.createAsarArchive(appPath, resourcesPath, asarOptions)
+ }
}
+ await pack(options)
- await this.copyExtraFiles(appOutDir, arch, customBuildOptions)
+ await this.doCopyExtraFiles(true, appOutDir, arch, customBuildOptions)
+ await this.doCopyExtraFiles(false, appOutDir, arch, customBuildOptions)
const afterPack = this.devMetadata.build.afterPack
if (afterPack != null) {
@@ -218,14 +251,6 @@ export abstract class PlatformPackager
}
}, this.devMetadata.build)
- if (!this.info.isTwoPackageJsonProjectLayoutUsed && typeof options.ignore !== "function") {
- const defaultIgnores = ["/node_modules/electron-builder($|/)", "^/" + path.relative(this.projectDir, this.buildResourcesDir) + "($|/)"]
- if (options.ignore != null && !Array.isArray(options.ignore)) {
- options.ignore = [options.ignore]
- }
- options.ignore = options.ignore == null ? defaultIgnores : options.ignore.concat(defaultIgnores)
- }
-
delete options.osx
delete options.win
delete options.linux
@@ -234,15 +259,6 @@ export abstract class PlatformPackager
return options
}
- private getExtraResources(isResources: boolean, arch: Arch, customBuildOptions: DC): Promise> {
- let patterns: Array | n = (this.devMetadata.build)[isResources ? "extraResources" : "extraFiles"]
- const platformSpecificPatterns = isResources ? customBuildOptions.extraResources : customBuildOptions.extraFiles
- if (platformSpecificPatterns != null) {
- patterns = patterns == null ? platformSpecificPatterns : patterns.concat(platformSpecificPatterns)
- }
- return patterns == null ? BluebirdPromise.resolve(new Set()) : globby(this.expandPatterns(patterns, arch), {cwd: this.projectDir});
- }
-
private computeAsarOptions(customBuildOptions: DC): AsarOptions | null {
let result = this.devMetadata.build.asar
let platformSpecific = customBuildOptions.asar
@@ -273,16 +289,12 @@ export abstract class PlatformPackager
}
}
- private async createAsarArchive(appOutDir: string, options: AsarOptions): Promise {
- const src = path.join(this.getResourcesDir(appOutDir), "app")
-
+ private async createAsarArchive(src: string, resourcesPath: string, options: AsarOptions): Promise {
+ // dot: true as in the asar by default by we use glob default - do not copy hidden files
let glob: Glob | null = null
const files = (await new BluebirdPromise>((resolve, reject) => {
glob = new Glob("**/*", {
cwd: src,
- // dot: true as in the asar by default
- dot: true,
- ignore: "**/.DS_Store",
}, (error, matches) => {
if (error == null) {
resolve(matches)
@@ -293,43 +305,81 @@ export abstract class PlatformPackager
})
})).map(it => path.join(src, it))
+ const metadata: { [key: string]: AsarFileMetadata; } = {}
+
const stats = await BluebirdPromise.map(files, it => {
- // const stat = glob!.statCache[it]
- // return stat == null ? lstat(it) : stat
- // todo check is it safe to reuse glob stat
- return lstat(it)
+ if (glob!.symlinks[it]) {
+ // asar doesn't use stat for link
+ metadata[it] = {
+ type: "link",
+ }
+ }
+ else if (glob!.cache[it] === "FILE") {
+ const stat = glob!.statCache[it]
+ return stat == null ? lstat(it) : stat
+ }
+ else {
+ // asar doesn't use stat for dir
+ metadata[it] = {
+ type: "directory",
+ }
+ }
+ return null
})
- const metadata: { [key: string]: AsarFileMetadata; } = {}
for (let i = 0, n = files.length; i < n; i++) {
const stat = stats[i]
- metadata[files[i]] = {
- type: stat.isFile() ? "file" : (stat.isDirectory() ? "directory" : "link"),
- stat: stat,
+ if (stat != null) {
+ metadata[files[i]] = {
+ type: "file",
+ stat: stat,
+ }
}
}
- await BluebirdPromise.promisify(createPackageFromFiles)(src, path.join(this.getResourcesDir(appOutDir), "app.asar"), files, metadata, options)
+ await BluebirdPromise.promisify(createPackageFromFiles)(src, path.join(resourcesPath, "app.asar"), files, metadata, options)
await remove(src)
}
- private expandPatterns(list: Array, arch: Arch): Array {
- return list.map(it => it
+ private expandPattern(pattern: string, arch: Arch): string {
+ return pattern
.replace(/\$\{arch}/g, Arch[arch])
- .replace(/\$\{os}/g, this.platform.buildConfigurationKey))
+ .replace(/\$\{os}/g, this.platform.buildConfigurationKey)
+ .replace(/\$\{\/\*}/g, "{,/**/*,/**/.*}")
}
- protected async copyExtraFiles(appOutDir: string, arch: Arch, customBuildOptions: DC): Promise {
- await this.doCopyExtraFiles(true, appOutDir, arch, customBuildOptions)
- await this.doCopyExtraFiles(false, appOutDir, arch, customBuildOptions)
+ private async doCopyExtraFiles(isResources: boolean, appOutDir: string, arch: Arch, customBuildOptions: DC): Promise {
+ const base = isResources ? this.getResourcesDir(appOutDir) : this.platform === Platform.OSX ? path.join(appOutDir, `${this.appName}.app`, "Contents") : appOutDir
+ const patterns = this.getFilePatterns(isResources ? "extraResources" : "extraFiles", customBuildOptions)
+ return patterns == null || patterns.length === 0 ? null : copyFiltered(this.projectDir, base, this.getParsedPatterns(patterns, arch))
}
- private async doCopyExtraFiles(isResources: boolean, appOutDir: string, arch: Arch, customBuildOptions: DC): Promise> {
- const base = isResources ? this.getResourcesDir(appOutDir) : this.platform === Platform.OSX ? path.join(appOutDir, `${this.appName}.app`, "Contents") : appOutDir
- return await BluebirdPromise.map(await this.getExtraResources(isResources, arch, customBuildOptions), it => copy(path.join(this.projectDir, it), path.join(base, it)))
+ private getParsedPatterns(patterns: Array, arch: Arch): Array {
+ const minimatchOptions = {}
+ const parsedPatterns: Array = []
+ for (let i = 0; i < patterns.length; i++) {
+ parsedPatterns[i] = new Minimatch(this.expandPattern(patterns[i], arch), minimatchOptions)
+ }
+ return parsedPatterns
+ }
+
+ private getFilePatterns(name: "files" | "extraFiles" | "extraResources", customBuildOptions: DC): Array | n {
+ let patterns: Array | string | n = (this.devMetadata.build)[name]
+ if (patterns != null && !Array.isArray(patterns)) {
+ patterns = [patterns]
+ }
+
+ let platformSpecificPatterns: Array | string | n = (customBuildOptions)[name]
+ if (platformSpecificPatterns != null) {
+ if (!Array.isArray(platformSpecificPatterns)) {
+ platformSpecificPatterns = [platformSpecificPatterns]
+ }
+ return patterns == null ? platformSpecificPatterns : Array.from(new Set(patterns.concat(platformSpecificPatterns)))
+ }
+ return patterns
}
- protected async computePackageUrl(): Promise {
+ async computePackageUrl(): Promise {
const url = this.metadata.homepage || this.devMetadata.homepage
if (url != null) {
return url
@@ -405,66 +455,7 @@ export abstract class PlatformPackager
}
protected async archiveApp(format: string, appOutDir: string, outFile: string): Promise {
- const compression = this.devMetadata.build.compression
- const storeOnly = compression === "store"
-
- const dirToArchive = this.platform === Platform.OSX ? path.join(appOutDir, `${this.appName}.app`) : appOutDir
- if (format.startsWith("tar.")) {
- // we don't use 7z here - develar: I spent a lot of time making pipe working - but it works on OS X and often hangs on Linux (even if use pipe-io lib)
- // and in any case it is better to use system tools (in the light of docker - it is not problem for user because we provide complete docker image).
- const info = extToCompressionDescriptor[format]
- let tarEnv = process.env
- if (compression != null && compression !== "normal") {
- tarEnv = Object.assign({}, process.env)
- tarEnv[info.env] = storeOnly ? info.minLevel : info.maxLevel
- }
-
- await spawn(process.platform === "darwin" || process.platform === "freebsd" ? "gtar" : "tar", [info.flag, "--transform", `s,^\.,${path.basename(outFile, "." + format)},`, "-cf", outFile, "."], {
- cwd: dirToArchive,
- stdio: ["ignore", debug.enabled ? "inherit" : "ignore", "inherit"],
- env: tarEnv
- })
- return
- }
-
- const args = debug7zArgs("a")
- if (compression === "maximum") {
- if (format === "7z" || format.endsWith(".7z")) {
- args.push("-mx=9", "-mfb=64", "-md=32m", "-ms=on")
- }
- else if (format === "zip") {
- // http://superuser.com/a/742034
- //noinspection SpellCheckingInspection
- args.push("-mfb=258", "-mpass=15")
- }
- else {
- args.push("-mx=9")
- }
- }
- else if (storeOnly) {
- if (format !== "zip") {
- args.push("-mx=1")
- }
- }
-
- // remove file before - 7z doesn't overwrite file, but update
- try {
- await unlink(outFile)
- }
- catch (e) {
- // ignore
- }
-
- if (format === "zip" || storeOnly) {
- args.push("-mm=" + (storeOnly ? "Copy" : "Deflate"))
- }
-
- args.push(outFile, dirToArchive)
-
- await spawn(path7za, args, {
- cwd: path.dirname(dirToArchive),
- stdio: ["ignore", debug.enabled ? "inherit" : "ignore", "inherit"],
- })
+ return archiveApp(this.devMetadata.build.compression, format, outFile, this.platform === Platform.OSX ? path.join(appOutDir, `${this.appName}.app`) : appOutDir)
}
}
@@ -501,3 +492,82 @@ export function smarten(s: string): string {
s = s.replace(/"/g, "\u201d")
return s
}
+
+// https://github.com/joshwnj/minimatch-all/blob/master/index.js
+function minimatchAll(path: string, patterns: Array): boolean {
+ let match = false
+ for (let pattern of patterns) {
+ // If we've got a match, only re-test for exclusions.
+ // if we don't have a match, only re-test for inclusions.
+ if (match !== pattern.negate) {
+ continue
+ }
+
+ // partial match — pattern: foo/bar.txt path: foo — we must allow foo
+ // use it only for non-negate patterns: const m = new Minimatch("!node_modules/@(electron-download|electron-prebuilt)/**/*", {dot: true }); m.match("node_modules", true) will return false, but must be true
+ match = pattern.match(path, !pattern.negate)
+ if (!match && !pattern.negate) {
+ const rawPattern = pattern.pattern
+ // 1 - slash
+ const patternLengthPlusSlash = rawPattern.length + 1
+ if (path.length > patternLengthPlusSlash) {
+ // foo: include all directory content
+ match = path[rawPattern.length] === "/" && path.startsWith(rawPattern)
+ }
+ }
+ }
+ return match
+}
+
+// we use relative path to avoid canonical path issue - e.g. /tmp vs /private/tmp
+function copyFiltered(src: string, destination: string, patterns: Array, dereference: boolean = false, ignoreFiles?: Set): Promise {
+ return copy(src, destination, {
+ dereference: dereference,
+ filter: it => {
+ if (src === it) {
+ return true
+ }
+ let relative = it.substring(src.length + 1)
+
+ // yes, check before path sep normalization
+ if (ignoreFiles != null && ignoreFiles.has(relative)) {
+ return false
+ }
+
+ if (path.sep === "\\") {
+ relative = relative.replace(/\\/g, "/")
+ }
+ return minimatchAll(relative, patterns)
+ }
+ })
+}
+
+export function computeEffectiveTargets(rawList: Array, targetsFromMetadata: Array | n): Array {
+ let targets = normalizeTargets(rawList.length === 0 ? targetsFromMetadata : rawList)
+ return targets == null ? ["default"] : targets
+}
+
+async function listDependencies(appDir: string, production: boolean): Promise> {
+ let npmExecPath = process.env.npm_execpath || process.env.NPM_CLI_JS
+ const npmExecArgs = ["ls", production ? "--production" : "--dev", "--parseable"]
+ if (npmExecPath == null) {
+ npmExecPath = process.platform === "win32" ? "npm.cmd" : "npm"
+ }
+ else {
+ npmExecArgs.unshift(npmExecPath)
+ npmExecPath = process.env.npm_node_execpath || process.env.NODE_EXE || "node"
+ }
+
+ const result = (await exec(npmExecPath, npmExecArgs, {
+ cwd: appDir,
+ stdio: "inherit",
+ maxBuffer: 1024 * 1024,
+ })).trim().split("\n")
+ if (result.length > 0 && !result[0].includes("/node_modules/")) {
+ // first line is a project dir
+ const lastIndex = result.length - 1
+ result[0] = result[lastIndex]
+ result.length = result.length - 1
+ }
+ return result
+}
\ No newline at end of file
diff --git a/src/targets/archive.ts b/src/targets/archive.ts
new file mode 100644
index 00000000000..e3bec2a4b3b
--- /dev/null
+++ b/src/targets/archive.ts
@@ -0,0 +1,81 @@
+import { spawn, debug, debug7zArgs } from "../util"
+import { CompressionLevel } from "../metadata"
+import * as path from "path"
+import { unlink } from "fs-extra-p"
+import { path7za } from "7zip-bin"
+
+//noinspection JSUnusedLocalSymbols
+const __awaiter = require("../awaiter")
+
+class CompressionDescriptor {
+ constructor(public flag: string, public env: string, public minLevel: string, public maxLevel: string = "-9") {
+ }
+}
+
+const extToCompressionDescriptor: { [key: string]: CompressionDescriptor; } = {
+ "tar.xz": new CompressionDescriptor("--xz", "XZ_OPT", "-0", "-9e"),
+ "tar.lz": new CompressionDescriptor("--lzip", "LZOP", "-0"),
+ "tar.gz": new CompressionDescriptor("--gz", "GZIP", "-1"),
+ "tar.bz2": new CompressionDescriptor("--bzip2", "BZIP2", "-1"),
+}
+
+export async function archiveApp(compression: CompressionLevel | n, format: string, outFile: string, dirToArchive: string): Promise {
+ const storeOnly = compression === "store"
+
+ if (format.startsWith("tar.")) {
+ // we don't use 7z here - develar: I spent a lot of time making pipe working - but it works on OS X and often hangs on Linux (even if use pipe-io lib)
+ // and in any case it is better to use system tools (in the light of docker - it is not problem for user because we provide complete docker image).
+ const info = extToCompressionDescriptor[format]
+ let tarEnv = process.env
+ if (compression != null && compression !== "normal") {
+ tarEnv = Object.assign({}, process.env)
+ tarEnv[info.env] = storeOnly ? info.minLevel : info.maxLevel
+ }
+
+ await spawn(process.platform === "darwin" || process.platform === "freebsd" ? "gtar" : "tar", [info.flag, "--transform", `s,^\.,${path.basename(outFile, "." + format)},`, "-cf", outFile, "."], {
+ cwd: dirToArchive,
+ stdio: ["ignore", debug.enabled ? "inherit" : "ignore", "inherit"],
+ env: tarEnv
+ })
+ return
+ }
+
+ const args = debug7zArgs("a")
+ if (compression === "maximum") {
+ if (format === "7z" || format.endsWith(".7z")) {
+ args.push("-mx=9", "-mfb=64", "-md=32m", "-ms=on")
+ }
+ else if (format === "zip") {
+ // http://superuser.com/a/742034
+ //noinspection SpellCheckingInspection
+ args.push("-mfb=258", "-mpass=15")
+ }
+ else {
+ args.push("-mx=9")
+ }
+ }
+ else if (storeOnly) {
+ if (format !== "zip") {
+ args.push("-mx=1")
+ }
+ }
+
+ // remove file before - 7z doesn't overwrite file, but update
+ try {
+ await unlink(outFile)
+ }
+ catch (e) {
+ // ignore
+ }
+
+ if (format === "zip" || storeOnly) {
+ args.push("-mm=" + (storeOnly ? "Copy" : "Deflate"))
+ }
+
+ args.push(outFile, dirToArchive)
+
+ await spawn(path7za, args, {
+ cwd: path.dirname(dirToArchive),
+ stdio: ["ignore", debug.enabled ? "inherit" : "ignore", "inherit"],
+ })
+}
\ No newline at end of file
diff --git a/src/targets/squirrelWindows.ts b/src/targets/squirrelWindows.ts
new file mode 100644
index 00000000000..70b56714618
--- /dev/null
+++ b/src/targets/squirrelWindows.ts
@@ -0,0 +1,122 @@
+import { WinPackager } from "../winPackager"
+import { getArchSuffix, smarten } from "../platformPackager"
+import { ElectronPackagerOptions } from "electron-packager-tf"
+import { Arch, WinBuildOptions } from "../metadata"
+import { createWindowsInstaller, convertVersion } from "electron-winstaller-fixed"
+import * as path from "path"
+import { warn } from "../util"
+import { emptyDir } from "fs-extra-p"
+
+//noinspection JSUnusedLocalSymbols
+const __awaiter = require("../awaiter")
+
+export default class SquirrelWindowsTarget {
+ constructor(private packager: WinPackager, private appOutDir: string, private arch: Arch) {
+ }
+
+ async build(packOptions: ElectronPackagerOptions) {
+ const version = this.packager.metadata.version
+ const archSuffix = getArchSuffix(this.arch)
+ const setupExeName = `${this.packager.appName} Setup ${version}${archSuffix}.exe`
+
+ const installerOutDir = path.join(this.appOutDir, "..", `win${getArchSuffix(this.arch)}`)
+ await emptyDir(installerOutDir)
+
+ const distOptions = await this.computeEffectiveDistOptions(installerOutDir, packOptions, setupExeName)
+ await createWindowsInstaller(distOptions)
+ this.packager.dispatchArtifactCreated(path.join(installerOutDir, setupExeName), `${this.packager.metadata.name}-Setup-${version}${archSuffix}.exe`)
+
+ const packagePrefix = `${this.packager.metadata.name}-${convertVersion(version)}-`
+ this.packager.dispatchArtifactCreated(path.join(installerOutDir, `${packagePrefix}full.nupkg`))
+ if (distOptions.remoteReleases != null) {
+ this.packager.dispatchArtifactCreated(path.join(installerOutDir, `${packagePrefix}delta.nupkg`))
+ }
+
+ this.packager.dispatchArtifactCreated(path.join(installerOutDir, "RELEASES"))
+ }
+
+ async computeEffectiveDistOptions(installerOutDir: string, packOptions: ElectronPackagerOptions, setupExeName: string): Promise {
+ const packager = this.packager
+ let iconUrl = packager.customBuildOptions.iconUrl || packager.devMetadata.build.iconUrl
+ if (iconUrl == null) {
+ if (packager.info.repositoryInfo != null) {
+ const info = await packager.info.repositoryInfo.getInfo(packager)
+ if (info != null) {
+ iconUrl = `https://github.com/${info.user}/${info.project}/blob/master/${packager.relativeBuildResourcesDirname}/icon.ico?raw=true`
+ }
+ }
+
+ if (iconUrl == null) {
+ throw new Error("iconUrl is not specified, please see https://github.com/electron-userland/electron-builder/wiki/Options#WinBuildOptions-iconUrl")
+ }
+ }
+
+ checkConflictingOptions(packager.customBuildOptions)
+
+ const projectUrl = await packager.computePackageUrl()
+ const rceditOptions = {
+ "version-string": packOptions["version-string"],
+ "file-version": packOptions["build-version"],
+ "product-version": packOptions["app-version"],
+ }
+ rceditOptions["version-string"]!.LegalCopyright = packOptions["app-copyright"]
+
+ const cscInfo = await packager.cscInfo
+ const options: any = Object.assign({
+ name: packager.metadata.name,
+ productName: packager.appName,
+ exe: packager.appName + ".exe",
+ setupExe: setupExeName,
+ title: packager.appName,
+ appDirectory: this.appOutDir,
+ outputDirectory: installerOutDir,
+ version: packager.metadata.version,
+ description: smarten(packager.metadata.description),
+ authors: packager.metadata.author.name,
+ iconUrl: iconUrl,
+ setupIcon: await packager.iconPath,
+ certificateFile: cscInfo == null ? null : cscInfo.file,
+ certificatePassword: cscInfo == null ? null : cscInfo.password,
+ fixUpPaths: false,
+ skipUpdateIcon: true,
+ usePackageJson: false,
+ extraMetadataSpecs: projectUrl == null ? null : `\n ${projectUrl}`,
+ copyright: packOptions["app-copyright"],
+ packageCompressionLevel: packager.devMetadata.build.compression === "store" ? 0 : 9,
+ sign: {
+ name: packager.appName,
+ site: projectUrl,
+ overwrite: true,
+ hash: packager.customBuildOptions.signingHashAlgorithms,
+ },
+ rcedit: rceditOptions,
+ }, packager.customBuildOptions)
+
+ if (!("loadingGif" in options)) {
+ const resourceList = await packager.resourceList
+ if (resourceList.includes("install-spinner.gif")) {
+ options.loadingGif = path.join(packager.buildResourcesDir, "install-spinner.gif")
+ }
+ }
+
+ return options
+ }
+}
+
+function checkConflictingOptions(options: any) {
+ for (let name of ["outputDirectory", "appDirectory", "exe", "fixUpPaths", "usePackageJson", "extraFileSpecs", "extraMetadataSpecs", "skipUpdateIcon", "setupExe"]) {
+ if (name in options) {
+ throw new Error(`Option ${name} is ignored, do not specify it.`)
+ }
+ }
+
+ if ("noMsi" in options) {
+ warn(`noMsi is deprecated, please specify as "msi": true if you want to create an MSI installer`)
+ options.msi = !options.noMsi
+ }
+
+ const msi = options.msi
+ if (msi != null && typeof msi !== "boolean") {
+ throw new Error(`msi expected to be boolean value, but string '"${msi}"' was specified`)
+ }
+}
\ No newline at end of file
diff --git a/src/util.ts b/src/util.ts
index 87cd7f9b039..9fa01925a4c 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -25,17 +25,20 @@ const DEFAULT_APP_DIR_NAMES = ["app", "www"]
export const readPackageJson = BluebirdPromise.promisify(readPackageJsonAsync)
export function installDependencies(appDir: string, electronVersion: string, arch: string = process.arch, command: string = "install"): BluebirdPromise {
- log((command === "install" ? "Installing" : "Rebuilding") + " app dependencies for arch %s to %s", arch, appDir)
+ log(`${(command === "install" ? "Installing" : "Rebuilding")} app dependencies for arch ${arch} to ${appDir}`)
const gypHome = path.join(os.homedir(), ".electron-gyp")
- const env = Object.assign({}, process.env, {
- npm_config_disturl: "https://atom.io/download/atom-shell",
- npm_config_target: electronVersion,
- npm_config_runtime: "electron",
- npm_config_arch: arch,
- HOME: gypHome,
- USERPROFILE: gypHome,
- })
+ return spawnNpmProduction(command, appDir, Object.assign({}, process.env, {
+ npm_config_disturl: "https://atom.io/download/atom-shell",
+ npm_config_target: electronVersion,
+ npm_config_runtime: "electron",
+ npm_config_arch: arch,
+ HOME: gypHome,
+ USERPROFILE: gypHome,
+ })
+ )
+}
+export function spawnNpmProduction(command: string, appDir: string, env?: any): BluebirdPromise {
let npmExecPath = process.env.npm_execpath || process.env.NPM_CLI_JS
const npmExecArgs = [command, "--production"]
if (npmExecPath == null) {
@@ -49,7 +52,7 @@ export function installDependencies(appDir: string, electronVersion: string, arc
return spawn(npmExecPath, npmExecArgs, {
cwd: appDir,
stdio: "inherit",
- env: env
+ env: env || process.env
})
}
diff --git a/src/winPackager.ts b/src/winPackager.ts
index 9ac2ce19ee6..b5d3b94294b 100644
--- a/src/winPackager.ts
+++ b/src/winPackager.ts
@@ -1,25 +1,26 @@
import { downloadCertificate } from "./codeSign"
import { Promise as BluebirdPromise } from "bluebird"
-import { PlatformPackager, BuildInfo, smarten, getArchSuffix } from "./platformPackager"
+import { PlatformPackager, BuildInfo, getArchSuffix } from "./platformPackager"
import { Platform, WinBuildOptions, Arch } from "./metadata"
import * as path from "path"
import { log, warn } from "./util"
-import { deleteFile, emptyDir, open, close, read } from "fs-extra-p"
+import { deleteFile, open, close, read } from "fs-extra-p"
import { sign, SignOptions } from "signcode-tf"
import { ElectronPackagerOptions } from "electron-packager-tf"
+import SquirrelWindowsTarget from "./targets/squirrelWindows"
//noinspection JSUnusedLocalSymbols
const __awaiter = require("./awaiter")
-interface FileCodeSigningInfo {
+export interface FileCodeSigningInfo {
readonly file: string
readonly password?: string | null
}
export class WinPackager extends PlatformPackager {
- private readonly cscInfo: Promise
+ readonly cscInfo: Promise
- private readonly iconPath: Promise
+ readonly iconPath: Promise
constructor(info: BuildInfo, cleanupTasks: Array<() => Promise>) {
super(info)
@@ -53,8 +54,8 @@ export class WinPackager extends PlatformPackager {
return Platform.WINDOWS
}
- protected get supportedTargets(): Array {
- return []
+ get supportedTargets(): Array {
+ return ["squirrel"]
}
private async getValidIconPath(): Promise {
@@ -74,29 +75,15 @@ export class WinPackager extends PlatformPackager {
const appOutDir = this.computeAppOutDir(outDir, arch)
const packOptions = this.computePackOptions(outDir, appOutDir, arch)
- if (!targets.includes("default")) {
- await this.doPack(packOptions, outDir, appOutDir, arch, this.customBuildOptions)
- return
- }
-
- const installerOut = computeDistOut(outDir, arch)
- await BluebirdPromise.all([
- this.doPack(packOptions, outDir, appOutDir, arch, this.customBuildOptions),
- emptyDir(installerOut)
- ])
-
- postAsyncTasks.push(this.packageInDistributableFormat(appOutDir, installerOut, arch, packOptions))
+ await this.doPack(packOptions, outDir, appOutDir, arch, this.customBuildOptions)
+ await this.sign(appOutDir)
+ this.packageInDistributableFormat(outDir, appOutDir, arch, packOptions, targets, postAsyncTasks)
}
protected computeAppOutDir(outDir: string, arch: Arch): string {
return path.join(outDir, `win${getArchSuffix(arch)}-unpacked`)
}
- protected async doPack(options: ElectronPackagerOptions, outDir: string, appOutDir: string, arch: Arch, customBuildOptions: WinBuildOptions) {
- await super.doPack(options, outDir, appOutDir, arch, customBuildOptions)
- await this.sign(appOutDir)
- }
-
protected async sign(appOutDir: string) {
const cscInfo = await this.cscInfo
if (cscInfo != null) {
@@ -118,89 +105,20 @@ export class WinPackager extends PlatformPackager {
return BluebirdPromise.promisify(sign)(opts)
}
- protected async computeEffectiveDistOptions(appOutDir: string, installerOutDir: string, packOptions: ElectronPackagerOptions, setupExeName: string): Promise {
- let iconUrl = this.customBuildOptions.iconUrl || this.devMetadata.build.iconUrl
- if (iconUrl == null) {
- if (this.info.repositoryInfo != null) {
- const info = await this.info.repositoryInfo.getInfo(this)
- if (info != null) {
- iconUrl = `https://github.com/${info.user}/${info.project}/blob/master/${this.relativeBuildResourcesDirname}/icon.ico?raw=true`
- }
+ protected packageInDistributableFormat(outDir: string, appOutDir: string, arch: Arch, packOptions: ElectronPackagerOptions, targets: Array, promises: Array>): void {
+ for (let target of targets) {
+ if (target === "squirrel.windows" || target === "default") {
+ const helperClass: typeof SquirrelWindowsTarget = require("./targets/squirrelWindows").default
+ promises.push(new helperClass(this, appOutDir, arch).build(packOptions))
}
-
- if (iconUrl == null) {
- throw new Error("iconUrl is not specified, please see https://github.com/electron-userland/electron-builder/wiki/Options#WinBuildOptions-iconUrl")
+ else {
+ log(`Creating Windows ${target}`)
+ // we use app name here - see https://github.com/electron-userland/electron-builder/pull/204
+ const outFile = path.join(outDir, `${this.appName}-${this.metadata.version}${getArchSuffix(arch)}-win.${target}`)
+ promises.push(this.archiveApp(target, appOutDir, outFile)
+ .then(() => this.dispatchArtifactCreated(outFile, `${this.metadata.name}-${this.metadata.version}${getArchSuffix(arch)}-win.${target}`)))
}
}
-
- checkConflictingOptions(this.customBuildOptions)
-
- const projectUrl = await this.computePackageUrl()
- const rceditOptions = {
- "version-string": packOptions["version-string"],
- "file-version": packOptions["build-version"],
- "product-version": packOptions["app-version"],
- }
- rceditOptions["version-string"]!.LegalCopyright = packOptions["app-copyright"]
-
- const cscInfo = await this.cscInfo
- const options: any = Object.assign({
- name: this.metadata.name,
- productName: this.appName,
- exe: this.appName + ".exe",
- setupExe: setupExeName,
- title: this.appName,
- appDirectory: appOutDir,
- outputDirectory: installerOutDir,
- version: this.metadata.version,
- description: smarten(this.metadata.description),
- authors: this.metadata.author.name,
- iconUrl: iconUrl,
- setupIcon: await this.iconPath,
- certificateFile: cscInfo == null ? null : cscInfo.file,
- certificatePassword: cscInfo == null ? null : cscInfo.password,
- fixUpPaths: false,
- skipUpdateIcon: true,
- usePackageJson: false,
- extraMetadataSpecs: projectUrl == null ? null : `\n ${projectUrl}`,
- copyright: packOptions["app-copyright"],
- packageCompressionLevel: this.devMetadata.build.compression === "store" ? 0 : 9,
- sign: {
- name: this.appName,
- site: projectUrl,
- overwrite: true,
- hash: this.customBuildOptions.signingHashAlgorithms,
- },
- rcedit: rceditOptions,
- }, this.customBuildOptions)
-
- 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
- }
-
- protected async packageInDistributableFormat(appOutDir: string, installerOutDir: string, arch: Arch, packOptions: ElectronPackagerOptions): Promise {
- const winstaller = require("electron-winstaller-fixed")
- const version = this.metadata.version
- const archSuffix = getArchSuffix(arch)
- const setupExeName = `${this.appName} Setup ${version}${archSuffix}.exe`
-
- const distOptions = await this.computeEffectiveDistOptions(appOutDir, installerOutDir, packOptions, setupExeName)
- await winstaller.createWindowsInstaller(distOptions)
- this.dispatchArtifactCreated(path.join(installerOutDir, setupExeName), `${this.metadata.name}-Setup-${version}${archSuffix}.exe`)
-
- const packagePrefix = `${this.metadata.name}-${winstaller.convertVersion(version)}-`
- this.dispatchArtifactCreated(path.join(installerOutDir, `${packagePrefix}full.nupkg`))
- if (distOptions.remoteReleases != null) {
- this.dispatchArtifactCreated(path.join(installerOutDir, `${packagePrefix}delta.nupkg`))
- }
-
- this.dispatchArtifactCreated(path.join(installerOutDir, "RELEASES"))
}
}
@@ -251,26 +169,4 @@ function parseIco(buffer: Buffer): Array {
function isIco(buffer: Buffer): boolean {
return buffer.readUInt16LE(0) === 0 && buffer.readUInt16LE(2) === 1
-}
-
-export function computeDistOut(outDir: string, arch: Arch): string {
- return path.join(outDir, `win${getArchSuffix(arch)}`)
-}
-
-function checkConflictingOptions(options: any) {
- for (let name of ["outputDirectory", "appDirectory", "exe", "fixUpPaths", "usePackageJson", "extraFileSpecs", "extraMetadataSpecs", "skipUpdateIcon", "setupExe"]) {
- if (name in options) {
- throw new Error(`Option ${name} is ignored, do not specify it.`)
- }
- }
-
- if ("noMsi" in options) {
- warn(`noMsi is deprecated, please specify as "msi": true if you want to create an MSI installer`)
- options.msi = !options.noMsi
- }
-
- const msi = options.msi
- if (msi != null && typeof msi !== "boolean") {
- throw new Error(`msi expected to be boolean value, but string '"${msi}"' was specified`)
- }
}
\ No newline at end of file
diff --git a/test/src/globTest.ts b/test/src/globTest.ts
index 56fbc96e218..12774726fa1 100644
--- a/test/src/globTest.ts
+++ b/test/src/globTest.ts
@@ -29,7 +29,51 @@ test.ifDevOrLinuxCi("ignore build resources", () => {
})
})
-test("copy extra content", async () => {
+test.ifDevOrLinuxCi("files", () => {
+ return assertPack("test-app-one", {
+ targets: Platform.LINUX.createTarget(DIR_TARGET),
+ devMetadata: {
+ build: {
+ asar: false,
+ files: ["**/*", "!ignoreMe${/*}"]
+ }
+ }
+ }, {
+ tempDirCreated: projectDir => {
+ return outputFile(path.join(projectDir, "ignoreMe", "foo"), "data")
+ },
+ packed: projectDir => {
+ return assertThat(path.join(projectDir, outDirName, "linux", "resources", "app", "ignoreMe")).doesNotExist()
+ },
+ })
+})
+
+test.ifDevOrLinuxCi("ignore node_modules known dev dep", () => {
+ return assertPack("test-app-one", {
+ targets: Platform.LINUX.createTarget(DIR_TARGET),
+ devMetadata: {
+ build: {
+ asar: false,
+ }
+ }
+ }, {
+ tempDirCreated: projectDir => {
+ return BluebirdPromise.all([
+ modifyPackageJson(projectDir, data => {
+ data.devDependencies = Object.assign({
+ "electron-osx-sign": "*",
+ }, data.devDependencies)
+ }),
+ outputFile(path.join(projectDir, "node_modules", "electron-osx-sign", "package.json"), "{}"),
+ ])
+ },
+ packed: projectDir => {
+ return assertThat(path.join(projectDir, outDirName, "linux", "resources", "app", "node_modules", "electron-osx-sign")).doesNotExist()
+ },
+ })
+})
+
+test("extraResources", async () => {
for (let platform of getPossiblePlatforms().keys()) {
const osName = platform.buildConfigurationKey
diff --git a/test/src/helpers/fileAssert.ts b/test/src/helpers/fileAssert.ts
index 697f3cd4e83..1a4a27a1067 100644
--- a/test/src/helpers/fileAssert.ts
+++ b/test/src/helpers/fileAssert.ts
@@ -25,15 +25,11 @@ class Assertions {
}
isEqualTo(expected: any) {
- if (!json8.equal(this.actual, expected)) {
- const actualJson = JSON.stringify(this.actual, jsonReplacer, 2)
- const expectedJson = JSON.stringify(expected, jsonReplacer, 2)
- throw new AssertionError({
- message: `Expected \n${expectedJson}\n\nis not equal to\n\n${actualJson}\n\n${prettyDiff(JSON.parse(actualJson), JSON.parse(expectedJson))}`,
- actual: this.actual,
- expected: expected,
- })
- }
+ compare(this.actual, expected)
+ }
+
+ containsAll(expected: Iterable) {
+ compare(this.actual.slice().sort(), Array.from(expected).slice().sort())
}
isAbsolute() {
@@ -76,4 +72,17 @@ function prettyDiff(actual: any, expected: any): string {
return gray(part.value.replace(/.+/g, ' | $&'))
}).join('')
return `\n${diff}\n`
+}
+
+function compare(actual: any, expected: any) {
+ if (!json8.equal(actual, expected)) {
+ const actualJson = JSON.stringify(actual, jsonReplacer, 2)
+ const expectedJson = JSON.stringify(expected, jsonReplacer, 2)
+ const stack = new Error().stack
+ throw new AssertionError({
+ message: `Expected \n${expectedJson}\n\nis not equal to\n\n${actualJson}\n\n${prettyDiff(JSON.parse(actualJson), JSON.parse(expectedJson))}\n${stack.split("\n")[3].trim()}`,
+ actual: actual,
+ expected: expected,
+ })
+ }
}
\ No newline at end of file
diff --git a/test/src/helpers/packTester.ts b/test/src/helpers/packTester.ts
index 2ee8dac9269..b9779aa6a68 100755
--- a/test/src/helpers/packTester.ts
+++ b/test/src/helpers/packTester.ts
@@ -9,7 +9,7 @@ import { Packager, PackagerOptions, Platform, getProductName, ArtifactCreated, A
import { exec, getTempName } from "out/util"
import { createTargets } from "out"
import { tmpdir } from "os"
-import { getArchSuffix } from "out/platformPackager"
+import { getArchSuffix, computeEffectiveTargets } from "out/platformPackager"
import pathSorter = require("path-sort")
import DecompressZip = require("decompress-zip")
@@ -43,7 +43,7 @@ export async function assertPack(fixtureName: string, packagerOptions: PackagerO
// non-osx test uses the same dir as osx test, but we cannot share node_modules (because tests executed in parallel)
const dir = customTmpDir == null ? path.join(tmpdir(), `${getTempName("electron-builder-test")}`) : path.resolve(customTmpDir)
if (customTmpDir != null) {
- console.log("Custom temp dir used: %s", customTmpDir)
+ console.log(`Custom temp dir used: ${customTmpDir}`)
}
await emptyDir(dir)
await copy(projectDir, dir, {
@@ -113,7 +113,7 @@ async function packAndCheck(projectDir: string, packagerOptions: PackagerOptions
await checkLinuxResult(projectDir, packager, checkOptions, artifacts.get(Platform.LINUX), arch)
}
else if (platform === Platform.WINDOWS) {
- await checkWindowsResult(packager, checkOptions, artifacts.get(Platform.WINDOWS), arch)
+ await checkWindowsResult(packager, targets, checkOptions, artifacts.get(Platform.WINDOWS), arch)
}
}
}
@@ -131,7 +131,7 @@ async function checkLinuxResult(projectDir: string, packager: Packager, checkOpt
return result
}
- assertThat(getFileNames(artifacts)).isEqualTo((checkOptions == null || checkOptions.expectedArtifacts == null ? getExpected() : checkOptions.expectedArtifacts.slice()).sort())
+ assertThat(getFileNames(artifacts)).containsAll(checkOptions == null || checkOptions.expectedArtifacts == null ? getExpected() : checkOptions.expectedArtifacts)
if (!targets.includes("deb") || !targets.includes("default")) {
return
@@ -223,35 +223,44 @@ async function checkOsXResult(packager: Packager, packagerOptions: PackagerOptio
}
function getFileNames(list: Array): Array {
- return list.map(it => path.basename(it.file)).sort()
+ return list.map(it => path.basename(it.file))
}
-async function checkWindowsResult(packager: Packager, checkOptions: AssertPackOptions, artifacts: Array, arch: Arch) {
+async function checkWindowsResult(packager: Packager, targets: Array, checkOptions: AssertPackOptions, artifacts: Array, arch: Arch) {
const productName = getProductName(packager.metadata, packager.devMetadata)
+ let squirrel = false
- function getExpectedFileNames(archSuffix: string) {
- const result = [
- `RELEASES`,
- `${productName} Setup 1.1.0${archSuffix}.exe`,
- `TestApp-1.1.0-full.nupkg`,
- ]
- const buildOptions = packager.devMetadata.build.win
- if (buildOptions != null && buildOptions.remoteReleases != null) {
- result.push(`${productName}-1.1.0-delta.nupkg`)
+ const artifactNames: Array = []
+ const expectedFileNames: Array = []
+ const archSuffix = getArchSuffix(arch)
+ const buildOptions = packager.devMetadata.build.win
+ for (let target of computeEffectiveTargets(targets, buildOptions == null ? null : buildOptions.target)) {
+ if (target === "default" || target === "squirrel") {
+ squirrel = true
+ expectedFileNames.push("RELEASES", `${productName} Setup 1.1.0${archSuffix}.exe`, `TestApp-1.1.0-full.nupkg`)
+
+ if (buildOptions != null && buildOptions.remoteReleases != null) {
+ expectedFileNames.push(`${productName}-1.1.0-delta.nupkg`)
+ }
+
+ artifactNames.push(`TestApp-Setup-1.1.0${archSuffix}.exe`)
+ }
+ else {
+ expectedFileNames.push(`${productName}-1.1.0${archSuffix}-win.${target}`)
+
+ artifactNames.push(`TestApp-1.1.0${archSuffix}-win.${target}`)
}
- return result
}
- const archSuffix = getArchSuffix(arch)
- assertThat(getFileNames(artifacts)).isEqualTo((checkOptions == null || checkOptions.expectedArtifacts == null ? getExpectedFileNames(archSuffix) : checkOptions.expectedArtifacts.slice()).sort())
+ assertThat(getFileNames(artifacts)).containsAll(checkOptions == null || checkOptions.expectedArtifacts == null ? expectedFileNames : checkOptions.expectedArtifacts)
- if (checkOptions != null && checkOptions.expectedArtifacts != null) {
+ if (!squirrel || (checkOptions != null && checkOptions.expectedArtifacts != null)) {
return
}
- assertThat(artifacts.map(it => it.artifactName).filter(it => it != null)).isEqualTo([`TestApp-Setup-1.1.0${archSuffix}.exe`])
+ assertThat(artifacts.map(it => it.artifactName).filter(it => it != null)).containsAll(artifactNames)
- const packageFile = path.join(path.dirname(artifacts[0].file), `TestApp-1.1.0-full.nupkg`)
+ const packageFile = artifacts.find(it => it.file.endsWith("-full.nupkg"))!.file
const unZipper = new DecompressZip(packageFile)
const fileDescriptors = await unZipper.getFiles()
diff --git a/test/src/osxPackagerTest.ts b/test/src/osxPackagerTest.ts
index 7ef7677d222..255c49de673 100644
--- a/test/src/osxPackagerTest.ts
+++ b/test/src/osxPackagerTest.ts
@@ -174,7 +174,7 @@ class CheckingOsXPackager extends OsXPackager {
this.effectiveFlatOptions = opts
}
- async packageInDistributableFormat(outDir: string, appOutDir: string, targets: Array): Promise {
+ packageInDistributableFormat(appOutDir: string, targets: Array, promises: Array>): void {
// skip
}
}
\ No newline at end of file
diff --git a/test/src/winPackagerTest.ts b/test/src/winPackagerTest.ts
index a7a1e4c9ede..4d655e208bf 100755
--- a/test/src/winPackagerTest.ts
+++ b/test/src/winPackagerTest.ts
@@ -3,17 +3,18 @@ import test from "./helpers/avaEx"
import { assertPack, platform, modifyPackageJson, signed } from "./helpers/packTester"
import { move, outputFile } from "fs-extra-p"
import * as path from "path"
-import { WinPackager, computeDistOut } from "out/winPackager"
+import { WinPackager } from "out/winPackager"
import { Promise as BluebirdPromise } from "bluebird"
import { ElectronPackagerOptions } from "electron-packager-tf"
import { assertThat } from "./helpers/fileAssert"
import { SignOptions } from "signcode-tf"
+import SquirrelWindowsTarget from "out/targets/squirrelWindows"
//noinspection JSUnusedLocalSymbols
const __awaiter = require("out/awaiter")
test.ifDevOrWinCi("win", () => assertPack("test-app-one", signed({
- targets: Platform.WINDOWS.createTarget(),
+ targets: Platform.WINDOWS.createTarget(["default", "zip"]),
})
))
@@ -115,15 +116,16 @@ class CheckingWinPackager extends WinPackager {
async pack(outDir: string, arch: Arch, targets: Array, postAsyncTasks: Array>): Promise {
// skip pack
- const installerOutDir = computeDistOut(outDir, arch)
const appOutDir = this.computeAppOutDir(outDir, arch)
const packOptions = this.computePackOptions(outDir, appOutDir, arch)
- this.effectiveDistOptions = await this.computeEffectiveDistOptions(appOutDir, installerOutDir, packOptions, "Foo.exe")
+
+ const helperClass: typeof SquirrelWindowsTarget = require("out/targets/squirrelWindows").default
+ this.effectiveDistOptions = await (new helperClass(this, appOutDir, arch).computeEffectiveDistOptions("foo", packOptions, "Foo.exe"))
await this.sign(appOutDir)
}
- async packageInDistributableFormat(appOutDir: string, installerOutDir: string, arch: Arch, packOptions: ElectronPackagerOptions): Promise {
+ packageInDistributableFormat(outDir: string, appOutDir: string, arch: Arch, packOptions: ElectronPackagerOptions, targets: Array, promises: Array>): void {
// skip
}
diff --git a/test/tsconfig.json b/test/tsconfig.json
index c98400d64c0..b910be012e8 100755
--- a/test/tsconfig.json
+++ b/test/tsconfig.json
@@ -33,6 +33,7 @@
"../typings/compareVersions.d.ts",
"../typings/deep-assign.d.ts",
"../typings/electron-packager.d.ts",
+ "../typings/electron-winstaller-fixed.d.ts",
"../typings/gh-api.d.ts",
"../typings/hosted-git-info.d.ts",
"../typings/lib.es2016.array.include.d.ts",
@@ -42,6 +43,7 @@
"../typings/main/definitions/debug/index.d.ts",
"../typings/main/definitions/source-map-support/source-map-support.d.ts",
"../typings/modules/glob/index.d.ts",
+ "../typings/modules/minimatch/index.d.ts",
"../typings/node.d.ts",
"../typings/progress-stream.d.ts",
"../typings/read-package-json.d.ts",
diff --git a/tsconfig.json b/tsconfig.json
index acb8a3b8b6a..ab9d4e96589 100755
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -20,7 +20,7 @@
},
"docs": "docs/Options.md",
"filesGlob": [
- "src/*.ts",
+ "src/**/*.ts",
"lib/*.d.ts",
"typings/**/*.d.ts",
"!typings/browser/**/*.d.ts",
@@ -37,6 +37,7 @@
"typings/compareVersions.d.ts",
"typings/deep-assign.d.ts",
"typings/electron-packager.d.ts",
+ "typings/electron-winstaller-fixed.d.ts",
"typings/gh-api.d.ts",
"typings/hosted-git-info.d.ts",
"typings/lib.es2016.array.include.d.ts",
@@ -46,6 +47,7 @@
"typings/main/definitions/debug/index.d.ts",
"typings/main/definitions/source-map-support/source-map-support.d.ts",
"typings/modules/glob/index.d.ts",
+ "typings/modules/minimatch/index.d.ts",
"typings/node.d.ts",
"typings/progress-stream.d.ts",
"typings/read-package-json.d.ts",
@@ -65,7 +67,6 @@
"src/fpmDownload.ts",
"src/gitHubPublisher.ts",
"src/gitHubRequest.ts",
- "src/globby.ts",
"src/httpRequest.ts",
"src/index.ts",
"src/install-app-deps.ts",
@@ -76,6 +77,8 @@
"src/platformPackager.ts",
"src/promise.ts",
"src/repositoryInfo.ts",
+ "src/targets/archive.ts",
+ "src/targets/squirrelWindows.ts",
"src/util.ts",
"src/winPackager.ts"
]
diff --git a/typings.json b/typings.json
index ee848027787..621a51e7b24 100755
--- a/typings.json
+++ b/typings.json
@@ -5,6 +5,7 @@
},
"dependencies": {
"glob": "registry:npm/glob#6.0.0+20160211003958",
+ "minimatch": "registry:npm/minimatch#3.0.0+20160211003958",
"source-map-support": "github:typed-typings/npm-source-map-support#900ed4180a22285bce4bbabc0760427e71a59eca"
}
}
diff --git a/typings/asar.d.ts b/typings/asar.d.ts
index 41ab7a713e4..024fce4d474 100644
--- a/typings/asar.d.ts
+++ b/typings/asar.d.ts
@@ -8,7 +8,7 @@ declare module "asar" {
interface AsarFileMetadata {
type: "file" | "directory" | "link"
- stat: Stats
+ stat?: Stats
}
interface AsarOptions {
diff --git a/typings/electron-packager.d.ts b/typings/electron-packager.d.ts
index fd87b0609fb..f16b806f0b0 100644
--- a/typings/electron-packager.d.ts
+++ b/typings/electron-packager.d.ts
@@ -62,6 +62,8 @@ declare module "electron-packager-tf" {
"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). */
@@ -76,5 +78,7 @@ declare module "electron-packager-tf" {
InternalName?: string;
}
+ export function userIgnoreFilter(opts: ElectronPackagerOptions): any
+
export function pack(opts: ElectronPackagerOptions): Promise
}
\ No newline at end of file
diff --git a/typings/electron-winstaller-fixed.d.ts b/typings/electron-winstaller-fixed.d.ts
new file mode 100644
index 00000000000..6739ffc9ad8
--- /dev/null
+++ b/typings/electron-winstaller-fixed.d.ts
@@ -0,0 +1,5 @@
+declare module "electron-winstaller-fixed" {
+ export function createWindowsInstaller(options: any): Promise
+
+ export function convertVersion(version: string): string
+}
\ No newline at end of file
diff --git a/typings/modules/minimatch/index.d.ts b/typings/modules/minimatch/index.d.ts
new file mode 100644
index 00000000000..30a5fbae834
--- /dev/null
+++ b/typings/modules/minimatch/index.d.ts
@@ -0,0 +1,116 @@
+// Generated by typings
+// Source: https://raw.githubusercontent.com/typed-typings/npm-minimatch/74f47de8acb42d668491987fc6bc144e7d9aa891/minimatch.d.ts
+declare module '~minimatch/minimatch' {
+function minimatch (target: string, pattern: string, options?: minimatch.Options): boolean;
+
+namespace minimatch {
+ export function match (list: string[], pattern: string, options?: Options): string[];
+ export function filter (pattern: string, options?: Options): (element: string, indexed: number, array: string[]) => boolean;
+ export function makeRe (pattern: string, options?: Options): RegExp;
+
+ /**
+ * All options are `false` by default.
+ */
+ export interface Options {
+ /**
+ * Dump a ton of stuff to stderr.
+ */
+ debug?: boolean;
+ /**
+ * Do not expand `{a,b}` and `{1..3}` brace sets.
+ */
+ nobrace?: boolean;
+ /**
+ * Disable `**` matching against multiple folder names.
+ */
+ noglobstar?: boolean;
+ /**
+ * Allow patterns to match filenames starting with a period, even if the pattern does not explicitly have a period in that spot.
+ *
+ * Note that by default, `a\/**\/b` will not match `a/.d/b`, unless `dot` is set.
+ */
+ dot?: boolean;
+ /**
+ * Disable "extglob" style patterns like `+(a|b)`.
+ */
+ noext?: boolean;
+ /**
+ * Perform a case-insensitive match.
+ */
+ nocase?: boolean;
+ /**
+ * When a match is not found by `minimatch.match`, return a list containing the pattern itself if this option is set. When not set, an empty list is returned if there are no matches.
+ */
+ nonull?: boolean;
+ /**
+ * If set, then patterns without slashes will be matched against the basename of the path if it contains slashes. For example, `a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`.
+ */
+ matchBase?: boolean;
+ /**
+ * Suppress the behavior of treating `#` at the start of a pattern as a comment.
+ */
+ nocomment?: boolean;
+ /**
+ * Suppress the behavior of treating a leading `!` character as negation.
+ */
+ nonegate?: boolean;
+ /**
+ * Returns from negate expressions the same as if they were not negated. (Ie, true on a hit, false on a miss.)
+ */
+ flipNegate?: boolean;
+ }
+
+ export class Minimatch {
+ constructor (pattern: string, options?: Options);
+
+ /**
+ * The original pattern the minimatch object represents.
+ */
+ pattern: string;
+ /**
+ * The options supplied to the constructor.
+ */
+ options: Options;
+
+ /**
+ * Created by the `makeRe` method. A single regular expression expressing the entire pattern. This is useful in cases where you wish to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled.
+ */
+ regexp: RegExp;
+ /**
+ * True if the pattern is negated.
+ */
+ negate: boolean;
+ /**
+ * True if the pattern is a comment.
+ */
+ comment: boolean;
+ /**
+ * True if the pattern is `""`.
+ */
+ empty: boolean;
+
+ /**
+ * Generate the regexp member if necessary, and return it. Will return false if the pattern is invalid.
+ */
+ makeRe (): RegExp | boolean;
+ /**
+ * Return true if the filename matches the pattern, or false otherwise.
+ */
+ match (fname: string, partial?: boolean): boolean;
+ /**
+ * Take a `/-`split filename, and match it against a single row in the `regExpSet`. This method is mainly for internal use, but is exposed so that it can be used by a glob-walker that needs to avoid excessive filesystem calls.
+ */
+ matchOne (fileArray: string[], patternArray: string[], partial: boolean): boolean;
+ }
+}
+
+export = minimatch;
+}
+declare module 'minimatch/minimatch' {
+import alias = require('~minimatch/minimatch');
+export = alias;
+}
+declare module 'minimatch' {
+import alias = require('~minimatch/minimatch');
+export = alias;
+}
diff --git a/typings/modules/minimatch/typings.json b/typings/modules/minimatch/typings.json
new file mode 100644
index 00000000000..22ff949ed9f
--- /dev/null
+++ b/typings/modules/minimatch/typings.json
@@ -0,0 +1,11 @@
+{
+ "resolution": "main",
+ "tree": {
+ "src": "https://raw.githubusercontent.com/typed-typings/npm-minimatch/74f47de8acb42d668491987fc6bc144e7d9aa891/typings.json",
+ "raw": "registry:npm/minimatch#3.0.0+20160211003958",
+ "main": "minimatch.d.ts",
+ "global": false,
+ "name": "minimatch",
+ "type": "typings"
+ }
+}