Skip to content

Commit 50d27bf

Browse files
committed
feat(nsis): multilang installer
WIP: #529 Closes #643, #646
1 parent d593a61 commit 50d27bf

18 files changed

+268
-119
lines changed

nsis-auto-updater/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
See wiki soon.

nsis-auto-updater/package.json

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
"version": "0.0.1",
44
"description": "NSIS Auto Updater",
55
"main": "out/nsis-auto-updater/src/nsis-updater.js",
6-
"scripts": {
7-
},
86
"author": "Vladimir Krivosheev",
97
"license": "MIT",
8+
"repository": "electron-userland/electron-builder",
9+
"bugs": "https://github.com/electron-userland/electron-builder/issues",
10+
"homepage": "https://github.com/electron-userland/electron-builder",
1011
"files": [
1112
"out"
1213
],
@@ -17,9 +18,5 @@
1718
"bundledDependencies": [
1819
"fs-extra-p",
1920
"bluebird"
20-
],
21-
"devDependencies": {
22-
"@types/electron": "^0.37.14",
23-
"@types/node": "^4.0.30"
24-
}
21+
]
2522
}

nsis-auto-updater/src/nsis-updater.ts

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,64 @@
11
import { EventEmitter } from "events"
2-
import { app } from "electron"
32
import { spawn } from "child_process"
43
import * as path from "path"
54
import { tmpdir } from "os"
5+
import { Promise as BluebirdPromise } from "bluebird"
6+
import { BintrayClient } from "../../src/publish/bintray"
7+
import { HttpError } from "../../src/publish/restApiRequest"
8+
9+
//noinspection JSUnusedLocalSymbols
10+
const __awaiter = require("../../src/util/awaiter")
11+
12+
interface VersionInfo {
13+
version: string
14+
}
15+
16+
interface Provider {
17+
checkForUpdates(): Promise<VersionInfo>
18+
}
19+
20+
//noinspection ReservedWordAsName
21+
interface BintraySourceMetadata {
22+
// e.g. develar
23+
readonly user: string
24+
// e.g. onshape-desktop-shell
25+
readonly package: string
26+
27+
// e.g. generic or bin, defaults to generic
28+
readonly repository?: string | null
29+
}
30+
31+
class BintrayProvider {
32+
private client: BintrayClient
33+
34+
constructor(configuration: BintraySourceMetadata) {
35+
this.client = new BintrayClient(configuration.user, configuration.package, configuration.repository || "generic")
36+
}
37+
38+
async checkForUpdates(): Promise<VersionInfo> {
39+
try {
40+
const data = await this.client.getVersion("_latest")
41+
return {
42+
version: data.name,
43+
}
44+
}
45+
catch (e) {
46+
if (e instanceof HttpError && e.response.statusCode === 404) {
47+
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}`)
48+
}
49+
throw e
50+
}
51+
}
52+
}
653

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

1057
private updateAvailable = false
1158
private quitAndInstallCalled = false
1259

60+
private client: Provider
61+
1362
constructor(public updateUrl?: string) {
1463
super()
1564
}
@@ -18,17 +67,21 @@ class NsisUpdater extends EventEmitter {
1867
return this.updateUrl
1968
}
2069

21-
setFeedURL(value: string) {
22-
this.updateUrl = value
70+
setFeedURL(value: string | BintraySourceMetadata) {
71+
this.updateUrl = value.toString()
72+
73+
this.client = new BintrayProvider(<BintraySourceMetadata>value)
2374
}
2475

25-
checkForUpdates(): void {
76+
checkForUpdates(): Promise<any> {
2677
if (this.updateUrl == null) {
27-
this.emitError("Update URL is not set")
28-
return
78+
const message = "Update URL is not set"
79+
this.emitError(message)
80+
return BluebirdPromise.reject(new Error(message))
2981
}
3082

3183
this.emit("checking-for-update")
84+
return this.client.checkForUpdates()
3285
}
3386

3487
quitAndInstall(): void {
@@ -49,7 +102,7 @@ class NsisUpdater extends EventEmitter {
49102
stdio: "ignore",
50103
}).unref()
51104

52-
app.quit()
105+
require("electron").app.quit()
53106
}
54107

55108
// emit both error object and message, this is to keep compatibility with old APIs

nsis-auto-updater/tsconfig.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
"skipLibCheck": true
1717
},
1818
"files": [
19+
"../node_modules/@types/node/index.d.ts",
1920
"../node_modules/fs-extra-p/index.d.ts",
2021
"../node_modules/fs-extra-p/bluebird.d.ts",
21-
"../src/util/httpRequest.ts"
22+
"../src/util/httpRequest.ts",
23+
"../src/publish/restApiRequest.ts",
24+
"../src/publish/bintray.ts",
25+
"../src/util/awaiter.ts"
2226
],
2327
"include": [
24-
"src/**/*.ts",
25-
"node_modules/@types/**/*.d.ts"
28+
"src/**/*.ts"
2629
],
2730
"exclude": [
2831
]

package.json

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,30 @@
66
"files": [
77
"out",
88
"templates",
9-
"certs/root_certs.keychain"
9+
"certs/root_certs.keychain",
10+
"nsis-auto-updater/out",
11+
"nsis-auto-updater/package.json"
1012
],
1113
"bin": {
1214
"build": "./out/build-cli.js",
1315
"cleanup": "./out/cleanup.js",
1416
"install-app-deps": "./out/install-app-deps.js"
1517
},
1618
"scripts": {
17-
"compile": "npm run compile-production && npm run compile-test",
19+
"compile": "npm run compile-production && npm run compile-test && npm run compile-updater",
1820
"compile-production": "ts-babel",
1921
"compile-test": "ts-babel test",
2022
"compile-updater": "tsc -p nsis-auto-updater",
2123
"lint": "tslint 'src/**/*.ts' 'test/src/**/*.ts'",
2224
"pretest": "npm run compile && npm run lint",
2325
"test": "node ./test/out/helpers/runTests.js",
24-
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
26+
"semantic-release": "semantic-release pre && cd nsis-auto-updater && npm install --production && cd .. && npm publish && semantic-release post",
2527
"//": "Update wiki if docs changed. Update only if functionalily are generally available (latest release, not next)",
2628
"update-wiki": "git subtree split -b wiki --prefix docs/ && git push -f wiki wiki:master",
2729
"whitespace": "whitespace 'src/**/*.ts'",
2830
"docker-images": "docker/build.sh"
2931
},
30-
"repository": {
31-
"type": "git",
32-
"url": "https://github.com/electron-userland/electron-builder.git"
33-
},
32+
"repository": "electron-userland/electron-builder",
3433
"engines": {
3534
"node": ">=0.4.0"
3635
},
@@ -75,10 +74,10 @@
7574
"fs-extra-p": "^1.0.6",
7675
"hosted-git-info": "^2.1.5",
7776
"image-size": "^0.5.0",
78-
"isbinaryfile": "^3.0.0",
77+
"isbinaryfile": "^3.0.1",
7978
"lodash.template": "^4.3.0",
8079
"mime": "^1.3.4",
81-
"minimatch": "^3.0.2",
80+
"minimatch": "^3.0.3",
8281
"normalize-package-data": "^2.3.5",
8382
"path-sort": "^0.1.0",
8483
"plist": "^1.2.0",
@@ -89,7 +88,6 @@
8988
"sanitize-filename": "^1.6.0",
9089
"semver": "^5.3.0",
9190
"source-map-support": "^0.4.2",
92-
"tslint": "^3.14.0-dev.1",
9391
"update-notifier": "^1.0.2",
9492
"uuid-1345": "^0.99.6",
9593
"yargs": "^4.8.1"
@@ -110,7 +108,7 @@
110108
"@types/debug": "0.0.28",
111109
"@types/mime": "0.0.28",
112110
"@types/progress": "^1.1.27",
113-
"@types/semver": "^4.3.27",
111+
"@types/semver": "^5.3.28",
114112
"@types/source-map-support": "^0.2.27",
115113
"ava-tf": "^0.15.4",
116114
"babel-plugin-array-includes": "^2.0.3",
@@ -122,7 +120,7 @@
122120
"json8": "^0.9.2",
123121
"pre-git": "^3.10.0",
124122
"ts-babel": "^1.0.4",
125-
"tslint": "3.14.0",
123+
"tslint": "^3.14.0-dev.1",
126124
"typescript": "^2.1.0-dev.20160802",
127125
"whitespace": "^2.1.0"
128126
},

src/packager/dirPackager.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { Promise as BluebirdPromise } from "bluebird"
2-
import { emptyDir } from "fs-extra-p"
2+
import { emptyDir, rename } from "fs-extra-p"
33
import { warn } from "../util/log"
44
import { AppInfo } from "../appInfo"
5+
import * as path from "path"
56

67
const downloadElectron: (options: any) => Promise<any> = BluebirdPromise.promisify(require("electron-download"))
78
const extract: any = BluebirdPromise.promisify(require("extract-zip"))
@@ -27,7 +28,6 @@ export interface ElectronPackagerOptions {
2728
const supportedPlatforms: any = {
2829
// Maps to module ID for each platform (lazy-required if used)
2930
darwin: "./mac",
30-
linux: "./linux",
3131
mas: "./mac", // map to darwin
3232
win32: "./win32"
3333
}
@@ -57,5 +57,14 @@ export async function pack(opts: ElectronPackagerOptions, out: string, platform:
5757
emptyDir(out)
5858
]))[0]
5959
await extract(zipPath, {dir: out})
60-
await require(supportedPlatforms[platform]).createApp(opts, out, initializeApp)
60+
61+
if (platform === "linux") {
62+
await BluebirdPromise.all([
63+
initializeApp(),
64+
rename(path.join(out, "electron"), path.join(out, opts.appInfo.productFilename))
65+
])
66+
}
67+
else {
68+
await (<any>require(supportedPlatforms[platform])).createApp(opts, out, initializeApp)
69+
}
6170
}

src/packager/linux.ts

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/publish/BintrayPublisher.ts

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,35 @@
11
import { Publisher, PublishOptions } from "./publisher"
22
import { Promise as BluebirdPromise } from "bluebird"
3-
import { bintrayRequest, HttpError, doApiRequest, uploadFile } from "./gitHubRequest"
3+
import { HttpError, doApiRequest } from "./restApiRequest"
4+
import { uploadFile } from "./uploader"
45
import { log } from "../util/log"
56
import { debug } from "../util/util"
67
import { basename } from "path"
78
import { stat } from "fs-extra-p"
9+
import { BintrayClient, Version } from "./bintray"
810

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

12-
//noinspection ReservedWordAsName
13-
interface Version {
14-
readonly name: string
15-
readonly package: string
16-
}
17-
1814
export class BintrayPublisher implements Publisher {
1915
private _versionPromise: BluebirdPromise<Version>
20-
private readonly auth: string
2116

22-
private basePath: string
17+
private readonly client: BintrayClient
2318

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

3024
private async init(): Promise<Version | null> {
3125
try {
32-
return await bintrayRequest<Version>(`${this.basePath}/versions/${this.version}`, this.auth)
26+
return await this.client.getVersion(this.version)
3327
}
3428
catch (e) {
3529
if (e instanceof HttpError && e.response.statusCode === 404) {
3630
if (this.options.publish !== "onTagOrDraft") {
3731
log(`Version ${this.version} doesn't exist, creating one`)
38-
return this.createVersion()
32+
return this.client.createVersion(this.version)
3933
}
4034
else {
4135
log(`Version ${this.version} doesn't exist, artifacts will be not published`)
@@ -46,12 +40,6 @@ export class BintrayPublisher implements Publisher {
4640
}
4741
}
4842

49-
private createVersion() {
50-
return bintrayRequest<Version>(`${this.basePath}/versions`, this.auth, {
51-
name: this.version,
52-
})
53-
}
54-
5543
async upload(file: string, artifactName?: string): Promise<any> {
5644
const fileName = artifactName || basename(file)
5745
const version = await this._versionPromise
@@ -74,7 +62,7 @@ export class BintrayPublisher implements Publisher {
7462
"X-Bintray-Override": "1",
7563
"X-Bintray-Publish": "1",
7664
}
77-
}, this.auth, uploadFile.bind(this, file, fileStat, fileName))
65+
}, this.client.auth, uploadFile.bind(this, file, fileStat, fileName))
7866
}
7967
catch (e) {
8068
if (e instanceof HttpError && e.response.statusCode === 502 && badGatewayCount++ < 3) {
@@ -93,10 +81,6 @@ export class BintrayPublisher implements Publisher {
9381
}
9482

9583
const version = this._versionPromise.value()
96-
if (version == null) {
97-
return BluebirdPromise.resolve()
98-
}
99-
100-
return bintrayRequest<Version>(`/packages/${this.user}/${this.repo}/${this.packageName}/versions/${version.name}`, this.auth, null, "DELETE")
84+
return version == null ? BluebirdPromise.resolve() : this.client.deleteVersion(version.name)
10185
}
10286
}

