Skip to content

Commit

Permalink
feat: if build/install-spinner.gif exists, set loadingGif to it
Browse files Browse the repository at this point in the history
Closes #292
  • Loading branch information
develar committed Apr 10, 2016
1 parent 1ef6555 commit 85a6fba
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 69 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
*.ico filter=lfs diff=lfs merge=lfs -text
*.icns filter=lfs diff=lfs merge=lfs -text
vendor/**/* filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ See [options](https://github.com/electron-userland/electron-builder/wiki/Options
You need to deploy somewhere releases/downloads server.
Consider to use [Nuts](https://github.com/GitbookIO/nuts) (GitHub as a backend to store assets) or [Electron Release Server](https://github.com/ArekSredzki/electron-release-server).

# Code signing
# Code Signing
OS X and Windows code singing is supported.
On a development machine set environment variable `CSC_NAME` to your identity (recommended). Or pass `--sign` parameter.
```
Expand All @@ -106,12 +106,12 @@ travis encrypt 'CSC_KEY_PASSWORD=beAwareAboutBashEscaping!!!' --add
# Build Version Management
`CFBundleVersion` (OS X) and `FileVersion` (Windows) will be set automatically to `version`.`build_number` on CI server (Travis, AppVeyor and CircleCI supported).
# CLI usage
# CLI Usage
Execute `node_modules/.bin/build --help` to get actual CLI usage guide.
In most cases you should not explicitly pass flags, so, we don't want to promote it here ([npm lifecycle](https://docs.npmjs.com/misc/scripts#current-lifecycle-event) is supported and script name is taken in account).
Want more — please file issue.
# Programmatic usage
# Programmatic Usage
See `node_modules/electron-builder/out/electron-builder.d.ts`. [Typings](https://github.com/Microsoft/TypeScript/wiki/Typings-for-npm-packages) is supported.
[npm-url]: https://npmjs.org/package/electron-builder
Expand Down
3 changes: 1 addition & 2 deletions docs/Multi Platform Build.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ To build app in distributable format for Windows on Linux:
```
sudo add-apt-repository ppa:ubuntu-wine/ppa
sudo apt-get update
sudo apt-get install wine1.8 winetricks
winetricks -q vcrun2013
sudo apt-get install wine1.8
```

* Install [Mono](http://www.mono-project.com/docs/getting-started/install/linux/#usage):
Expand Down
12 changes: 11 additions & 1 deletion docs/Options.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Here documented only `electron-builder` specific options:
| 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 directory (<code>Contents/Resources</code> for OS X).</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>
| osx | <a name="BuildMetadata-osx"></a>See [.build.osx](#OsXBuildOptions).
| win | <a name="BuildMetadata-win"></a>See [windows-installer options](https://github.com/electronjs/windows-installer#usage).
| win | <a name="BuildMetadata-win"></a>See [.build.win](#LinuxBuildOptions).
| linux | <a name="BuildMetadata-linux"></a>See [.build.linux](#LinuxBuildOptions).
| compression | <a name="BuildMetadata-compression"></a>The compression level, one of `store`, `normal`, `maximum` (default: `normal`). If you want to rapidly test build, `store` can reduce build time significantly.

Expand All @@ -69,6 +69,16 @@ See all [appdmg options](https://www.npmjs.com/package/appdmg#json-specification
| icon | <a name="OsXBuildOptions-icon"></a>The path to icon, which will be shown when mounted (default: `build/icon.icns`).
| background | <a name="OsXBuildOptions-background"></a>The path to background (default: `build/background.png`).

<a name="WinBuildOptions"></a>
### `.build.win`

See all [windows-installer options](https://github.com/electron/windows-installer#usage).

| Name | Description
| --- | ---
| loadingGif | <a name="WinBuildOptions-loadingGif"></a><p>The path to a .gif file to display during install. <code>build/install-spinner.gif</code> will be used if exists (otherwise [default](https://github.com/electron/windows-installer/blob/master/resources/install-spinner.gif)).</p>
| noMsi | <a name="WinBuildOptions-noMsi"></a>Whether to create an MSI installer. Defaults to `true` (MSI is not created).

<a name="LinuxBuildOptions"></a>
### `.build.linux`
| Name | Description
Expand Down
11 changes: 5 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
"pretest": "npm run compile && npm run lint",
"test": "node ./test/out/helpers/runTests.js",
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
"validate-commit-msg": "validate-commit-msg"
"validate-commit-msg": "validate-commit-msg",
"//": "Update wiki if docs changed. Update only if functionalily are generally available (latest release, not next)",
"update-wiki": "git subtree split -b wiki --prefix docs/ && git push https://github.com/electron-userland/electron-builder.wiki.git wiki:master"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -54,7 +56,7 @@
"dependencies": {
"bluebird": "^3.3.4",
"command-line-args": "^2.1.6",
"electron-packager": "^6.0.1",
"electron-packager-tf": "^6.0.3-beta.0",
"electron-winstaller-fixed": "^2.0.6-beta.8",
"fs-extra": "^0.26.7",
"fs-extra-p": "^0.2.0",
Expand Down Expand Up @@ -109,8 +111,5 @@
"typings": "./out/electron-builder.d.ts",
"precommit": [
"validate-commit-msg"
],
"publishConfig": {
"tag": "next"
}
]
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { Packager } from "./packager"
export { PackagerOptions, ArtifactCreated } from "./platformPackager"
export { BuildOptions, build, createPublisher } from "./builder"
export { AppMetadata, DevMetadata, Platform, getProductName, BuildMetadata, OsXBuildOptions, LinuxBuildOptions } from "./metadata"
export { AppMetadata, DevMetadata, Platform, getProductName, BuildMetadata, OsXBuildOptions, WinBuildOptions, LinuxBuildOptions } from "./metadata"
26 changes: 25 additions & 1 deletion src/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export interface BuildMetadata {
readonly osx?: OsXBuildOptions

/**
See [windows-installer options](https://github.com/electronjs/windows-installer#usage).
See [.build.win](#LinuxBuildOptions).
*/
readonly win?: any,

Expand Down Expand Up @@ -141,6 +141,30 @@ export interface OsXBuildOptions extends PlatformSpecificBuildOptions {
background?: string
}

/*
### `.build.win`
See all [windows-installer options](https://github.com/electron/windows-installer#usage).
*/
export interface WinBuildOptions extends PlatformSpecificBuildOptions {
readonly certificateFile?: string
readonly certificatePassword?: string

readonly icon?: string
readonly iconUrl?: string

/*
The path to a .gif file to display during install. `build/install-spinner.gif` will be used if exists
(otherwise [default](https://github.com/electron/windows-installer/blob/master/resources/install-spinner.gif)).
*/
readonly loadingGif?: string

/**
Whether to create an MSI installer. Defaults to `true` (MSI is not created).
*/
readonly noMsi?: boolean
}

/*
### `.build.linux`
*/
Expand Down
8 changes: 6 additions & 2 deletions src/packager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { InfoRetriever } from "./repositoryInfo"
import { AppMetadata, DevMetadata } from "./metadata"
import { PackagerOptions, PlatformPackager, BuildInfo, ArtifactCreated, use } from "./platformPackager"
import MacPackager from "./macPackager"
import WinPackager from "./winPackager"
import { WinPackager } from "./winPackager"
import * as errorMessages from "./errorMessages"
import * as util from "util"

Expand Down Expand Up @@ -84,6 +84,10 @@ export class Packager implements BuildInfo {
}

private createHelper(platform: string, cleanupTasks: Array<() => Promise<any>>): PlatformPackager<any> {
if (this.options.platformPackagerFactory != null) {
return this.options.platformPackagerFactory(this, platform, cleanupTasks)
}

switch (platform) {
case "darwin":
case "osx":
Expand All @@ -96,7 +100,7 @@ export class Packager implements BuildInfo {
case "win":
case "windows":
{
const helperClass: typeof WinPackager = require("./winPackager").default
const helperClass: typeof WinPackager = require("./winPackager").WinPackager
return new helperClass(this, cleanupTasks)
}

Expand Down
7 changes: 5 additions & 2 deletions src/platformPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { AppMetadata, DevMetadata, Platform, PlatformSpecificBuildOptions, getPr
import EventEmitter = NodeJS.EventEmitter
import { Promise as BluebirdPromise } from "bluebird"
import * as path from "path"
import packager = require("electron-packager")
import packager = require("electron-packager-tf")
import globby = require("globby")
import { copy } from "fs-extra-p"
import { Packager } from "./packager";

//noinspection JSUnusedLocalSymbols
const __awaiter = require("./awaiter")
Expand All @@ -30,6 +31,8 @@ export interface PackagerOptions {
cscLink?: string
csaLink?: string
cscKeyPassword?: string

platformPackagerFactory?: (packager: Packager, platform: string, cleanupTasks: Array<() => Promise<any>>) => PlatformPackager<any>
}

export interface BuildInfo extends ProjectMetadataProvider {
Expand Down Expand Up @@ -182,7 +185,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
}
}

function checkConflictingOptions(options: any): void {
function checkConflictingOptions(options: any) {
for (let name of ["all", "out", "tmpdir", "version", "platform", "dir", "arch"]) {
if (name in options) {
throw new Error(`Option ${name} is ignored, do not specify it.`)
Expand Down
97 changes: 57 additions & 40 deletions src/winPackager.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,21 @@
import { downloadCertificate } from "./codeSign"
import { Promise as BluebirdPromise } from "bluebird"
import { PlatformPackager, BuildInfo } from "./platformPackager"
import { Platform, PlatformSpecificBuildOptions } from "./metadata"
import { PlatformPackager, BuildInfo, use } from "./platformPackager"
import { Platform, WinBuildOptions } from "./metadata"
import * as path from "path"
import { log } from "./util"
import { readFile, deleteFile, stat, rename, copy, emptyDir, writeFile, open, close, read } from "fs-extra-p"

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

export interface WinBuildOptions extends PlatformSpecificBuildOptions {
readonly certificateFile?: string
readonly certificatePassword?: string

readonly icon?: string
readonly iconUrl?: string

/**
Whether to create an MSI installer. Defaults to `true` (MSI is not created).
*/
readonly noMsi?: boolean
}

export default class WinPackager extends PlatformPackager<WinBuildOptions> {
export class WinPackager extends PlatformPackager<WinBuildOptions> {
certFilePromise: Promise<string>

extraNuGetFileSources: Promise<Array<string>>

loadingGifStat: Promise<string>

readonly iconPath: Promise<string>

constructor(info: BuildInfo, cleanupTasks: Array<() => Promise<any>>) {
Expand All @@ -46,6 +35,20 @@ export default class WinPackager extends PlatformPackager<WinBuildOptions> {
}

this.iconPath = this.getValidIconPath()

if (this.options.dist && (this.customBuildOptions == null || this.customBuildOptions.loadingGif == null)) {
const installSpinnerPath = path.join(this.buildResourcesDir, "install-spinner.gif")
this.loadingGifStat = stat(installSpinnerPath)
.then(() => installSpinnerPath)
.catch(e => {
if (e.code === "ENOENT") {
return null
}
else {
throw e
}
})
}
}

protected get platform() {
Expand All @@ -63,7 +66,7 @@ export default class WinPackager extends PlatformPackager<WinBuildOptions> {
await this.iconPath

if (this.options.dist) {
const installerOut = WinPackager.computeDistOut(outDir, arch)
const installerOut = computeDistOut(outDir, arch)
log("Removing %s", installerOut)
await BluebirdPromise.all([
this.doPack(outDir, arch),
Expand All @@ -87,44 +90,35 @@ export default class WinPackager extends PlatformPackager<WinBuildOptions> {
}
}

private static computeDistOut(outDir: string, arch: string): string {
return path.join(outDir, "win" + (arch === "x64" ? "-x64" : ""))
}

async packageInDistributableFormat(outDir: string, appOutDir: string, arch: string): Promise<any> {
protected async computeEffectiveDistOptions(appOutDir: string, installerOutDir: string): Promise<any> {
let iconUrl = this.devMetadata.build.iconUrl
if (!iconUrl) {
if (this.customBuildOptions != null) {
iconUrl = this.customBuildOptions.iconUrl
}
use(this.customBuildOptions, it => iconUrl = it.iconUrl)

if (!iconUrl) {
if (this.info.repositoryInfo != null) {
const info = await this.info.repositoryInfo.getInfo(this)
if (info != null) {
iconUrl = `https://raw.githubusercontent.com/${info.user}/${info.project}/master/${this.relativeBuildResourcesDirname}/icon.ico`
}
}
use(this.info.repositoryInfo, async(it) =>
use(await it.getInfo(this), it =>
iconUrl = `https://raw.githubusercontent.com/${it.user}/${it.project}/master/${this.relativeBuildResourcesDirname}/icon.ico`))
}

