Skip to content

Commit 1778a8d

Browse files
committed
feat: prevent error "Unable to find a valid app"
Closes #633
1 parent 753cd08 commit 1778a8d

File tree

6 files changed

+56
-28
lines changed

6 files changed

+56
-28
lines changed

docs/Options.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ Here documented only `electron-builder` specific options:
5454
| 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>
5555
| 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>
5656
| productName | <a name="BuildMetadata-productName"></a>See [AppMetadata.productName](#AppMetadata-productName).
57-
| 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>
58-
| 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>
57+
| 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>
58+
| 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>
5959
| 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).
6060
| mac | <a name="BuildMetadata-mac"></a>See [.build.mac](#MacOptions).
6161
| dmg | <a name="BuildMetadata-dmg"></a>See [.build.dmg](#DmgOptions).
@@ -174,8 +174,20 @@ NSIS only, [in progress](https://github.com/electron-userland/electron-builder/i
174174

175175
<!-- end of generated block -->
176176

177+
# File Patterns
177178

178-
# Multiple Glob Patterns
179+
[build.files](#BuildMetadata-files) defaults to `**/*` (i.e. [hidden files are ignored by default](https://www.npmjs.com/package/glob#dots)).
180+
181+
Development dependencies are never copied in any case. You don't need to ignore it explicitly.
182+
183+
[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.
184+
If directory matched, all contents are copied. So, you can just specify `foo` to copy `foo` directory.
185+
186+
Remember that default pattern `**/*` is not added to your custom, so, you have to add it explicitly — e.g. `["**/*", "!ignoreMe${/*}"]`.
187+
188+
May be specified in the platform options (e.g. in the `build.mac`).
189+
190+
## Multiple Glob Patterns
179191
```js
180192
[
181193
// match all files

src/asarUtil.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -384,33 +384,37 @@ function writeAsarFile(filesystem: any, dest: string, toPack: Array<string>, cha
384384
})
385385
}
386386

387-
export async function checkFileInPackage(asarFile: string, relativeFile: string) {
387+
export async function checkFileInArchive(asarFile: string, relativeFile: string, messagePrefix: string) {
388+
function error(text: string) {
389+
return new Error(`${messagePrefix} "${relativeFile}" in the "${asarFile}" ${text}`)
390+
}
391+
388392
let stat: AsarFileInfo | null
389393
try {
390394
stat = statFile(asarFile, relativeFile)
391395
}
392396
catch (e) {
393397
const fileStat = await statOrNull(asarFile)
394398
if (fileStat == null) {
395-
throw new Error(`File "${asarFile}" does not exist. Seems like a wrong configuration.`)
399+
throw error(`does not exist. Seems like a wrong configuration.`)
396400
}
397401

398402
try {
399403
listPackage(asarFile)
400404
}
401405
catch (e) {
402-
throw new Error(`File "${asarFile}" is corrupted: ${e}`)
406+
throw error(`is corrupted: ${e}`)
403407
}
404408

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

409413
if (stat == null) {
410-
throw new Error(`Application entry file "${relativeFile}" in the "${asarFile}" does not exist. Seems like a wrong configuration.`)
414+
throw error(`does not exist. Seems like a wrong configuration.`)
411415
}
412416
if (stat.size === 0) {
413-
throw new Error(`Application entry file "${relativeFile}" in the "${asarFile}" is corrupted: size 0`)
417+
throw error(`is corrupted: size 0`)
414418
}
415419
}
416420

src/metadata.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { ElectronPackagerOptions } from "./packager/dirPackager"
33

44
export interface Metadata {
55
readonly repository?: string | RepositoryInfo | null
6+
7+
dependencies?: { [key: string]: string }
68
}
79

810
/*
@@ -122,23 +124,15 @@ export interface BuildMetadata {
122124
readonly productName?: string | null
123125

124126
/**
125-
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)).
126-
127-
Development dependencies are never copied in any case. You don't need to ignore it explicitly.
128-
129-
[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.
130-
If directory matched, all contents are copied. So, you can just specify `foo` to copy `foo` directory.
131-
132-
Remember that default pattern `\*\*\/\*` is not added to your custom, so, you have to add it explicitly — e.g. `["\*\*\/\*", "!ignoreMe${/\*}"]`.
133-
134-
May be specified in the platform options (e.g. in the `build.mac`).
127+
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.
128+
See [File Patterns](#multiple-glob-patterns).
135129
*/
136130
readonly files?: Array<string> | string | null
137131

138132
/**
139133
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).
140134
141-
Glob rules the same as for [files](#BuildMetadata-files).
135+
Glob rules the same as for [files](#multiple-glob-patterns).
142136
*/
143137
readonly extraResources?: Array<string> | string | null
144138

src/packager.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,10 @@ export class Packager implements BuildInfo {
168168
checkNotEmpty("description", appMetadata.description)
169169
checkNotEmpty("version", appMetadata.version)
170170

171+
checkDependencies(this.devMetadata.dependencies)
171172
if ((<any>appMetadata) !== this.devMetadata) {
173+
checkDependencies(appMetadata.dependencies)
174+
172175
if ((<any>appMetadata).build != null) {
173176
throw new Error(util.format(errorMessages.buildInAppSpecified, appPackageFile, devAppPackageFile))
174177
}
@@ -282,4 +285,16 @@ async function checkWineVersion(checkPromise: Promise<string>) {
282285
if (semver.lt(wineVersion, "1.8.0")) {
283286
throw new Error(wineError(`wine 1.8+ is required, but your version is ${wineVersion}`))
284287
}
288+
}
289+
290+
function checkDependencies(dependencies?: { [key: string]: string }) {
291+
if (dependencies == null) {
292+
return
293+
}
294+
295+
for (let name of ["electron", "electron-prebuilt", "electron-builder"]) {
296+
if (name in dependencies) {
297+
throw new Error(`${name} must be in the devDependencies`)
298+
}
299+
}
285300
}

src/platformPackager.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Packager } from "./packager"
88
import { AsarOptions } from "asar-electron-builder"
99
import { archiveApp } from "./targets/archive"
1010
import { Minimatch } from "minimatch"
11-
import { checkFileInPackage, createAsarArchive } from "./asarUtil"
11+
import { checkFileInArchive, createAsarArchive } from "./asarUtil"
1212
import { deepAssign } from "./util/deepAssign"
1313
import { warn, log, task } from "./util/log"
1414
import { AppInfo } from "./appInfo"
@@ -362,34 +362,34 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
362362
return path.join(appOutDir, `${this.appInfo.productFilename}.app`, "Contents", "Resources")
363363
}
364364

365-
private async checkFileInPackage(resourcesDir: string, file: string, isAsar: boolean) {
365+
private async checkFileInPackage(resourcesDir: string, file: string, messagePrefix: string, isAsar: boolean) {
366366
const relativeFile = path.relative(this.info.appDir, path.resolve(this.info.appDir, file))
367367
if (isAsar) {
368-
await checkFileInPackage(path.join(resourcesDir, "app.asar"), relativeFile)
368+
await checkFileInArchive(path.join(resourcesDir, "app.asar"), relativeFile, messagePrefix)
369369
}
370370
else {
371371
const outStat = await statOrNull(path.join(resourcesDir, "app", relativeFile))
372372
if (outStat == null) {
373-
throw new Error(`Application entry file "${relativeFile}" does not exist. Seems like a wrong configuration.`)
373+
throw new Error(`${messagePrefix} "${relativeFile}" does not exist. Seems like a wrong configuration.`)
374374
}
375375
else if (!outStat.isFile()) {
376-
throw new Error(`Application entry file "${relativeFile}" is not a file. Seems like a wrong configuration.`)
376+
throw new Error(`${messagePrefix} "${relativeFile}" is not a file. Seems like a wrong configuration.`)
377377
}
378378
}
379379
}
380380

381381
private async sanityCheckPackage(appOutDir: string, isAsar: boolean): Promise<any> {
382382
const outStat = await statOrNull(appOutDir)
383-
384383
if (outStat == null) {
385384
throw new Error(`Output directory "${appOutDir}" does not exist. Seems like a wrong configuration.`)
386385
}
387386
else if (!outStat.isDirectory()) {
388387
throw new Error(`Output directory "${appOutDir}" is not a directory. Seems like a wrong configuration.`)
389388
}
390389

391-
const mainFile = this.appInfo.metadata.main || "index.js"
392-
await this.checkFileInPackage(this.getResourcesDir(appOutDir), mainFile, isAsar)
390+
const resourcesDir = this.getResourcesDir(appOutDir)
391+
await this.checkFileInPackage(resourcesDir, this.appInfo.metadata.main || "index.js", "Application entry file", isAsar)
392+
await this.checkFileInPackage(resourcesDir, "package.json", "Application", isAsar)
393393
}
394394

395395
protected async archiveApp(format: string, appOutDir: string, outFile: string): Promise<any> {

src/util/util.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,9 @@ export async function computeDefaultAppDirectory(projectDir: string, userAppDir:
204204
else if (!stat.isDirectory()) {
205205
throw new Error(`Application directory ${userAppDir} is not a directory`)
206206
}
207+
else if (projectDir === absolutePath) {
208+
warn(`Specified application directory "${userAppDir}" equals to project dir — superfluous or wrong configuration`)
209+
}
207210
return absolutePath
208211
}
209212

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

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

244247
export function isEmptyOrSpaces(s: string | n) {

0 commit comments

Comments
 (0)