Skip to content

Commit

Permalink
feat: prevent error "Unable to find a valid app"
Browse files Browse the repository at this point in the history
Closes #633
  • Loading branch information
develar committed Aug 4, 2016
1 parent 753cd08 commit 1778a8d
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 28 deletions.
18 changes: 15 additions & 3 deletions docs/Options.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ Here documented only `electron-builder` specific options:
| app-category-type | <a name="BuildMetadata-app-category-type"></a><p>*macOS-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> <p>Or you can pass object of any asar options.</p> <p>electron-builder detects node modules that must be unpacked automatically, you don’t need to explicitly set <code>asar.unpackDir</code> - please file issue if this doesn’t work.</p>
| productName | <a name="BuildMetadata-productName"></a>See [AppMetadata.productName](#AppMetadata-productName).
| files | <a name="BuildMetadata-files"></a><p>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 <code>**\/\*</code> (i.e. [hidden files are ignored by default](https://www.npmjs.com/package/glob#dots)).</p> <p>Development dependencies are never copied in any case. You don’t need to ignore it explicitly.</p> <p>[Multiple patterns](#multiple-glob-patterns) are supported. You can use <code>${os}</code> (expanded to mac, linux or win according to current platform) and <code>${arch}</code> in the pattern. If directory matched, all contents are copied. So, you can just specify <code>foo</code> to copy <code>foo</code> directory.</p> <p>Remember that default pattern <code>\*\*\/\*</code> is not added to your custom, so, you have to add it explicitly — e.g. <code>[&quot;\*\*\/\*&quot;, &quot;!ignoreMe${/\*}&quot;]</code>.</p> <p>May be specified in the platform options (e.g. in the <code>build.mac</code>).</p>
| extraResources | <a name="BuildMetadata-extraResources"></a><p>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 (<code>Contents/Resources</code> for MacOS, <code>resources</code> for Linux/Windows).</p> <p>Glob rules the same as for [files](#BuildMetadata-files).</p>
| files | <a name="BuildMetadata-files"></a><p>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. See [File Patterns](#multiple-glob-patterns).</p>
| extraResources | <a name="BuildMetadata-extraResources"></a><p>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 (<code>Contents/Resources</code> for MacOS, <code>resources</code> for Linux/Windows).</p> <p>Glob rules the same as for [files](#multiple-glob-patterns).</p>
| extraFiles | <a name="BuildMetadata-extraFiles"></a>The same as [extraResources](#BuildMetadata-extraResources) but copy into the app's content directory (`Contents` for MacOS, root directory for Linux/Windows).
| mac | <a name="BuildMetadata-mac"></a>See [.build.mac](#MacOptions).
| dmg | <a name="BuildMetadata-dmg"></a>See [.build.dmg](#DmgOptions).
Expand Down Expand Up @@ -174,8 +174,20 @@ NSIS only, [in progress](https://github.com/electron-userland/electron-builder/i

<!-- end of generated block -->

# File Patterns

# Multiple Glob Patterns
[build.files](#BuildMetadata-files) 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 mac, 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.mac`).

## Multiple Glob Patterns
```js
[
// match all files
Expand Down
14 changes: 9 additions & 5 deletions src/asarUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,33 +384,37 @@ function writeAsarFile(filesystem: any, dest: string, toPack: Array<string>, cha
})
}

export async function checkFileInPackage(asarFile: string, relativeFile: string) {
export async function checkFileInArchive(asarFile: string, relativeFile: string, messagePrefix: string) {
function error(text: string) {
return new Error(`${messagePrefix} "${relativeFile}" in the "${asarFile}" ${text}`)
}

let stat: AsarFileInfo | null
try {
stat = statFile(asarFile, relativeFile)
}
catch (e) {
const fileStat = await statOrNull(asarFile)
if (fileStat == null) {
throw new Error(`File "${asarFile}" does not exist. Seems like a wrong configuration.`)
throw error(`does not exist. Seems like a wrong configuration.`)
}

try {
listPackage(asarFile)
}
catch (e) {
throw new Error(`File "${asarFile}" is corrupted: ${e}`)
throw error(`is corrupted: ${e}`)
}

// asar throws error on access to undefined object (info.link)
stat = null
}

if (stat == null) {
throw new Error(`Application entry file "${relativeFile}" in the "${asarFile}" does not exist. Seems like a wrong configuration.`)
throw error(`does not exist. Seems like a wrong configuration.`)
}
if (stat.size === 0) {
throw new Error(`Application entry file "${relativeFile}" in the "${asarFile}" is corrupted: size 0`)
throw error(`is corrupted: size 0`)
}
}

Expand Down
16 changes: 5 additions & 11 deletions src/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { ElectronPackagerOptions } from "./packager/dirPackager"

export interface Metadata {
readonly repository?: string | RepositoryInfo | null

dependencies?: { [key: string]: string }
}

/*
Expand Down Expand Up @@ -122,23 +124,15 @@ export interface BuildMetadata {
readonly productName?: string | null

/**
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 mac, 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.mac`).
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.
See [File Patterns](#multiple-glob-patterns).
*/
readonly files?: Array<string> | string | null

/**
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 MacOS, `resources` for Linux/Windows).
Glob rules the same as for [files](#BuildMetadata-files).
Glob rules the same as for [files](#multiple-glob-patterns).
*/
readonly extraResources?: Array<string> | string | null

Expand Down
15 changes: 15 additions & 0 deletions src/packager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,10 @@ export class Packager implements BuildInfo {
checkNotEmpty("description", appMetadata.description)
checkNotEmpty("version", appMetadata.version)

checkDependencies(this.devMetadata.dependencies)
if ((<any>appMetadata) !== this.devMetadata) {
checkDependencies(appMetadata.dependencies)

if ((<any>appMetadata).build != null) {
throw new Error(util.format(errorMessages.buildInAppSpecified, appPackageFile, devAppPackageFile))
}
Expand Down Expand Up @@ -282,4 +285,16 @@ async function checkWineVersion(checkPromise: Promise<string>) {
if (semver.lt(wineVersion, "1.8.0")) {
throw new Error(wineError(`wine 1.8+ is required, but your version is ${wineVersion}`))
}
}

function checkDependencies(dependencies?: { [key: string]: string }) {
if (dependencies == null) {
return
}

for (let name of ["electron", "electron-prebuilt", "electron-builder"]) {
if (name in dependencies) {
throw new Error(`${name} must be in the devDependencies`)
}
}
}
16 changes: 8 additions & 8 deletions src/platformPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Packager } from "./packager"
import { AsarOptions } from "asar-electron-builder"
import { archiveApp } from "./targets/archive"
import { Minimatch } from "minimatch"
import { checkFileInPackage, createAsarArchive } from "./asarUtil"
import { checkFileInArchive, createAsarArchive } from "./asarUtil"
import { deepAssign } from "./util/deepAssign"
import { warn, log, task } from "./util/log"
import { AppInfo } from "./appInfo"
Expand Down Expand Up @@ -362,34 +362,34 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
return path.join(appOutDir, `${this.appInfo.productFilename}.app`, "Contents", "Resources")
}

private async checkFileInPackage(resourcesDir: string, file: string, isAsar: boolean) {
private async checkFileInPackage(resourcesDir: string, file: string, messagePrefix: string, isAsar: boolean) {
const relativeFile = path.relative(this.info.appDir, path.resolve(this.info.appDir, file))
if (isAsar) {
await checkFileInPackage(path.join(resourcesDir, "app.asar"), relativeFile)
await checkFileInArchive(path.join(resourcesDir, "app.asar"), relativeFile, messagePrefix)
}
else {
const outStat = await statOrNull(path.join(resourcesDir, "app", relativeFile))
if (outStat == null) {
throw new Error(`Application entry file "${relativeFile}" does not exist. Seems like a wrong configuration.`)
throw new Error(`${messagePrefix} "${relativeFile}" does not exist. Seems like a wrong configuration.`)
}
else if (!outStat.isFile()) {
throw new Error(`Application entry file "${relativeFile}" is not a file. Seems like a wrong configuration.`)
throw new Error(`${messagePrefix} "${relativeFile}" is not a file. Seems like a wrong configuration.`)
}
}
}

private async sanityCheckPackage(appOutDir: string, isAsar: boolean): Promise<any> {
const outStat = await statOrNull(appOutDir)

if (outStat == null) {
throw new Error(`Output directory "${appOutDir}" does not exist. Seems like a wrong configuration.`)
}
else if (!outStat.isDirectory()) {
throw new Error(`Output directory "${appOutDir}" is not a directory. Seems like a wrong configuration.`)
}

const mainFile = this.appInfo.metadata.main || "index.js"
await this.checkFileInPackage(this.getResourcesDir(appOutDir), mainFile, isAsar)
const resourcesDir = this.getResourcesDir(appOutDir)
await this.checkFileInPackage(resourcesDir, this.appInfo.metadata.main || "index.js", "Application entry file", isAsar)
await this.checkFileInPackage(resourcesDir, "package.json", "Application", isAsar)
}

protected async archiveApp(format: string, appOutDir: string, outFile: string): Promise<any> {
Expand Down
5 changes: 4 additions & 1 deletion src/util/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ export async function computeDefaultAppDirectory(projectDir: string, userAppDir:
else if (!stat.isDirectory()) {
throw new Error(`Application directory ${userAppDir} is not a directory`)
}
else if (projectDir === absolutePath) {
warn(`Specified application directory "${userAppDir}" equals to project dir — superfluous or wrong configuration`)
}
return absolutePath
}

Expand Down Expand Up @@ -238,7 +241,7 @@ let tmpDirCounter = 0
const tempDirPrefix = `${process.pid.toString(36)}-${Date.now().toString(36)}`

export function getTempName(prefix?: string | n): string {
return `${prefix == null ? "" : prefix + "-"}${tempDirPrefix}-${(tmpDirCounter++).toString(36)}`
return `${prefix == null ? "" : `${prefix}-`}${tempDirPrefix}-${(tmpDirCounter++).toString(36)}`
}

export function isEmptyOrSpaces(s: string | n) {
Expand Down

0 comments on commit 1778a8d

Please sign in to comment.