Skip to content

Commit

Permalink
feat(nsis): multilang installer
Browse files Browse the repository at this point in the history
WIP: #529

Closes #643, #646
  • Loading branch information
develar committed Aug 9, 2016
1 parent d593a61 commit 50d27bf
Show file tree
Hide file tree
Showing 18 changed files with 268 additions and 119 deletions.
1 change: 1 addition & 0 deletions nsis-auto-updater/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
See wiki soon.
11 changes: 4 additions & 7 deletions nsis-auto-updater/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
"version": "0.0.1",
"description": "NSIS Auto Updater",
"main": "out/nsis-auto-updater/src/nsis-updater.js",
"scripts": {
},
"author": "Vladimir Krivosheev",
"license": "MIT",
"repository": "electron-userland/electron-builder",
"bugs": "https://github.com/electron-userland/electron-builder/issues",
"homepage": "https://github.com/electron-userland/electron-builder",
"files": [
"out"
],
Expand All @@ -17,9 +18,5 @@
"bundledDependencies": [
"fs-extra-p",
"bluebird"
],
"devDependencies": {
"@types/electron": "^0.37.14",
"@types/node": "^4.0.30"
}
]
}
67 changes: 60 additions & 7 deletions nsis-auto-updater/src/nsis-updater.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,64 @@
import { EventEmitter } from "events"
import { app } from "electron"
import { spawn } from "child_process"
import * as path from "path"
import { tmpdir } from "os"
import { Promise as BluebirdPromise } from "bluebird"
import { BintrayClient } from "../../src/publish/bintray"
import { HttpError } from "../../src/publish/restApiRequest"

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

interface VersionInfo {
version: string
}

interface Provider {
checkForUpdates(): Promise<VersionInfo>
}

//noinspection ReservedWordAsName
interface BintraySourceMetadata {
// e.g. develar
readonly user: string
// e.g. onshape-desktop-shell
readonly package: string

// e.g. generic or bin, defaults to generic
readonly repository?: string | null
}

class BintrayProvider {
private client: BintrayClient

constructor(configuration: BintraySourceMetadata) {
this.client = new BintrayClient(configuration.user, configuration.package, configuration.repository || "generic")
}

async checkForUpdates(): Promise<VersionInfo> {
try {
const data = await this.client.getVersion("_latest")
return {
version: data.name,
}
}
catch (e) {
if (e instanceof HttpError && e.response.statusCode === 404) {
throw new Error(`No latest version, please ensure that user, repository and package correctly configured. Or at least one version is published.${e.stack || e.message}`)
}
throw e
}
}
}

