Skip to content

Commit

Permalink
fix: Application entry can't be found
Browse files Browse the repository at this point in the history
Closes #371
  • Loading branch information
develar committed Jun 3, 2016
1 parent 7c2a3bc commit a7b2932
Show file tree
Hide file tree
Showing 14 changed files with 521 additions and 44 deletions.
2 changes: 1 addition & 1 deletion docs/Options.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Here documented only `electron-builder` specific options:
| --- | ---
| app-bundle-id | <a name="BuildMetadata-app-bundle-id"></a>*OS X-only.* The app bundle ID. See [CFBundleIdentifier](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/20001431-102070).
| app-category-type | <a name="BuildMetadata-app-category-type"></a><p>*OS X-only.* The application category type, as shown in the Finder via *View -&gt; Arrange by Application Category* when viewing the Applications directory.</p> <p>For example, <code>app-category-type=public.app-category.developer-tools</code> will set the application category to *Developer Tools*.</p> <p>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).</p>
| asar | <a name="BuildMetadata-asar"></a><p>Whether to package the application’s source code into an archive, using [Electron’s archive format](https://github.com/electron/asar). Defaults to <code>true</code>. 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/).</p>
| asar | <a name="BuildMetadata-asar"></a><p>Whether to package the application’s source code into an archive, using [Electron’s archive format](https://github.com/electron/asar). Defaults to <code>true</code>. 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/).</p> <p>Or you can pass object of any asar options.</p>
| productName | <a name="BuildMetadata-productName"></a>See [AppMetadata.productName](#AppMetadata-productName).
| extraResources | <a name="BuildMetadata-extraResources"></a><p>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 (<code>Contents/Resources</code> for OS X, <code>resources</code> for Linux/Windows).</p> <p>You can use <code>${os}</code> (expanded to osx, linux or win according to current platform) and <code>${arch}</code> in the pattern.</p> <p>If directory matched, all contents are copied. So, you can just specify <code>foo</code> to copy <code>&lt;project_dir&gt;/foo</code> directory.</p> <p>May be specified in the platform options (i.e. in the <code>build.osx</code>).</p>
| extraFiles | <a name="BuildMetadata-extraFiles"></a>The same as [extraResources](#BuildMetadata-extraResources) but copy into the app's content directory (`Contents` for OS X, `` for Linux/Windows).
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@
"deep-assign": "^2.0.0",
"electron-osx-sign-tf": "0.6.0",
"electron-packager-tf": "~7.3.0",
"electron-winstaller-fixed": "~2.9.4",
"electron-winstaller-fixed": "~2.9.5",
"fs-extra-p": "^1.0.1",
"globby": "^4.1.0",
"glob": "^7.0.3",
"hosted-git-info": "^2.1.5",
"image-size": "^0.5.0",
"lodash.template": "^4.2.5",
Expand Down
55 changes: 55 additions & 0 deletions src/globby.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
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<string>, opts: Options): Array<any> {
opts = Object.assign({ignore: []}, opts)

const globTasks: Array<any> = []
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: (<Array<string>>opts.ignore).concat(ignore)
})
})
})
return globTasks
}

export function globby(patterns: Array<string>, opts: Options): Promise<Set<string>> {
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)))
}
9 changes: 7 additions & 2 deletions src/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ElectronPackagerOptions } from "electron-packager-tf"
import { AsarOptions } from "asar"

