Skip to content

Commit 8008734

Browse files
committed
fix: Bump electron-wininstaller-fixed to Squirrel 1.4.4
1 parent 8665ef4 commit 8008734

File tree

13 files changed

+301
-43
lines changed

13 files changed

+301
-43
lines changed

.idea/dictionaries/develar.xml

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
osx_image: xcode7.3
1+
osx_image: xcode8
22

33
matrix:
44
include:

docker/winSign.sh

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

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
"dependencies": {
6161
"7zip-bin": "^1.0.6",
6262
"ansi-escapes": "^1.4.0",
63+
"archiver": "^1.0.1",
64+
"archiver-utils": "^1.2.0",
6365
"asar-electron-builder": "^0.13.2",
6466
"bluebird": "^3.4.1",
6567
"chalk": "^1.1.3",
@@ -69,7 +71,6 @@
6971
"debug": "^2.2.0",
7072
"electron-download": "^2.1.2",
7173
"electron-osx-sign": "^0.4.0-beta4",
72-
"electron-winstaller-fixed": "~4.0.0",
7374
"extract-zip": "^1.5.0",
7475
"fs-extra-p": "^1.0.6",
7576
"hosted-git-info": "^2.1.5",
@@ -102,7 +103,6 @@
102103
]
103104
},
104105
"devDependencies": {
105-
"path-sort": "^0.1.0",
106106
"@develar/semantic-release": "^6.3.6",
107107
"@types/debug": "0.0.28",
108108
"@types/mime": "0.0.28",
@@ -117,6 +117,7 @@
117117
"decompress-zip": "^0.3.0",
118118
"diff": "^2.2.3",
119119
"json8": "^0.9.2",
120+
"path-sort": "^0.1.0",
120121
"pre-git": "^3.10.0",
121122
"ts-babel": "^1.0.4",
122123
"tslint": "^3.14.0-dev.1",

src/targets/nsis.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Arch, NsisOptions } from "../metadata"
33
import { debug, doSpawn, handleProcess, use } from "../util/util"
44
import * as path from "path"
55
import { Promise as BluebirdPromise } from "bluebird"
6-
import { getBin } from "../util/binDownload"
6+
import { getBinFromBintray } from "../util/binDownload"
77
import { v5 as uuid5 } from "uuid-1345"
88
import { Target } from "../platformPackager"
99
import { archiveApp } from "./archive"
@@ -14,14 +14,14 @@ import semver = require("semver")
1414
//noinspection JSUnusedLocalSymbols
1515
const __awaiter = require("../util/awaiter")
1616

17-
const NSIS_VERSION = "nsis-3.0.0"
17+
const NSIS_VERSION = "3.0.0"
1818
//noinspection SpellCheckingInspection
1919
const NSIS_SHA2 = "7741089f3ca13de879f87836156ef785eab49844cacbeeabaeaefd1ade325ee7"
2020

2121
//noinspection SpellCheckingInspection
2222
const ELECTRON_BUILDER_NS_UUID = "50e065bc-3134-11e6-9bab-38c9862bdaf3"
2323

24-
const nsisPathPromise = getBin("nsis", NSIS_VERSION, `https://dl.bintray.com/electron-userland/bin/${NSIS_VERSION}.7z`, NSIS_SHA2)
24+
const nsisPathPromise = getBinFromBintray("nsis", NSIS_VERSION, NSIS_SHA2)
2525

