diff --git a/index.js b/index.js index fa7724d8116..d2588334197 100644 --- a/index.js +++ b/index.js @@ -10,7 +10,7 @@ var platforms = require( './lib/platforms' ); var path = require( 'path' ); var fs = require( 'fs' ); -var mkdirp = require( 'mkdirp' ); +var fse = require( 'fs-extra' ); /** @@ -45,7 +45,7 @@ var Builder = { // directory exists if ( !fs.existsSync( options.out ) ) { options.log( '- Ouput directory ´' + options.out + '´ does not exist ' ); - mkdirp.sync( options.out ); + fse.mkdirsSync( options.out ); options.log( '- Created ´' + options.out + '´ ' ); } diff --git a/package.json b/package.json index bf5c1bf98dc..a3ec5e54c41 100644 --- a/package.json +++ b/package.json @@ -57,12 +57,10 @@ "fs-extra": "^0.26.5", "gm": "^1.21.1", "hosted-git-info": "^2.1.4", - "json-parse-helpfulerror": "^1.0.3", "lodash.camelcase": "^4.1.0", "lodash.template": "^4.2.0", "meow": "^3.7.0", "mime": "^1.3.4", - "mkdirp": "^0.5.1", "progress": "^1.1.8", "progress-stream": "^1.2.0", "rimraf": "^2.5.1", @@ -77,11 +75,12 @@ "babel-plugin-array-includes": "^2.0.3", "babel-plugin-transform-es2015-parameters": "^6.5.0", "dts-generator-tf": "^1.7.0-beta.0", - "eslint": "^2.1.0", + "eslint": "^2.2.0", "path-sort": "^0.1.0", "plist": "^1.2.0", "proxyquire": "^1.7.4", "publish-please": "^1.1.0", + "read-package-json": "^2.0.3", "rimraf": "^2.5.2", "should": "^8.2.2", "tap-nyan": "0.0.2", @@ -89,8 +88,8 @@ "tape": "^4.4.0", "ts-babel": "^0.3.0", "tsconfig-glob": "^0.4.1", - "tslint": "^3.3.0", - "typescript": "^1.8.0-beta" + "tslint": "^3.4.0", + "typescript": "^1.8.2" }, "babel": { "plugins": [ diff --git a/src/errorMessages.ts b/src/errorMessages.ts index dc2f2145d5d..cdb265edbd6 100644 --- a/src/errorMessages.ts +++ b/src/errorMessages.ts @@ -8,4 +8,12 @@ export const buildIsMissed = `Please specify 'build' configuration in the applic } is required. +` + +export const authorEmailIsMissed = `Please specify author 'email' in the application package.json ('%s') + +See https://docs.npmjs.com/files/package.json#people-fields-author-contributors + +It is required to set Linux .deb package maintainer. Or you can set maintainer in the custom linux options. +(see https://github.com/loopline-systems/electron-builder#distributable-format-configuration). ` \ No newline at end of file diff --git a/src/install-app-deps.ts b/src/install-app-deps.ts index 46f527ef108..05363947799 100644 --- a/src/install-app-deps.ts +++ b/src/install-app-deps.ts @@ -1,9 +1,7 @@ #! /usr/bin/env node -import { DEFAULT_APP_DIR_NAME, installDependencies, commonArgs, getElectronVersion } from "./util" -import { parseJson } from "./promisifed-fs" +import { DEFAULT_APP_DIR_NAME, installDependencies, commonArgs, getElectronVersion, readPackageJson } from "./util" import { printErrorAndExit } from "./promise" -import { readFileSync } from "fs" import * as path from "path" import cla = require("command-line-args") @@ -13,7 +11,8 @@ const args = cla(commonArgs.concat({ })).parse() const devPackageFile = path.join(process.cwd(), "package.json") - const appDir = args.appDir || DEFAULT_APP_DIR_NAME -installDependencies(path.join(process.cwd(), appDir), args.arch, getElectronVersion(parseJson(readFileSync(devPackageFile, "utf8"), devPackageFile), devPackageFile)) + +readPackageJson(devPackageFile) + .then(it => installDependencies(path.join(process.cwd(), appDir), args.arch, getElectronVersion(it, devPackageFile))) .catch(printErrorAndExit) \ No newline at end of file diff --git a/src/linuxPackager.ts b/src/linuxPackager.ts index 1df823ad9f4..cfcd15c76b7 100644 --- a/src/linuxPackager.ts +++ b/src/linuxPackager.ts @@ -68,7 +68,7 @@ export class LinuxPackager extends PlatformPackager { version: this.metadata.version, title: this.metadata.name, comment: this.metadata.description, - maintainer: this.metadata.author, + maintainer: `${this.metadata.author.name} <${this.metadata.author.email}>`, arch: this.currentArch === "ia32" ? 32 : 64, target: "deb", executable: this.metadata.name, diff --git a/src/macPackager.ts b/src/macPackager.ts index 128e7c84d07..2231939538d 100644 --- a/src/macPackager.ts +++ b/src/macPackager.ts @@ -50,7 +50,7 @@ export default class MacPackager extends PlatformPackager } packageInDistributableFormat(outDir: string, appOutDir: string): Promise { - const artifactPath = path.join(outDir, this.metadata.name + "-" + this.metadata.version + ".dmg") + const artifactPath = path.join(appOutDir, this.metadata.name + "-" + this.metadata.version + ".dmg") return BluebirdPromise.all([ new BluebirdPromise((resolve, reject) => { log("Creating DMG") @@ -80,8 +80,7 @@ export default class MacPackager extends PlatformPackager specification.contents[1].path = path.join(appOutDir, this.metadata.name + ".app") - const appDmg = require("appdmg") - const emitter = appDmg({ + const emitter = require("appdmg")({ target: artifactPath, basepath: this.projectDir, specification: specification diff --git a/src/packager.ts b/src/packager.ts index 58be17be730..ec6caafedcd 100644 --- a/src/packager.ts +++ b/src/packager.ts @@ -1,7 +1,6 @@ import * as fs from "fs" import * as path from "path" -import { DEFAULT_APP_DIR_NAME, installDependencies, log, getElectronVersion } from "./util" -import { parseJsonFile } from "./promisifed-fs" +import { DEFAULT_APP_DIR_NAME, installDependencies, log, getElectronVersion, readPackageJson } from "./util" import { all, executeFinally } from "./promise" import { EventEmitter } from "events" import { Promise as BluebirdPromise } from "bluebird" @@ -52,22 +51,23 @@ export class Packager implements BuildInfo { async build(): Promise { const buildPackageFile = this.devPackageFile const appPackageFile = this.projectDir === this.appDir ? buildPackageFile : path.join(this.appDir, "package.json") - await BluebirdPromise.all(Array.from(new Set([buildPackageFile, appPackageFile]), parseJsonFile)) - .then((result: any[]) => { + const platforms = normalizePlatforms(this.options.platform) + await BluebirdPromise.all(Array.from(new Set([buildPackageFile, appPackageFile]), readPackageJson)) + .then(result => { this.metadata = result[result.length - 1] this.devMetadata = result[0] - this.checkMetadata(appPackageFile) + this.checkMetadata(appPackageFile, platforms) this.electronVersion = getElectronVersion(this.devMetadata, buildPackageFile) }) const cleanupTasks: Array<() => Promise> = [] - return executeFinally(this.doBuild(cleanupTasks), error => all(cleanupTasks.map(it => it()))) + return executeFinally(this.doBuild(platforms, cleanupTasks), error => all(cleanupTasks.map(it => it()))) } - private async doBuild(cleanupTasks: Array<() => Promise>): Promise { + private async doBuild(platforms: Array, cleanupTasks: Array<() => Promise>): Promise { const distTasks: Array> = [] - for (let platform of normalizePlatforms(this.options.platform)) { + for (let platform of platforms) { const helper = this.createHelper(platform, cleanupTasks) const archs = platform === "darwin" ? ["x64"] : (this.options.arch == null || this.options.arch === "all" ? ["ia32", "x64"] : [this.options.arch]) for (let arch of archs) { @@ -136,7 +136,7 @@ export class Packager implements BuildInfo { return absoluteAppPath } - private checkMetadata(appPackageFile: string): void { + private checkMetadata(appPackageFile: string, platforms: Array): void { const reportError = (missedFieldName: string) => { throw new Error("Please specify '" + missedFieldName + "' in the application package.json ('" + appPackageFile + "')") } @@ -154,8 +154,14 @@ export class Packager implements BuildInfo { else if (metadata.build == null) { throw new Error(util.format(errorMessages.buildIsMissed, appPackageFile)) } - else if (metadata.author == null) { - reportError("author") + else { + const author = metadata.author + if (author == null) { + reportError("author") + } + else if (this.options.dist && author.email == null && platforms.includes("linux")) { + throw new Error(util.format(errorMessages.authorEmailIsMissed, appPackageFile)) + } } } diff --git a/src/platformPackager.ts b/src/platformPackager.ts index 4df0b31a0b5..5186c71d1a7 100644 --- a/src/platformPackager.ts +++ b/src/platformPackager.ts @@ -104,7 +104,7 @@ export abstract class PlatformPackager implements ProjectMetadataProvider { "app-version": version, "build-version": buildVersion, "version-string": { - CompanyName: this.metadata.author, + CompanyName: this.metadata.author.name, FileDescription: this.metadata.description, ProductVersion: version, FileVersion: buildVersion, diff --git a/src/promisifed-fs.ts b/src/promisifed-fs.ts index 0f488c36d56..f1212ba1ef2 100644 --- a/src/promisifed-fs.ts +++ b/src/promisifed-fs.ts @@ -1,54 +1,18 @@ import * as fs from "fs" -import { parse as _parseJson } from "json-parse-helpfulerror" import { Promise as BluebirdPromise } from "bluebird" -import rimraf = require("rimraf") const readFileAsync: ((filename: string, encoding?: string) => Promise) = BluebirdPromise.promisify(fs.readFile) -const writeFileAsync = BluebirdPromise.promisify(fs.writeFile) export function readText(file: string): BluebirdPromise { return >readFileAsync(file, "utf8") } -export function readBytes(file: string): BluebirdPromise { - return >readFileAsync(file) -} - -export function writeFile(path: string, data: string | Buffer): BluebirdPromise { - return writeFileAsync(path, data) -} - -export function parseJsonFile(file: string): BluebirdPromise { - return readText(file). - then(it => parseJson(it, file)) -} - -export function parseJson(data: string, path: string): any { - try { - return _parseJson(data) - } - catch (e) { - if (e instanceof SyntaxError) { - throw new Error("Cannot parse '" + path + "': " + e.message) - } - else { - throw e - } - } -} - export function deleteFile(path: string, ignoreIfNotExists: boolean = false): BluebirdPromise { return new BluebirdPromise((resolve, reject) => { fs.unlink(path, it => it == null || (ignoreIfNotExists && it.code === "ENOENT") ? resolve(null) : reject(it)) }) } -export function deleteDirectory(path: string) { - return new BluebirdPromise((resolve, reject) => { - rimraf(path, {glob: false}, error => error == null ? resolve(null) : reject(error)) - }) -} - // returns new name export function renameFile(oldPath: string, newPath: string): BluebirdPromise { return new BluebirdPromise((resolve, reject) => { diff --git a/src/repositoryInfo.ts b/src/repositoryInfo.ts index 97e9c478089..dac2535f32d 100644 --- a/src/repositoryInfo.ts +++ b/src/repositoryInfo.ts @@ -14,11 +14,16 @@ export interface Metadata { repository: string | RepositoryInfo } +export interface MetadataAuthor { + name: string + email: string +} + export interface AppMetadata extends Metadata { version: string name: string description: string - author: string + author: MetadataAuthor build: BuildMetadata diff --git a/src/util.ts b/src/util.ts index 9d385166abc..546300b68bb 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,6 +1,7 @@ import { execFile, spawn as _spawn } from "child_process" import { Promise as BluebirdPromise } from "bluebird" import "source-map-support/register" +import readPackageJsonAsync = require("read-package-json") export const log = console.log @@ -18,6 +19,7 @@ export const commonArgs: any[] = [{ }] const execFileAsync: (file: string, args?: string[], options?: ExecOptions) => BluebirdPromise = (BluebirdPromise.promisify(execFile, {multiArgs: true})) +export const readPackageJson = BluebirdPromise.promisify(readPackageJsonAsync) export function installDependencies(appDir: string, arch: string, electronVersion: string): BluebirdPromise { log("Installing app dependencies for arch %s to %s", arch || process.arch, appDir) diff --git a/test/BuildTest.js b/test/BuildTest.js index 04c2e952167..8a3bbaf2c50 100644 --- a/test/BuildTest.js +++ b/test/BuildTest.js @@ -7,7 +7,7 @@ import * as path from "path" import { parse as parsePlist } from "plist" import { Packager } from "../out/packager" import { exec } from "../out/util" -import { deleteDirectory, readText } from "../out/promisifed-fs" +import { readText } from "../out/promisifed-fs" import { CSC_LINK, CSC_KEY_PASSWORD } from "./helpers/codeSignData" import pathSorter from "path-sort" @@ -136,6 +136,10 @@ if (process.platform !== "win32") { test("linux", async function () { await assertPack("test-app-one", "linux") }) + + test("no-author-email", async (t) => { + t.throws(assertPack("test-app-no-author-email", "linux"), /Please specify author 'email' in .*/) + }) } if (!process.env.TRAVIS) { @@ -145,4 +149,4 @@ if (!process.env.TRAVIS) { test("win: nsis", async function () { await assertPack("test-app-one", "win32", ["nsis"], true) }) -} +} \ No newline at end of file diff --git a/test/fixtures/test-app-no-author-email/package.json b/test/fixtures/test-app-no-author-email/package.json new file mode 100644 index 00000000000..cb88b903213 --- /dev/null +++ b/test/fixtures/test-app-no-author-email/package.json @@ -0,0 +1,15 @@ +{ + "private": true, + "name": "TestApp", + "version": "1.0.0", + "description": "Test Application", + "author": "Foo Bar", + "devDependencies": { + "electron-prebuilt": "^0.36.7" + }, + "build": { + "app-bundle-id": "your.id", + "app-category-type": "your.app.category.type", + "iconUrl": "https://raw.githubusercontent.com/szwacz/electron-boilerplate/master/resources/windows/icon.ico" + } +} diff --git a/test/fixtures/test-app-one/package.json b/test/fixtures/test-app-one/package.json index c19b9ca22d9..5f30e795a1b 100644 --- a/test/fixtures/test-app-one/package.json +++ b/test/fixtures/test-app-one/package.json @@ -6,7 +6,7 @@ "scripts": { "start": "electron ." }, - "author": "Foo Bar", + "author": "Foo Bar ", "devDependencies": { "electron-prebuilt": "^0.36.7" }, diff --git a/tsconfig.json b/tsconfig.json index 6a9a0ab4c4a..8b67189c1be 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,7 +31,6 @@ "typings/electron-packager.d.ts", "typings/gh-api.d.ts", "typings/hosted-git-info.d.ts", - "typings/json-parse-helpfulerror.d.ts", "typings/main/ambient/fs-extra/fs-extra.d.ts", "typings/main/ambient/gm/gm.d.ts", "typings/main/ambient/mime/mime.d.ts", @@ -41,6 +40,7 @@ "typings/main/definitions/source-map-support/source-map-support.d.ts", "typings/node.d.ts", "typings/progress-stream.d.ts", + "typings/read-package-json.d.ts", "typings/rimraf.d.ts", "node_modules/typescript/lib/lib.es7.d.ts", "src/awaiter.ts", diff --git a/typings/json-parse-helpfulerror.d.ts b/typings/json-parse-helpfulerror.d.ts deleted file mode 100644 index 814303a6818..00000000000 --- a/typings/json-parse-helpfulerror.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -declare module "json-parse-helpfulerror" { - function parse(data: string): any -} \ No newline at end of file diff --git a/typings/read-package-json.d.ts b/typings/read-package-json.d.ts new file mode 100644 index 00000000000..a8cee7c282d --- /dev/null +++ b/typings/read-package-json.d.ts @@ -0,0 +1,5 @@ +declare module "read-package-json" { + function readJson(file: string, callback: (error: Error, data: any) => void): void + + export = readJson +} \ No newline at end of file