src/publish/bintray.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { bintrayRequest } from "./restApiRequest"
2+
3+
//noinspection ReservedWordAsName
4+
export interface Version {
5+
readonly name: string
6+
readonly package: string
7+
}
8+
9+
export class BintrayClient {
10+
private readonly basePath: string
11+
readonly auth: string | null
12+
13+
constructor(private user: string, private packageName: string, private repo: string = "generic", apiKey?: string | null) {
14+
this.auth = apiKey == null ? null : `Basic ${new Buffer(`${user}:${apiKey}`).toString("base64")}`
15+
this.basePath = `/packages/${this.user}/${this.repo}/${this.packageName}`
16+
}
17+
18+
getVersion(version: string): Promise<Version> {
19+
return bintrayRequest<Version>(`${this.basePath}/versions/${version}`, this.auth)
20+
}
21+
22+
createVersion(version: string): Promise<any> {
23+
return bintrayRequest<Version>(`${this.basePath}/versions`, this.auth, {
24+
name: version,
25+
})
26+
}
27+
28+
deleteVersion(version: string): Promise<any> {
29+
return bintrayRequest(`/packages/${this.user}/${this.repo}/${this.packageName}/versions/${version}`, this.auth, null, "DELETE")
30+
}
31+
}

0 commit comments

Comments
 (0)