class NsisUpdater extends EventEmitter {
private setupPath = path.join(tmpdir(), 'innobox-upgrade.exe')

private updateAvailable = false
private quitAndInstallCalled = false

private client: Provider

constructor(public updateUrl?: string) {
super()
}
Expand All @@ -18,17 +67,21 @@ class NsisUpdater extends EventEmitter {
return this.updateUrl
}

setFeedURL(value: string) {
this.updateUrl = value
setFeedURL(value: string | BintraySourceMetadata) {
this.updateUrl = value.toString()

this.client = new BintrayProvider(<BintraySourceMetadata>value)
}

checkForUpdates(): void {
checkForUpdates(): Promise<any> {
if (this.updateUrl == null) {
this.emitError("Update URL is not set")
return
const message = "Update URL is not set"
this.emitError(message)
return BluebirdPromise.reject(new Error(message))
}

this.emit("checking-for-update")
return this.client.checkForUpdates()
}

quitAndInstall(): void {
Expand All @@ -49,7 +102,7 @@ class NsisUpdater extends EventEmitter {
stdio: "ignore",
}).unref()

app.quit()
require("electron").app.quit()
}

// emit both error object and message, this is to keep compatibility with old APIs
Expand Down
9 changes: 6 additions & 3 deletions nsis-auto-updater/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@
"skipLibCheck": true
},
"files": [
"../node_modules/@types/node/index.d.ts",
"../node_modules/fs-extra-p/index.d.ts",
"../node_modules/fs-extra-p/bluebird.d.ts",
"../src/util/httpRequest.ts"
"../src/util/httpRequest.ts",
"../src/publish/restApiRequest.ts",
"../src/publish/bintray.ts",
"../src/util/awaiter.ts"
],
"include": [
"src/**/*.ts",
"node_modules/@types/**/*.d.ts"
"src/**/*.ts"
],
"exclude": [
]
Expand Down
22 changes: 10 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,30 @@
"files": [
"out",
"templates",
"certs/root_certs.keychain"
"certs/root_certs.keychain",
"nsis-auto-updater/out",
"nsis-auto-updater/package.json"
],
"bin": {
"build": "./out/build-cli.js",
"cleanup": "./out/cleanup.js",
"install-app-deps": "./out/install-app-deps.js"
},
"scripts": {
"compile": "npm run compile-production && npm run compile-test",
"compile": "npm run compile-production && npm run compile-test && npm run compile-updater",
"compile-production": "ts-babel",
"compile-test": "ts-babel test",
"compile-updater": "tsc -p nsis-auto-updater",
"lint": "tslint 'src/**/*.ts' 'test/src/**/*.ts'",
"pretest": "npm run compile && npm run lint",
"test": "node ./test/out/helpers/runTests.js",
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
"semantic-release": "semantic-release pre && cd nsis-auto-updater && npm install --production && cd .. && npm publish && semantic-release post",
"//": "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 -f wiki wiki:master",
"whitespace": "whitespace 'src/**/*.ts'",
"docker-images": "docker/build.sh"
},
"repository": {
"type": "git",
"url": "https://github.com/electron-userland/electron-builder.git"
},
"repository": "electron-userland/electron-builder",
"engines": {
"node": ">=0.4.0"
},
Expand Down Expand Up @@ -75,10 +74,10 @@
"fs-extra-p": "^1.0.6",
"hosted-git-info": "^2.1.5",
"image-size": "^0.5.0",
"isbinaryfile": "^3.0.0",
"isbinaryfile": "^3.0.1",
"lodash.template": "^4.3.0",
"mime": "^1.3.4",
"minimatch": "^3.0.2",
"minimatch": "^3.0.3",
"normalize-package-data": "^2.3.5",
"path-sort": "^0.1.0",
"plist": "^1.2.0",
Expand All @@ -89,7 +88,6 @@
"sanitize-filename": "^1.6.0",
"semver": "^5.3.0",
"source-map-support": "^0.4.2",
"tslint": "^3.14.0-dev.1",
"update-notifier": "^1.0.2",
"uuid-1345": "^0.99.6",
"yargs": "^4.8.1"
Expand All @@ -110,7 +108,7 @@
"@types/debug": "0.0.28",
"@types/mime": "0.0.28",
"@types/progress": "^1.1.27",
"@types/semver": "^4.3.27",
"@types/semver": "^5.3.28",
"@types/source-map-support": "^0.2.27",
"ava-tf": "^0.15.4",
"babel-plugin-array-includes": "^2.0.3",
Expand All @@ -122,7 +120,7 @@
"json8": "^0.9.2",
"pre-git": "^3.10.0",
"ts-babel": "^1.0.4",
"tslint": "3.14.0",
"tslint": "^3.14.0-dev.1",
"typescript": "^2.1.0-dev.20160802",
"whitespace": "^2.1.0"
},
Expand Down
15 changes: 12 additions & 3 deletions src/packager/dirPackager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Promise as BluebirdPromise } from "bluebird"
import { emptyDir } from "fs-extra-p"
import { emptyDir, rename } from "fs-extra-p"
import { warn } from "../util/log"
import { AppInfo } from "../appInfo"
import * as path from "path"

const downloadElectron: (options: any) => Promise<any> = BluebirdPromise.promisify(require("electron-download"))
const extract: any = BluebirdPromise.promisify(require("extract-zip"))
Expand All @@ -27,7 +28,6 @@ export interface ElectronPackagerOptions {
const supportedPlatforms: any = {
// Maps to module ID for each platform (lazy-required if used)
darwin: "./mac",
linux: "./linux",
mas: "./mac", // map to darwin
win32: "./win32"
}
Expand Down Expand Up @@ -57,5 +57,14 @@ export async function pack(opts: ElectronPackagerOptions, out: string, platform:
emptyDir(out)
]))[0]
await extract(zipPath, {dir: out})
await require(supportedPlatforms[platform]).createApp(opts, out, initializeApp)

if (platform === "linux") {
await BluebirdPromise.all([
initializeApp(),
rename(path.join(out, "electron"), path.join(out, opts.appInfo.productFilename))
])
}
else {
await (<any>require(supportedPlatforms[platform])).createApp(opts, out, initializeApp)
}
}
11 changes: 0 additions & 11 deletions src/packager/linux.ts