export interface Metadata {
readonly repository?: string | RepositoryInfo | null
Expand Down Expand Up @@ -92,9 +93,11 @@ export interface BuildMetadata {

/*
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/).
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.
*/
readonly asar?: boolean
readonly asar?: AsarOptions | boolean | null

// deprecated
readonly iconUrl?: string | null
Expand Down Expand Up @@ -345,6 +348,8 @@ export interface PlatformSpecificBuildOptions {
readonly extraFiles?: Array<string> | null
readonly extraResources?: Array<string> | null

readonly asar?: AsarOptions | boolean

readonly target?: Array<string> | null
}

Expand Down
2 changes: 1 addition & 1 deletion src/packager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class Packager implements BuildInfo {
metadata: AppMetadata
devMetadata: DevMetadata

private isTwoPackageJsonProjectLayoutUsed = true
isTwoPackageJsonProjectLayoutUsed = true

electronVersion: string

Expand Down
122 changes: 104 additions & 18 deletions src/platformPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import EventEmitter = NodeJS.EventEmitter
import { Promise as BluebirdPromise } from "bluebird"
import * as path from "path"
import { pack, ElectronPackagerOptions } from "electron-packager-tf"
import globby = require("globby")
import { readdir, copy, unlink } from "fs-extra-p"
import { statOrNull, use, spawn, debug7zArgs, debug } from "./util"
import { globby } from "./globby"
import { readdir, copy, unlink, lstat, remove } from "fs-extra-p"
import { statOrNull, use, spawn, debug7zArgs, debug, warn } from "./util"
import { Packager } from "./packager"
import deepAssign = require("deep-assign")
import { listPackage, statFile } from "asar"
import { listPackage, statFile, AsarFileMetadata, createPackageFromFiles, AsarOptions } from "asar"
import { path7za } from "7zip-bin"
import deepAssign = require("deep-assign")
import { Glob } from "glob"

//noinspection JSUnusedLocalSymbols
const __awaiter = require("./awaiter")
Expand Down Expand Up @@ -64,6 +65,8 @@ export interface BuildInfo extends ProjectMetadataProvider {

repositoryInfo: InfoRetriever | n
eventEmitter: EventEmitter

isTwoPackageJsonProjectLayoutUsed: boolean
}

export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions> implements ProjectMetadataProvider {
Expand Down Expand Up @@ -149,7 +152,16 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
abstract pack(outDir: string, arch: Arch, targets: Array<string>, postAsyncTasks: Array<Promise<any>>): Promise<any>

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)
}

await this.copyExtraFiles(appOutDir, arch, customBuildOptions)

const afterPack = this.devMetadata.build.afterPack
Expand All @@ -160,7 +172,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
})
}

await this.sanityCheckPackage(appOutDir, <boolean>options.asar)
await this.sanityCheckPackage(appOutDir, asarOptions != null)
}

protected computePackOptions(outDir: string, appOutDir: string, arch: Arch): ElectronPackagerOptions {
Expand All @@ -171,7 +183,8 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
buildVersion += "." + buildNumber
}

const options = deepAssign({
//noinspection JSUnusedGlobalSymbols
const options: any = deepAssign({
dir: this.info.appDir,
out: outDir,
name: this.appName,
Expand All @@ -180,7 +193,6 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
arch: Arch[arch],
version: this.info.electronVersion,
icon: path.join(this.buildResourcesDir, "icon"),
asar: true,
overwrite: true,
"app-version": version,
"app-copyright": `Copyright © ${new Date().getFullYear()} ${this.metadata.author.name || this.appName}`,
Expand All @@ -195,6 +207,14 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
}
}, 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
Expand All @@ -203,23 +223,89 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
return options
}

private getExtraResources(isResources: boolean, arch: Arch, customBuildOptions: DC): Promise<Array<string>> {
const buildMetadata: any = this.devMetadata.build
let extra: Array<string> | n = buildMetadata == null ? null : buildMetadata[isResources ? "extraResources" : "extraFiles"]
private getExtraResources(isResources: boolean, arch: Arch, customBuildOptions: DC): Promise<Set<string>> {
let patterns: Array<string> | n = (<any>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
if (platformSpecific != null) {
result = platformSpecific
}

const platformSpecificExtra = isResources ? customBuildOptions.extraResources : customBuildOptions.extraFiles
if (platformSpecificExtra != null) {
extra = extra == null ? platformSpecificExtra : extra.concat(platformSpecificExtra)
if (result === false) {
return null
}

if (extra == null) {
return BluebirdPromise.resolve([])
const buildMetadata = <ElectronPackagerOptions>this.devMetadata.build
if (buildMetadata["asar-unpack"] != null) {
warn("asar-unpack is deprecated, please set as asar.unpack")
}
if (buildMetadata["asar-unpack-dir"] != null) {
warn("asar-unpack-dir is deprecated, please set as asar.unpackDir")
}

const expandedPatterns = extra.map(it => it
if (result == null || result === true) {
return {
unpack: buildMetadata["asar-unpack"],
unpackDir: buildMetadata["asar-unpack-dir"]
}
}
else {
return result
}
}

private async createAsarArchive(appOutDir: string, options: AsarOptions): Promise<any> {
const src = path.join(this.getResourcesDir(appOutDir), "app")

let glob: Glob | null = null
const files = (await new BluebirdPromise<Array<string>>((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)
}
else {
reject(error)
}
})
})).map(it => path.join(src, it))

const stats = await BluebirdPromise.map(files, it => {
// const stat = glob!.statCache[it]
// return stat == null ? lstat(it) : <any>stat
// todo check is it safe to reuse glob stat
return lstat(it)
})

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,
}
}

await BluebirdPromise.promisify(createPackageFromFiles)(src, path.join(this.getResourcesDir(appOutDir), "app.asar"), files, metadata, options)
await remove(src)
}