if (!iconUrl) {
throw new Error("iconUrl is not specified, please see https://github.com/electron-userland/electron-builder#in-short")
}
if (!iconUrl) {
throw new Error("iconUrl is not specified, please see https://github.com/electron-userland/electron-builder#in-short")
}
}

const certificateFile = await this.certFilePromise
const version = this.metadata.version
const installerOutDir = WinPackager.computeDistOut(outDir, arch)
const archSuffix = arch === "x64" ? "" : ("-" + arch)
const projectUrl = await this.computePackageUrl()

const options = Object.assign({
use(this.customBuildOptions, checkConflictingOptions)

const options: any = Object.assign({
name: this.metadata.name,
productName: this.appName,
exe: this.appName + ".exe",
title: this.appName,
appDirectory: appOutDir,
outputDirectory: installerOutDir,
version: version,
version: this.metadata.version,
description: this.metadata.description,
authors: this.metadata.author.name,
iconUrl: iconUrl,
Expand All @@ -138,8 +132,19 @@ export default class WinPackager extends PlatformPackager<WinBuildOptions> {
extraMetadataSpecs: projectUrl == null ? null : `\n<projectUrl>${projectUrl}</projectUrl>`,
}, this.customBuildOptions)

await require("electron-winstaller-fixed").createWindowsInstaller(options)
if (this.loadingGifStat != null) {
options.loadingGif = await this.loadingGifStat
}

return options
}

async packageInDistributableFormat(outDir: string, appOutDir: string, arch: string): Promise<any> {
const installerOutDir = computeDistOut(outDir, arch)
await require("electron-winstaller-fixed").createWindowsInstaller(await this.computeEffectiveDistOptions(appOutDir, installerOutDir))

const version = this.metadata.version
const archSuffix = arch === "x64" ? "" : ("-" + arch)
const releasesFile = path.join(installerOutDir, "RELEASES")
const nupkgPathOriginal = this.metadata.name + "-" + version + "-full.nupkg"
const nupkgPathWithArch = this.metadata.name + "-" + version + archSuffix + "-full.nupkg"
Expand Down Expand Up @@ -217,4 +222,16 @@ function parseIco(buffer: Buffer): Array<Size> {

function isIco(buffer: Buffer): boolean {
return buffer.readUInt16LE(0) === 0 && buffer.readUInt16LE(2) === 1
}

export function computeDistOut(outDir: string, arch: string): string {
return path.join(outDir, "win" + (arch === "x64" ? "-x64" : ""))
}

function checkConflictingOptions(options: any) {
for (let name of ["outputDirectory", "appDirectory", "exe", "fixUpPaths", "usePackageJson", "extraFileSpecs", "extraMetadataSpecs"]) {
if (name in options) {
throw new Error(`Option ${name} is ignored, do not specify it.`)
}
}
}
3 changes: 3 additions & 0 deletions test/fixtures/test-app-one/install-spinner.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/src/helpers/packTester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ async function packAndCheck(projectDir: string, packagerOptions: PackagerOptions

await packager.build()

if (!packagerOptions.dist) {
if (!packagerOptions.dist || packagerOptions.platformPackagerFactory != null) {
return
}

Expand Down
Loading

0 comments on commit 85a6fba

Please sign in to comment.