This file was deleted.

34 changes: 9 additions & 25 deletions src/publish/BintrayPublisher.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,35 @@
import { Publisher, PublishOptions } from "./publisher"
import { Promise as BluebirdPromise } from "bluebird"
import { bintrayRequest, HttpError, doApiRequest, uploadFile } from "./gitHubRequest"
import { HttpError, doApiRequest } from "./restApiRequest"
import { uploadFile } from "./uploader"
import { log } from "../util/log"
import { debug } from "../util/util"
import { basename } from "path"
import { stat } from "fs-extra-p"
import { BintrayClient, Version } from "./bintray"

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

//noinspection ReservedWordAsName
interface Version {
readonly name: string
readonly package: string
}

export class BintrayPublisher implements Publisher {
private _versionPromise: BluebirdPromise<Version>
private readonly auth: string

private basePath: string
private readonly client: BintrayClient

constructor(private user: string, apiKey: string, private version: string, private packageName: string, private repo: string = "generic", private options: PublishOptions = {}) {
this.auth = `Basic ${new Buffer(`${user}:${apiKey}`).toString("base64")}`
this.basePath = `/packages/${this.user}/${this.repo}/${this.packageName}`
this.client = new BintrayClient(user, packageName, repo, apiKey)
this._versionPromise = <BluebirdPromise<Version>>this.init()
}

private async init(): Promise<Version | null> {
try {
return await bintrayRequest<Version>(`${this.basePath}/versions/${this.version}`, this.auth)
return await this.client.getVersion(this.version)
}
catch (e) {
if (e instanceof HttpError && e.response.statusCode === 404) {
if (this.options.publish !== "onTagOrDraft") {
log(`Version ${this.version} doesn't exist, creating one`)
return this.createVersion()
return this.client.createVersion(this.version)
}
else {
log(`Version ${this.version} doesn't exist, artifacts will be not published`)
Expand All @@ -46,12 +40,6 @@ export class BintrayPublisher implements Publisher {
}
}

private createVersion() {
return bintrayRequest<Version>(`${this.basePath}/versions`, this.auth, {
name: this.version,
})
}

async upload(file: string, artifactName?: string): Promise<any> {
const fileName = artifactName || basename(file)
const version = await this._versionPromise
Expand All @@ -74,7 +62,7 @@ export class BintrayPublisher implements Publisher {
"X-Bintray-Override": "1",
"X-Bintray-Publish": "1",
}
}, this.auth, uploadFile.bind(this, file, fileStat, fileName))
}, this.client.auth, uploadFile.bind(this, file, fileStat, fileName))
}
catch (e) {
if (e instanceof HttpError && e.response.statusCode === 502 && badGatewayCount++ < 3) {
Expand All @@ -93,10 +81,6 @@ export class BintrayPublisher implements Publisher {
}

const version = this._versionPromise.value()
if (version == null) {
return BluebirdPromise.resolve()
}

return bintrayRequest<Version>(`/packages/${this.user}/${this.repo}/${this.packageName}/versions/${version.name}`, this.auth, null, "DELETE")
return version == null ? BluebirdPromise.resolve() : this.client.deleteVersion(version.name)
}
}
31 changes: 31 additions & 0 deletions src/publish/bintray.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { bintrayRequest } from "./restApiRequest"

//noinspection ReservedWordAsName
export interface Version {
readonly name: string
readonly package: string
}

export class BintrayClient {
private readonly basePath: string
readonly auth: string | null

constructor(private user: string, private packageName: string, private repo: string = "generic", apiKey?: string | null) {
this.auth = apiKey == null ? null : `Basic ${new Buffer(`${user}:${apiKey}`).toString("base64")}`
this.basePath = `/packages/${this.user}/${this.repo}/${this.packageName}`
}

getVersion(version: string): Promise<Version> {
return bintrayRequest<Version>(`${this.basePath}/versions/${version}`, this.auth)
}

createVersion(version: string): Promise<any> {
return bintrayRequest<Version>(`${this.basePath}/versions`, this.auth, {
name: version,
})
}

deleteVersion(version: string): Promise<any> {
return bintrayRequest(`/packages/${this.user}/${this.repo}/${this.packageName}/versions/${version}`, this.auth, null, "DELETE")
}
}
Loading

0 comments on commit 50d27bf

Please sign in to comment.