Skip to content

Commit ea5f842

Browse files
demetris-manikasdevelar
authored andcommitted
feat: accept multiple default app dirs
www checked in addition to app. Closes #344
1 parent 9b043d6 commit ea5f842

File tree

13 files changed

+170
-69
lines changed

13 files changed

+170
-69
lines changed

docs/Options.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,5 +97,6 @@ See all [windows-installer options](https://github.com/electron/windows-installe
9797
| --- | ---
9898
| buildResources | <a name="MetadataDirectories-buildResources"></a>The path to build resources, default `build`.
9999
| output | <a name="MetadataDirectories-output"></a>The output directory, default `dist`.
100+
| app | <a name="MetadataDirectories-app"></a>The application directory (containing the application package.json), default `app`, `www` or working directory.
100101

101102
<!-- end of generated block -->

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"dependencies": {
5757
"7zip-bin": "^0.0.4",
5858
"bluebird": "^3.3.5",
59+
"chalk": "^1.1.3",
5960
"command-line-args": "^2.1.6",
6061
"deep-assign": "^2.0.0",
6162
"electron-packager": "^7.0.0",

src/build-cli.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
import { PackagerOptions } from "./platformPackager"
44
import { build } from "./builder"
55
import { PublishOptions } from "./gitHubPublisher"
6-
import { commonArgs } from "./util"
76
import { printErrorAndExit } from "./promise"
87
import cla = require("command-line-args")
98
import { readFileSync } from "fs"
109
import * as path from "path"
10+
import { warn } from "./util"
1111

1212
//noinspection JSUnusedLocalSymbols
1313
const __awaiter = require("./awaiter")
@@ -16,26 +16,33 @@ interface CliOptions extends PackagerOptions, PublishOptions {
1616
help: boolean
1717
}
1818

19-
const cli = cla(commonArgs.concat(
19+
const cli = cla([
2020
{name: "dist", type: Boolean, alias: "d", description: "Whether to package in a distributable format (e.g. DMG, windows installer, NuGet package)."},
2121
{name: "publish", type: String, alias: "p", description: "Publish artifacts (to GitHub Releases): onTag (on tag push only) or onTagOrDraft (on tag push or if draft release exists)."},
2222
{name: "platform", type: String, multiple: true, description: "darwin, linux, win32 or all. Current platform (" + process.platform + ") by default."},
2323
{name: "arch", type: String, description: "ia32, x64 or all. Defaults to architecture you're running on."},
2424
{name: "target", type: String, multiple: true, description: "Installer or package type."},
2525
{name: "sign", type: String},
26-
{name: "help", alias: "h", type: Boolean, description: "Display this usage guide."}
27-
))
26+
{name: "help", alias: "h", type: Boolean, description: "Display this usage guide."},
27+
{name: "appDir", type: String}
28+
])
2829

2930
const args: CliOptions = cli.parse()
3031

3132
if (args.help) {
3233
const version = process.env.npm_package_version || JSON.parse(readFileSync(path.join(__dirname, "..", "package.json"), "utf8")).version
3334
console.log(cli.getUsage({
3435
title: "electron-builder " + version,
35-
footer: "Project home: [underline]{https://github.com/electron-userland/electron-builder}"
36+
footer: "Project home: [underline]{https://github.com/electron-userland/electron-builder}",
37+
hide: ["appDir"],
3638
}))
3739
}
3840
else {
41+
if (args.appDir) {
42+
warn(`-appDir CLI parameter is deprecated, please configure build.directories.app instead
43+
See https://github.com/electron-userland/electron-builder/wiki/Options#MetadataDirectories-app`)
44+
}
45+
3946
build(args)
4047
.catch(printErrorAndExit)
4148
}

src/install-app-deps.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
11
#! /usr/bin/env node
22

3-
import { DEFAULT_APP_DIR_NAME, installDependencies, commonArgs, getElectronVersion, readPackageJson } from "./util"
3+
import { computeDefaultAppDirectory, installDependencies, getElectronVersion, readPackageJson, use } from "./util"
44
import { printErrorAndExit } from "./promise"
55
import * as path from "path"
66
import cla = require("command-line-args")
7+
import { Promise as BluebirdPromise } from "bluebird"
8+
import { DevMetadata } from "./metadata";
79

810
//noinspection JSUnusedLocalSymbols
911
const __awaiter = require("./awaiter")
1012

11-
const args = cla(commonArgs.concat({
12-
name: "arch",
13-
type: String,
14-
})).parse()
13+
const args = cla([{name: "arch", type: String}, {name: "appDir", type: String}]).parse()
1514

16-
const devPackageFile = path.join(process.cwd(), "package.json")
17-
const appDir = args.appDir || DEFAULT_APP_DIR_NAME
15+
const projectDir = process.cwd()
16+
const devPackageFile = path.join(projectDir, "package.json")
1817

19-
readPackageJson(devPackageFile)
20-
.then(async (it) => installDependencies(path.join(process.cwd(), appDir), await getElectronVersion(it, devPackageFile), args.arch))
21-
.catch(printErrorAndExit)
18+
async function main() {
19+
const devMetadata: DevMetadata = await readPackageJson(devPackageFile)
20+
const results: Array<string> = await BluebirdPromise.all([
21+
computeDefaultAppDirectory(projectDir, use(devMetadata.directories, it => it.app) || args.appDir),
22+
getElectronVersion(devMetadata, devPackageFile)
23+
])
24+
25+
await installDependencies(results[0], results[1], args.arch)
26+
}
27+
28+
try {
29+
main()
30+
}
31+
catch (e) {
32+
printErrorAndExit(e)
33+
}

src/linuxPackager.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import * as path from "path"
22
import { Promise as BluebirdPromise } from "bluebird"
3-
import { PlatformPackager, BuildInfo, use } from "./platformPackager"
3+
import { PlatformPackager, BuildInfo } from "./platformPackager"
44
import { Platform, LinuxBuildOptions } from "./metadata"
55
import { dir as _tpmDir, TmpOptions } from "tmp"
6-
import { exec, log } from "./util"
6+
import { exec, log, use } from "./util"
77
import { outputFile, readFile, readdir } from "fs-extra-p"
88
const template = require("lodash.template")
99

@@ -107,6 +107,9 @@ Icon=${this.metadata.name}
107107
}
108108

109109
const promises: Array<Promise<any>> = [resize(24), resize(96)]
110+
if (!output.includes("is32")) {
111+
promises.push(resize(16))
112+
}
110113
if (!output.includes("ih32")) {
111114
promises.push(resize(48))
112115
}

src/metadata.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,11 @@ export interface MetadataDirectories {
233233
The output directory, default `dist`.
234234
*/
235235
readonly output?: string
236+
237+
/*
238+
The application directory (containing the application package.json), default `app`, `www` or working directory.
239+
*/
240+
readonly app?: string
236241
}
237242

238243
export interface PlatformSpecificBuildOptions {

src/packager.ts

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { accessSync } from "fs"
21
import * as path from "path"
3-
import { DEFAULT_APP_DIR_NAME, installDependencies, log, getElectronVersion, readPackageJson } from "./util"
2+
import { computeDefaultAppDirectory, installDependencies, log, getElectronVersion, readPackageJson, use, warn } from "./util"
43
import { all, executeFinally } from "./promise"
54
import { EventEmitter } from "events"
65
import { Promise as BluebirdPromise } from "bluebird"
76
import { InfoRetriever } from "./repositoryInfo"
87
import { AppMetadata, DevMetadata, Platform } from "./metadata"
9-
import { PackagerOptions, PlatformPackager, BuildInfo, ArtifactCreated, use } from "./platformPackager"
8+
import { PackagerOptions, PlatformPackager, BuildInfo, ArtifactCreated } from "./platformPackager"
109
import MacPackager from "./macPackager"
1110
import { WinPackager } from "./winPackager"
1211
import * as errorMessages from "./errorMessages"
@@ -22,7 +21,7 @@ function addHandler(emitter: EventEmitter, event: string, handler: Function) {
2221

2322
export class Packager implements BuildInfo {
2423
readonly projectDir: string
25-
readonly appDir: string
24+
appDir: string
2625

2726
metadata: AppMetadata
2827
devMetadata: DevMetadata
@@ -36,7 +35,9 @@ export class Packager implements BuildInfo {
3635
//noinspection JSUnusedGlobalSymbols
3736
constructor(public options: PackagerOptions, public repositoryInfo: InfoRetriever = null) {
3837
this.projectDir = options.projectDir == null ? process.cwd() : path.resolve(options.projectDir)
39-
this.appDir = this.computeAppDirectory()
38+
if (this.appDir === this.projectDir) {
39+
this.isTwoPackageJsonProjectLayoutUsed = false
40+
}
4041
}
4142

4243
artifactCreated(handler: (event: ArtifactCreated) => void): Packager {
@@ -50,12 +51,12 @@ export class Packager implements BuildInfo {
5051

5152
async build(): Promise<any> {
5253
const devPackageFile = this.devPackageFile
53-
const appPackageFile = this.projectDir === this.appDir ? devPackageFile : path.join(this.appDir, "package.json")
5454
const platforms = this.options.platform
5555

56-
const metadataList = await BluebirdPromise.map(Array.from(new Set([devPackageFile, appPackageFile])), readPackageJson)
57-
this.metadata = metadataList[metadataList.length - 1]
58-
this.devMetadata = deepAssign(metadataList[0], this.options.devMetadata)
56+
this.devMetadata = deepAssign(await readPackageJson(devPackageFile), this.options.devMetadata)
57+
this.appDir = await computeDefaultAppDirectory(this.projectDir, use(this.devMetadata.directories, it => it.app) || this.options.appDir)
58+
const appPackageFile = this.projectDir === this.appDir ? devPackageFile : path.join(this.appDir, "package.json")
59+
this.metadata = appPackageFile === devPackageFile ? this.devMetadata : await readPackageJson(appPackageFile)
5960
this.checkMetadata(appPackageFile, devPackageFile, platforms)
6061

6162
this.electronVersion = await getElectronVersion(this.devMetadata, devPackageFile)
@@ -110,31 +111,6 @@ export class Packager implements BuildInfo {
110111
}
111112
}
112113

113-
// Auto-detect app/ (two package.json project layout (development and app)) or fallback to use working directory if not explicitly specified
114-
private computeAppDirectory(): string {
115-
let customAppPath = this.options.appDir
116-
let required = true
117-
if (customAppPath == null) {
118-
customAppPath = DEFAULT_APP_DIR_NAME
119-
required = false
120-
}
121-
122-
const absoluteAppPath = path.join(this.projectDir, customAppPath)
123-
try {
124-
accessSync(absoluteAppPath)
125-
}
126-
catch (e) {
127-
if (required) {
128-
throw new Error(customAppPath + " doesn't exists, " + e.message)
129-
}
130-
else {
131-
this.isTwoPackageJsonProjectLayoutUsed = false
132-
return this.projectDir
133-
}
134-
}
135-
return absoluteAppPath
136-
}
137-
138114
private checkMetadata(appPackageFile: string, devAppPackageFile: string, platforms: Array<Platform>): void {
139115
const reportError = (missedFieldName: string) => {
140116
throw new Error("Please specify '" + missedFieldName + "' in the application package.json ('" + appPackageFile + "')")
@@ -156,10 +132,10 @@ export class Packager implements BuildInfo {
156132
}
157133

158134
if (this.devMetadata.homepage != null) {
159-
console.warn("homepage in the development package.json is deprecated, please move to the application package.json")
135+
warn("homepage in the development package.json is deprecated, please move to the application package.json")
160136
}
161137
if (this.devMetadata.license != null) {
162-
console.warn("license in the development package.json is deprecated, please move to the application package.json")
138+
warn("license in the development package.json is deprecated, please move to the application package.json")
163139
}
164140
}
165141

src/platformPackager.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as path from "path"
66
import packager = require("electron-packager")
77
import globby = require("globby")
88
import { copy } from "fs-extra-p"
9-
import { statOrNull } from "./util"
9+
import { statOrNull, use } from "./util"
1010
import { Packager } from "./packager"
1111
import deepAssign = require("deep-assign")
1212

@@ -26,6 +26,7 @@ export interface PackagerOptions {
2626
platform?: Array<Platform>
2727
target?: Array<string>
2828

29+
// deprecated
2930
appDir?: string
3031

3132
projectDir?: string
@@ -147,7 +148,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
147148
throw new Error(`Output directory ${appOutDir} does not exists. Seems like a wrong configuration.`)
148149
}
149150
else if (!outStat.isDirectory()) {
150-
throw new Error(`Output directory ${appOutDir} is a file. Seems like a wrong configuration.`)
151+
throw new Error(`Output directory ${appOutDir} is not a directory. Seems like a wrong configuration.`)
151152
}
152153
}
153154

@@ -213,8 +214,4 @@ export interface ArtifactCreated {
213214
readonly artifactName?: string
214215

215216
readonly platform: Platform
216-
}
217-
218-
export function use<T, R>(value: T, task: (it: T) => R): R {
219-
return value == null ? null : task(value)
220217
}

src/util.ts

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,23 @@ import readPackageJsonAsync = require("read-package-json")
44
import * as os from "os"
55
import * as path from "path"
66
import { readJson, stat } from "fs-extra-p"
7+
import { yellow } from "chalk"
78

89
//noinspection JSUnusedLocalSymbols
910
const __awaiter = require("./awaiter")
1011

1112
export const log = console.log
1213

13-
export const DEFAULT_APP_DIR_NAME = "app"
14+
export function warn(message: string) {
15+
console.warn(yellow(message))
16+
}
1417

15-
export const commonArgs: any[] = [{
16-
name: "appDir",
17-
type: String,
18-
description: "Relative (to the working directory) path to the folder containing the application package.json. Working directory or app/ by default."
19-
}]
18+
const DEFAULT_APP_DIR_NAMES = ["app", "www"]
2019

2120
export const readPackageJson = BluebirdPromise.promisify(readPackageJsonAsync)
2221

2322
export function installDependencies(appDir: string, electronVersion: string, arch: string = process.arch, command: string = "install"): BluebirdPromise<any> {
24-
log("Installing app dependencies for arch %s to %s", arch, appDir)
23+
log((command === "install" ? "Installing" : "Rebuilding") + " app dependencies for arch %s to %s", arch, appDir)
2524
const gypHome = path.join(os.homedir(), ".electron-gyp")
2625
const env = Object.assign({}, process.env, {
2726
npm_config_disturl: "https://atom.io/download/atom-shell",
@@ -102,7 +101,7 @@ export async function getElectronVersion(packageData: any, packageJsonPath: stri
102101
}
103102
catch (e) {
104103
if (e.code !== "ENOENT") {
105-
console.warn("Cannot read electron version from electron-prebuilt package.json" + e.message)
104+
warn("Cannot read electron version from electron-prebuilt package.json" + e.message)
106105
}
107106
}
108107

@@ -133,4 +132,31 @@ export async function statOrNull(file: string) {
133132
throw e
134133
}
135134
}
135+
}
136+
137+
export async function computeDefaultAppDirectory(projectDir: string, userAppDir: string): Promise<string> {
138+
if (userAppDir != null) {
139+
const absolutePath = path.join(projectDir, userAppDir)
140+
const stat = await statOrNull(absolutePath)
141+
if (stat == null) {
142+
throw new Error(`Application directory ${userAppDir} doesn't exists`)
143+
}
144+
else if (!stat.isDirectory()) {
145+
throw new Error(`Application directory ${userAppDir} is not a directory`)
146+
}
147+
return absolutePath
148+
}
149+
150+
for (let dir of DEFAULT_APP_DIR_NAMES) {
151+
const absolutePath = path.join(projectDir, dir)
152+
const stat = await statOrNull(absolutePath)
153+
if (stat != null && stat.isDirectory()) {
154+
return absolutePath
155+
}
156+
}
157+
return projectDir
158+
}
159+
160+
export function use<T, R>(value: T, task: (it: T) => R): R {
161+
return value == null ? null : task(value)
136162
}

src/winPackager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { downloadCertificate } from "./codeSign"
22
import { Promise as BluebirdPromise } from "bluebird"
3-
import { PlatformPackager, BuildInfo, use } from "./platformPackager"
3+
import { PlatformPackager, BuildInfo } from "./platformPackager"
44
import { Platform, WinBuildOptions } from "./metadata"
55
import * as path from "path"
6-
import { log, statOrNull } from "./util"
6+
import { log, statOrNull, use } from "./util"
77
import { readFile, deleteFile, stat, rename, copy, emptyDir, writeFile, open, close, read } from "fs-extra-p"
88
import { sign } from "signcode"
99

0 commit comments

Comments
 (0)