Skip to content

Commit

Permalink
feat(electron-updater): use cache dir for electron-updater cache data
Browse files Browse the repository at this point in the history
  • Loading branch information
develar committed Nov 11, 2018
1 parent d9341d6 commit c01b7c0
Show file tree
Hide file tree
Showing 42 changed files with 1,095 additions and 547 deletions.
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -31,7 +31,7 @@
"dependencies": {
"7zip-bin": "~4.1.0",
"@types/is-ci": "^1.1.0",
"app-builder-bin": "2.4.1",
"app-builder-bin": "2.4.3",
"archiver": "^3.0.0",
"async-exit-hook": "^2.0.1",
"bluebird-lst": "^1.0.6",
Expand Down Expand Up @@ -123,7 +123,7 @@
},
"/////": "proton-native is required only for proton tests",
"optionalDependencies": {
"proton-native": "1.1.9"
"proton-native": "1.1.10"
},
"jest": {
"testEnvironment": "node",
Expand Down
2 changes: 1 addition & 1 deletion packages/app-builder-lib/package.json
Expand Up @@ -42,7 +42,7 @@
"homepage": "https://github.com/electron-userland/electron-builder",
"dependencies": {
"7zip-bin": "~4.1.0",
"app-builder-bin": "2.4.1",
"app-builder-bin": "2.4.3",
"async-exit-hook": "^2.0.1",
"bluebird-lst": "^1.0.6",
"chromium-pickle-js": "^0.2.0",
Expand Down
4 changes: 4 additions & 0 deletions packages/app-builder-lib/src/appInfo.ts
Expand Up @@ -102,6 +102,10 @@ export class AppInfo {
return sanitizeFileName(this.name)
}

get updaterCacheDirName(): string {
return this.sanitizedName.toLowerCase() + "-updater"
}

get copyright(): string {
const copyright = this.info.config.copyright
if (copyright != null) {
Expand Down
14 changes: 8 additions & 6 deletions packages/app-builder-lib/src/publish/PublishManager.ts
Expand Up @@ -94,6 +94,7 @@ export class PublishManager implements PublishContext {
}
}
else {
// AppImage writes data to AppImage stage dir, not to linux-unpacked
return
}

Expand Down Expand Up @@ -223,15 +224,16 @@ export async function getAppUpdatePublishConfiguration(packager: PlatformPackage
return null
}

let publishConfig = publishConfigs[0]
const publishConfig = {
...publishConfigs[0],
updaterCacheDirName: packager.appInfo.updaterCacheDirName,
}

if (packager.platform === Platform.WINDOWS && publishConfig.publisherName == null) {
const winPackager = packager as WinPackager
if (winPackager.isForceCodeSigningVerification) {
const publisherName = await winPackager.computedPublisherName.value
if (publisherName != null) {
publishConfig = {...publishConfig, publisherName}
}
const publisherName = winPackager.isForceCodeSigningVerification ? await winPackager.computedPublisherName.value : undefined
if (publisherName != null) {
publishConfig.publisherName = publisherName
}
}
return publishConfig
Expand Down
18 changes: 16 additions & 2 deletions packages/app-builder-lib/src/publish/updateInfoBuilder.ts
Expand Up @@ -76,6 +76,20 @@ export interface UpdateInfoFileTask {
readonly packager: PlatformPackager<any>
}

function computeIsisElectronUpdater1xCompatibility(updaterCompatibility: string | null, publishConfiguration: PublishConfiguration, packager: Packager) {
if (updaterCompatibility != null) {
return semver.satisfies("1.0.0", updaterCompatibility)
}

// spaces is a new publish provider, no need to keep backward compatibility
if (publishConfiguration.provider === "spaces") {
return false
}

const updaterVersion = packager.metadata.dependencies == null ? null : packager.metadata.dependencies["electron-updater"]
return updaterVersion == null || semver.lt(updaterVersion, "4.0.0")
}

/** @internal */
export async function createUpdateInfoTasks(event: ArtifactCreated, _publishConfigs: Array<PublishConfiguration>): Promise<Array<UpdateInfoFileTask>> {
const packager = event.packager
Expand All @@ -100,15 +114,15 @@ export async function createUpdateInfoTasks(event: ArtifactCreated, _publishConf
dir = path.join(outDir, publishConfiguration.provider)
}

// spaces is a new publish provider, no need to keep backward compatibility
let isElectronUpdater1xCompatibility = publishConfiguration.provider !== "spaces" && (electronUpdaterCompatibility == null || semver.satisfies("1.0.0", electronUpdaterCompatibility))
let isElectronUpdater1xCompatibility = computeIsisElectronUpdater1xCompatibility(electronUpdaterCompatibility, publishConfiguration, packager.info)

let info = sharedInfo
// noinspection JSDeprecatedSymbols
if (isElectronUpdater1xCompatibility && packager.platform === Platform.WINDOWS) {
info = {
...info,
};
// noinspection JSDeprecatedSymbols
(info as WindowsUpdateInfo).sha2 = await sha2.value
}

Expand Down
4 changes: 2 additions & 2 deletions packages/app-builder-lib/src/targets/nsis/NsisTarget.ts
Expand Up @@ -444,10 +444,10 @@ export class NsisTarget extends Target {
}

if (this.isWebInstaller) {
defines.APP_PACKAGE_STORE_FILE = `${appInfo.productFilename}\\${CURRENT_APP_PACKAGE_FILE_NAME}`
defines.APP_PACKAGE_STORE_FILE = `${appInfo.updaterCacheDirName}\\${CURRENT_APP_PACKAGE_FILE_NAME}`
}
else {
defines.APP_INSTALLER_STORE_FILE = `${appInfo.productFilename}\\${CURRENT_APP_INSTALLER_FILE_NAME}`
defines.APP_INSTALLER_STORE_FILE = `${appInfo.updaterCacheDirName}\\${CURRENT_APP_INSTALLER_FILE_NAME}`
}

if (!this.isWebInstaller && defines.APP_BUILD_DIR == null) {
Expand Down
5 changes: 3 additions & 2 deletions packages/app-builder-lib/src/util/packageMetadata.ts
Expand Up @@ -92,8 +92,9 @@ function checkDependencies(dependencies: { [key: string]: string } | null | unde
}

const updaterVersion = dependencies["electron-updater"]
if (updaterVersion != null && !semver.satisfies(versionFromDependencyRange(updaterVersion), ">=3.2.0")) {
errors.push(`At least electron-updater 3.2.0 is recommended by current electron-builder version. Please set electron-updater version to "^3.2.0"`)
const requiredElectronUpdaterVersion = "4.0.0"
if (updaterVersion != null && !semver.satisfies(versionFromDependencyRange(updaterVersion), `>=${requiredElectronUpdaterVersion}`)) {
errors.push(`At least electron-updater ${requiredElectronUpdaterVersion} is recommended by current electron-builder version. Please set electron-updater version to "^${requiredElectronUpdaterVersion}"`)
}

const swVersion = dependencies["electron-builder-squirrel-windows"]
Expand Down
21 changes: 12 additions & 9 deletions packages/app-builder-lib/templates/nsis/include/installUtil.nsh
@@ -1,3 +1,14 @@
!macro moveFile FROM TO
ClearErrors
Rename `${FROM}` `${TO}`
${if} ${errors}
# not clear - can NSIS rename on another drive or not, so, in case of error, just copy
ClearErrors
!insertmacro copyFile `${FROM}` `${TO}`
Delete `${FROM}`
${endif}
!macroend

!macro copyFile FROM TO
${StdUtils.GetParentPath} $R5 `${TO}`
CreateDirectory `$R5`
Expand Down Expand Up @@ -131,15 +142,7 @@ Function uninstallOldVersion
Goto Done
${endif}

ClearErrors
Rename "$uninstallerFileName" "$PLUGINSDIR\old-uninstaller.exe"
${if} ${errors}
# not clear - can NSIS rename on another drive or not, so, in case of error, just copy
ClearErrors
!insertmacro copyFile "$uninstallerFileName" "$PLUGINSDIR\old-uninstaller.exe"
Delete "$uninstallerFileName"
${endif}

!insertmacro moveFile "$uninstallerFileName" "$PLUGINSDIR\old-uninstaller.exe"
StrCpy $uninstallerFileName "$PLUGINSDIR\old-uninstaller.exe"

${if} $installMode == "CurrentUser"
Expand Down
11 changes: 2 additions & 9 deletions packages/app-builder-lib/templates/nsis/include/installer.nsh
Expand Up @@ -66,14 +66,7 @@
SetShellVarContext current
${endif}

ClearErrors
Rename "$packageFile" "$APPDATA\${APP_PACKAGE_STORE_FILE}"
${if} ${errors}
# not clear - can NSIS rename on another drive or not, so, in case of error, just copy
ClearErrors
!insertmacro copyFile "$packageFile" "$APPDATA\${APP_PACKAGE_STORE_FILE}"
Delete "$packageFile"
${endif}
!insertmacro moveFile "$packageFile" "$LOCALAPPDATA\${APP_PACKAGE_STORE_FILE}"

${if} $installMode == "all"
SetShellVarContext all
Expand All @@ -84,7 +77,7 @@
${if} $installMode == "all"
SetShellVarContext current
${endif}
!insertmacro copyFile "$EXEPATH" "$APPDATA\${APP_INSTALLER_STORE_FILE}"
!insertmacro copyFile "$EXEPATH" "$LOCALAPPDATA\${APP_INSTALLER_STORE_FILE}"
${if} $installMode == "all"
SetShellVarContext all
${endif}
Expand Down
92 changes: 80 additions & 12 deletions packages/builder-util-runtime/src/httpExecutor.ts
Expand Up @@ -4,7 +4,7 @@ import { createWriteStream } from "fs-extra-p"
import { IncomingMessage, OutgoingHttpHeaders, RequestOptions } from "http"
import { Socket } from "net"
import { Transform } from "stream"
import { parse as parseUrl, URL } from "url"
import { URL } from "url"
import { CancellationToken } from "./CancellationToken"
import { newError } from "./index"
import { ProgressCallbackTransform, ProgressInfo } from "./ProgressCallbackTransform"
Expand Down Expand Up @@ -175,6 +175,72 @@ Please double check that your authentication token is correct. Due to security r
// noinspection JSUnusedLocalSymbols
abstract createRequest(options: any, callback: (response: any) => void): any

async downloadToBuffer(url: URL, options: DownloadOptions): Promise<Buffer> {
return await options.cancellationToken.createPromise<Buffer>((resolve, reject, onCancel) => {
let result: Buffer | null = null
const requestOptions = {
headers: options.headers || undefined,
// because PrivateGitHubProvider requires HttpExecutor.prepareRedirectUrlOptions logic, so, we need to redirect manually
redirect: "manual",
}
configureRequestUrl(url, requestOptions)
configureRequestOptions(requestOptions)
this.doDownload(requestOptions, {
destination: null,
options,
onCancel,
callback: error => {
if (error == null) {
resolve(result!!)
}
else {
reject(error)
}
},
responseHandler: (response, callback) => {
const contentLength = safeGetHeader(response, "content-length")
let position = -1
if (contentLength != null) {
const size = parseInt(contentLength, 10)
if (size > 0) {
if (size > 5242880) {
callback(new Error("Maximum allowed size is 5 MB"))
return
}

result = Buffer.alloc(size)
position = 0
}
}
response.on("data", (chunk: Buffer) => {
if (position !== -1) {
chunk.copy(result!!, position)
position += chunk.length
}
else if (result == null) {
result = chunk
}
else {
if (result.length > 5242880) {
callback(new Error("Maximum allowed size is 5 MB"))
return
}
result = Buffer.concat([result, chunk])
}
})
response.on("end", () => {
if (result != null && position !== -1 && position !== result.length) {
callback(new Error(`Received data length ${position} is not equal to expected ${result.length}`))
}
else {
callback(null)
}
})
},
}, 0)
})
}

protected doDownload(requestOptions: any, options: DownloadCallOptions, redirectCount: number) {
const request = this.createRequest(requestOptions, (response: IncomingMessage) => {
if (response.statusCode! >= 400) {
Expand Down Expand Up @@ -245,19 +311,21 @@ export interface DownloadCallOptions {
}

export function configureRequestOptionsFromUrl(url: string, options: RequestOptions) {
const parsedUrl = parseUrl(url)
options.protocol = parsedUrl.protocol
options.hostname = parsedUrl.hostname
if (parsedUrl.port == null) {
if (options.port != null) {
delete options.port
}
const result = configureRequestOptions(options)
configureRequestUrl(new URL(url), result)
return result
}

export function configureRequestUrl(url: URL, options: RequestOptions): void {
options.protocol = url.protocol
options.hostname = url.hostname
if (url.port) {
options.port = url.port
}
else {
options.port = parsedUrl.port
else if (options.port) {
delete options.port
}
options.path = parsedUrl.path
return configureRequestOptions(options)
options.path = url.pathname + url.search
}

export class DigestTransform extends Transform {
Expand Down
6 changes: 3 additions & 3 deletions packages/builder-util-runtime/src/index.ts
@@ -1,5 +1,5 @@
export { CancellationToken, CancellationError } from "./CancellationToken"
export { HttpError, createHttpError, HttpExecutor, DownloadOptions, DigestTransform, RequestHeaders, safeGetHeader, configureRequestOptions, configureRequestOptionsFromUrl, safeStringifyJson, parseJson } from "./httpExecutor"
export { HttpError, createHttpError, HttpExecutor, DownloadOptions, DigestTransform, RequestHeaders, safeGetHeader, configureRequestOptions, configureRequestOptionsFromUrl, safeStringifyJson, parseJson, configureRequestUrl } from "./httpExecutor"
export { BintrayOptions, GenericServerOptions, GithubOptions, PublishConfiguration, S3Options, SpacesOptions, BaseS3Options, getS3LikeProviderBaseUrl, Publish, githubUrl, PublishProvider, AllPublishOptions } from "./publishOptions"
export { UpdateInfo, UpdateFileInfo, WindowsUpdateInfo, BlockMapDataHolder, PackageFileInfo, ReleaseNoteInfo } from "./updateInfo"
export { parseDn } from "./rfc2253Parser"
Expand All @@ -9,9 +9,9 @@ export { parseXml, XElement } from "./xml"
export { BlockMap } from "./blockMapApi"

// nsis
export const CURRENT_APP_INSTALLER_FILE_NAME = "__installer.exe"
export const CURRENT_APP_INSTALLER_FILE_NAME = "installer.exe"
// nsis-web
export const CURRENT_APP_PACKAGE_FILE_NAME = "__package.7z"
export const CURRENT_APP_PACKAGE_FILE_NAME = "package.7z"

export function asArray<T>(v: null | undefined | T | Array<T>): Array<T> {
if (v == null) {
Expand Down
9 changes: 8 additions & 1 deletion packages/builder-util-runtime/src/publishOptions.ts
Expand Up @@ -13,8 +13,15 @@ export interface PublishConfiguration {

/**
* @private
* win-only
*/
readonly publisherName?: Array<string> | null
publisherName?: Array<string> | null

/**
* @private
* win-only
*/
readonly updaterCacheDirName?: string | null

/**
* Whether to publish auto update info files.
Expand Down
2 changes: 1 addition & 1 deletion packages/builder-util/package.json
Expand Up @@ -11,7 +11,7 @@
"out"
],
"dependencies": {
"app-builder-bin": "2.4.1",
"app-builder-bin": "2.4.3",
"temp-file": "^3.2.0",
"fs-extra-p": "^7.0.0",
"is-ci": "^1.2.1",
Expand Down
9 changes: 7 additions & 2 deletions packages/builder-util/src/util.ts
Expand Up @@ -133,9 +133,14 @@ export function exec(file: string, args?: Array<string> | null, options?: ExecFi
function removeWineSpam(out: string) {
return out.toString()
.split("\n")
.filter(it => !it.includes("wine: cannot find L\"C:\\\\windows\\\\system32\\\\winemenubuilder.exe\"") && !it.includes("err:wineboot:ProcessRunKeys Error running cmd L\"C:\\\\windows\\\\system32\\\\winemenubuilder.exe"))
.filter(it => !it.includes("wine: cannot find L\"C:\\\\windows\\\\system32\\\\winemenubuilder.exe\"")
&& !it.includes("err:wineboot:ProcessRunKeys Error running cmd L\"C:\\\\windows\\\\system32\\\\winemenubuilder.exe")
&& !it.includes("Wine cannot find the FreeType font library.")
&& !it.includes("use TrueType fonts please install a version of FreeType greater than")
&& !it.includes("or equal to 2.0.5.")
&& !it.includes("http://www.freetype.org")
)
.join("\n")

}

export interface ExtraSpawnOptions {
Expand Down
2 changes: 1 addition & 1 deletion packages/electron-builder/package.json
Expand Up @@ -13,7 +13,7 @@
},
"repository": "electron-userland/electron-builder",
"engines": {
"node": ">=6.11.4"
"node": ">=8.12.0"
},
"keywords": [
"electron",
Expand Down
6 changes: 3 additions & 3 deletions packages/electron-updater/src/AppImageUpdater.ts
Expand Up @@ -50,11 +50,11 @@ export class AppImageUpdater extends BaseUpdater {
let isDownloadFull = false
try {
await new FileWithEmbeddedBlockMapDifferentialDownloader(fileInfo.info, this.httpExecutor, {
newUrl: fileInfo.url.href,
newUrl: fileInfo.url,
oldFile,
logger: this._logger,
newFile: updateFile,
useMultipleRangeRequest: provider.useMultipleRangeRequest,
isUseMultipleRangeRequest: provider.isUseMultipleRangeRequest,
requestHeaders: downloadUpdateOptions.requestHeaders,
})
.download()
Expand All @@ -66,7 +66,7 @@ export class AppImageUpdater extends BaseUpdater {
}

if (isDownloadFull) {
await this.httpExecutor.download(fileInfo.url.href, updateFile, downloadOptions)
await this.httpExecutor.download(fileInfo.url, updateFile, downloadOptions)
}

await chmod(updateFile, 0o755)
Expand Down

0 comments on commit c01b7c0

Please sign in to comment.