2626
export default class NsisTarget extends Target {
2727
private readonly options: NsisOptions

src/targets/squirrelPack.ts

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
import * as path from "path"
2+
import { Promise as BluebirdPromise } from "bluebird"
3+
import { emptyDir, copy, createWriteStream, unlink } from "fs-extra-p"
4+
import { spawn, exec } from "../util/util"
5+
import { debug } from "../util/util"
6+
import { WinPackager } from "../winPackager"
7+
8+
const archiverUtil = require("archiver-utils")
9+
const archiver = require("archiver")
10+
11+
//noinspection JSUnusedLocalSymbols
12+
const __awaiter = require("../util/awaiter")
13+
14+
export function convertVersion(version: string): string {
15+
const parts = version.split("-")
16+
const mainVersion = parts.shift()
17+
if (parts.length > 0) {
18+
return [mainVersion, parts.join("-").replace(/\./g, "")].join("-")
19+
}
20+
else {
21+
return mainVersion!
22+
}
23+
}
24+
25+
function syncReleases(outputDirectory: string, options: SquirrelOptions) {
26+
const args = prepareArgs(["-u", options.remoteReleases!, "-r", outputDirectory], path.join(options.vendorPath, "SyncReleases.exe"))
27+
if (options.remoteToken) {
28+
args.push("-t", options.remoteToken)
29+
}
30+
return spawn(process.platform === "win32" ? path.join(options.vendorPath, "SyncReleases.exe") : "mono", args)
31+
}
32+
33+
export interface SquirrelOptions {
34+
vendorPath: string
35+
remoteReleases?: string
36+
remoteToken?: string
37+
loadingGif?: string
38+
productName?: string
39+
name: string
40+
packageCompressionLevel?: number
41+
version: string
42+
msi?: any
43+
44+
owners?: string
45+
description?: string
46+
iconUrl?: string
47+
authors?: string
48+
extraMetadataSpecs?: string
49+
copyright?: string
50+
}
51+
52+
export async function buildInstaller(options: SquirrelOptions, outputDirectory: string, stageDir: string, setupExe: string, packager: WinPackager, appOutDir: string) {
53+
const appUpdate = path.join(stageDir, "Update.exe")
54+
const promises = [
55+
copy(path.join(options.vendorPath, "Update.exe"), appUpdate)
56+
.then(() => packager.sign(appUpdate)),
57+
emptyDir(outputDirectory)
58+
]
59+
if (options.remoteReleases) {
60+
promises.push(syncReleases(outputDirectory, options))
61+
}
62+
await BluebirdPromise.all(promises)
63+
64+
const embeddedArchiveFile = path.join(stageDir, "setup.zip")
65+
const embeddedArchive = archiver("zip", {zlib: {level: options.packageCompressionLevel == null ? 6 : options.packageCompressionLevel}})
66+
const embeddedArchiveOut = createWriteStream(embeddedArchiveFile)
67+
const embeddedArchivePromise = new BluebirdPromise(function (resolve, reject) {
68+
embeddedArchive.on("error", reject)
69+
embeddedArchiveOut.on("close", resolve)
70+
})
71+
embeddedArchive.pipe(embeddedArchiveOut)
72+
73+
embeddedArchive.file(appUpdate, {name: "Update.exe"})
74+
embeddedArchive.file(options.loadingGif ? path.resolve(options.loadingGif) : path.join(__dirname, "..", "..", "templates", "install-spinner.gif"), {name: "background.gif"})
75+
76+
const version = convertVersion(options.version)
77+
const packageName = `${options.name}-${version}-full.nupkg`
78+
const nupkgPath = path.join(outputDirectory, packageName)
79+
const setupPath = path.join(outputDirectory, setupExe || `${options.name || options.productName}Setup.exe`)
80+
81+
await BluebirdPromise.all<any>([
82+
pack(options, appOutDir, appUpdate, nupkgPath, version, options.packageCompressionLevel),
83+
copy(path.join(options.vendorPath, "Setup.exe"), setupPath),
84+
])
85+
86+
embeddedArchive.file(nupkgPath, {name: packageName})
87+
88+
const releaseEntry = await releasify(options, nupkgPath, outputDirectory, packageName)
89+
90+
embeddedArchive.append(releaseEntry, {name: "RELEASES"})
91+
embeddedArchive.finalize()
92+
await embeddedArchivePromise
93+
94+
const writeZipToSetup = path.join(options.vendorPath, "WriteZipToSetup.exe")
95+
await exec(process.platform === "win32" ? writeZipToSetup : "wine", prepareArgs([setupPath, embeddedArchiveFile], writeZipToSetup))
96+
97+
await packager.signAndEditResources(setupPath)
98+
if (options.msi && process.platform === "win32") {
99+
const outFile = setupExe.replace(".exe", ".msi")
100+
await msi(options, nupkgPath, setupPath, outputDirectory, outFile)
101+
await packager.signAndEditResources(path.join(outputDirectory, outFile))
102+
}
103+
}
104+
105+
async function pack(options: SquirrelOptions, directory: string, updateFile: string, outFile: string, version: string, packageCompressionLevel?: number) {
106+
const archive = archiver("zip", {zlib: {level: packageCompressionLevel == null ? 9 : packageCompressionLevel}})
107+
// const archiveOut = createWriteStream('/Users/develar/test.zip')
108+
const archiveOut = createWriteStream(outFile)
109+
const archivePromise = new BluebirdPromise(function (resolve, reject) {
110+
archive.on("error", reject)
111+
archiveOut.on("close", resolve)
112+
})
113+
archive.pipe(archiveOut)
114+
115+
const author = options.authors || options.owners
116+
const copyright = options.copyright || `Copyright © ${new Date().getFullYear()} ${author}`
117+
const nuspecContent = `<?xml version="1.0"?>
118+
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
119+
<metadata>
120+
<id>${options.name}</id>
121+
<version>${version}</version>
122+
<title>${options.productName}</title>
123+
<authors>${author}</authors>
124+
<owners>${options.owners || options.authors}</owners>
125+
<iconUrl>${options.iconUrl}</iconUrl>
126+
<requireLicenseAcceptance>false</requireLicenseAcceptance>
127+
<description>${options.description}</description>
128+
<copyright>${copyright}</copyright>${options.extraMetadataSpecs || ""}
129+
</metadata>
130+
</package>`
131+
debug(`Created NuSpec file:\n${nuspecContent}`)
132+
archive.append(nuspecContent.replace(/\n/, "\r\n"), {name: `${encodeURI(options.name).replace(/%5B/g, "[").replace(/%5D/g, "]")}.nuspec`})
133+
134+
//noinspection SpellCheckingInspection
135+
archive.append(`<?xml version="1.0" encoding="utf-8"?>
136+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
137+
<Relationship Type="http://schemas.microsoft.com/packaging/2010/07/manifest" Target="/${options.name}.nuspec" Id="Re0" />
138+
<Relationship Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="/package/services/metadata/core-properties/1.psmdcp" Id="Re1" />
139+
</Relationships>`.replace(/\n/, "\r\n"), {name: ".rels", prefix: "_rels"})
140+
141+
//noinspection SpellCheckingInspection
142+
archive.append(`<?xml version="1.0" encoding="utf-8"?>
143+
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
144+
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />
145+
<Default Extension="nuspec" ContentType="application/octet" />
146+
<Default Extension="pak" ContentType="application/octet" />
147+
<Default Extension="asar" ContentType="application/octet" />
148+
<Default Extension="bin" ContentType="application/octet" />
149+
<Default Extension="dll" ContentType="application/octet" />
150+
<Default Extension="exe" ContentType="application/octet" />
151+
<Default Extension="dat" ContentType="application/octet" />
152+
<Default Extension="psmdcp" ContentType="application/vnd.openxmlformats-package.core-properties+xml" />
153+
<Override PartName="/lib/net45/LICENSE" ContentType="application/octet" />
154+
<Default Extension="diff" ContentType="application/octet" />
155+
<Default Extension="bsdiff" ContentType="application/octet" />
156+
<Default Extension="shasum" ContentType="text/plain" />
157+
</Types>`.replace(/\n/, "\r\n"), {name: "[Content_Types].xml"})
158+
159+
archive.append(`<?xml version="1.0" encoding="utf-8"?>
160+
<coreProperties xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
161+
xmlns="http://schemas.openxmlformats.org/package/2006/metadata/core-properties">
162+
<dc:creator>${author}</dc:creator>
163+
<dc:description>${options.description}</dc:description>
164+
<dc:identifier>${options.name}</dc:identifier>
165+
<version>${version}</version>
166+
<keywords/>
167+
<dc:title>${options.productName}</dc:title>
168+
<lastModifiedBy>NuGet, Version=2.8.50926.602, Culture=neutral, PublicKeyToken=null;Microsoft Windows NT 6.2.9200.0;.NET Framework 4</lastModifiedBy>
169+
</coreProperties>`.replace(/\n/, "\r\n"), {name: "1.psmdcp", prefix: "package/services/metadata/core-properties"})
170+
171+
archive.file(updateFile, {name: "Update.exe", prefix: "lib/net45"})
172+
encodedZip(archive, directory, "lib/net45")
173+
await archivePromise
174+
}
175+
176+
async function releasify(options: SquirrelOptions, nupkgPath: string, outputDirectory: string, packageName: string) {
177+
const args = [
178+
"--releasify", nupkgPath,
179+
"--releaseDir", outputDirectory
180+
]
181+
const out = (await exec(process.platform === "win32" ? path.join(options.vendorPath, "Update.com") : "mono", prepareArgs(args, path.join(options.vendorPath, "Update-Mono.exe")))).trim()
182+
if (debug.enabled) {
183+
debug(out)
184+
}
185+
186+
const lines = out.split("\n")
187+
for (let i = lines.length - 1; i > -1; i--) {
188+
const line = lines[i]
189+
if (line.includes(packageName)) {
190+
return line.trim()
191+
}
192+
}
193+
194+
throw new Error("Invalid output, cannot find last release entry")
195+
}
196+
197+
async function msi(options: SquirrelOptions, nupkgPath: string, setupPath: string, outputDirectory: string, outFile: string) {
198+
const args = [
199+
"--createMsi", nupkgPath,
200+
"--bootstrapperExe", setupPath
201+
]
202+
await exec(process.platform === "win32" ? path.join(options.vendorPath, "Update.com") : "mono", prepareArgs(args, path.join(options.vendorPath, "Update-Mono.exe")))
203+
//noinspection SpellCheckingInspection
204+
await exec(path.join(options.vendorPath, "candle.exe"), ["-nologo", "-ext", "WixNetFxExtension", "-out", "Setup.wixobj", "Setup.wxs"], {
205+
cwd: outputDirectory,
206+
})
207+
//noinspection SpellCheckingInspection
208+
await exec(path.join(options.vendorPath, "light.exe"), ["-ext", "WixNetFxExtension", "-sval", "-out", outFile, "Setup.wixobj"], {
209+
cwd: outputDirectory,
210+
})
211+
212+
//noinspection SpellCheckingInspection
213+
await BluebirdPromise.all([
214+
unlink(path.join(outputDirectory, "Setup.wxs")),
215+
unlink(path.join(outputDirectory, "Setup.wixobj")),
216+
unlink(path.join(outputDirectory, outFile.replace(".msi", ".wixpdb"))).catch(e => debug(e.toString())),
217+
])
218+
}
219+
220+
function prepareArgs(args: Array<string>, exePath: string) {
221+
if (process.platform !== "win32") {
222+
args.unshift(exePath)
223+
}
224+
return args
225+
}
226+
227+
function encodedZip(archive: any, dir: string, prefix: string) {
228+
archiverUtil.walkdir(dir, function (error: any, files: any) {
229+
if (error) {
230+
archive.emit("error", error)
231+
return
232+
}
233+
234+
for (let file of files) {
235+
if (file.stats.isDirectory()) {
236+
continue
237+
}
238+
239+
// GBK file name encoding (or Non-English file name) caused a problem
240+
const entryData = {
241+
name: encodeURI(file.relative.replace(/\\/g, "/")).replace(/%5B/g, "[").replace(/%5D/g, "]"),
242+
prefix: prefix,
243+
stats: file.stats,
244+
}
245+
archive._append(file.path, entryData)
246+
}
247+
248+
archive.finalize()
249+
})
250+
}

0 commit comments

Comments
 (0)