private expandPatterns(list: Array<string>, arch: Arch): Array<string> {
return list.map(it => it
.replace(/\$\{arch}/g, Arch[arch])
.replace(/\$\{os}/g, this.platform.buildConfigurationKey))
return globby(expandedPatterns, {cwd: this.projectDir})
}

protected async copyExtraFiles(appOutDir: string, arch: Arch, customBuildOptions: DC): Promise<any> {
Expand Down
2 changes: 1 addition & 1 deletion test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@
"../typings/deep-assign.d.ts",
"../typings/electron-packager.d.ts",
"../typings/gh-api.d.ts",
"../typings/globby.d.ts",
"../typings/hosted-git-info.d.ts",
"../typings/lib.es2016.array.include.d.ts",
"../typings/main/ambient/mime/mime.d.ts",
"../typings/main/ambient/progress/progress.d.ts",
"../typings/main/definitions/chalk/index.d.ts",
"../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/node.d.ts",
"../typings/progress-stream.d.ts",
"../typings/read-package-json.d.ts",
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@
"typings/deep-assign.d.ts",
"typings/electron-packager.d.ts",
"typings/gh-api.d.ts",
"typings/globby.d.ts",
"typings/hosted-git-info.d.ts",
"typings/lib.es2016.array.include.d.ts",
"typings/main/ambient/mime/mime.d.ts",
"typings/main/ambient/progress/progress.d.ts",
"typings/main/definitions/chalk/index.d.ts",
"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/node.d.ts",
"typings/progress-stream.d.ts",
"typings/read-package-json.d.ts",
Expand All @@ -65,6 +65,7 @@
"src/fpmDownload.ts",
"src/gitHubPublisher.ts",
"src/gitHubRequest.ts",
"src/globby.ts",
"src/httpRequest.ts",
"src/index.ts",
"src/install-app-deps.ts",
Expand Down
1 change: 1 addition & 0 deletions typings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"progress": "github:DefinitelyTyped/DefinitelyTyped/progress/progress.d.ts#d54b18e0ac3277376700b6026ef9e9e3f380df50"
},
"dependencies": {
"glob": "registry:npm/glob#6.0.0+20160211003958",
"source-map-support": "github:typed-typings/npm-source-map-support#900ed4180a22285bce4bbabc0760427e71a59eca"
}
}
14 changes: 14 additions & 0 deletions typings/asar.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
declare module "asar" {
import { Stats } from "fs"

interface Info {
offset: number
size: number
}

interface AsarFileMetadata {
type: "file" | "directory" | "link"
stat: Stats
}

interface AsarOptions {
unpack?: string
unpackDir?: string
}

export function listPackage(archive: string): Array<string>

// followLinks defaults to true
export function statFile(archive: string, filename: string, followLinks?: boolean): Info | null

export function createPackageFromFiles(src: string, dest: string, filenames: Array<string>, metadata: { [key: string]: AsarFileMetadata;}, options: AsarOptions, callback: (error?: Error) => void): void
}
Loading

0 comments on commit a7b2932

Please sign in to comment.