Skip to content

Commit

Permalink
feat: proton support (part 2)
Browse files Browse the repository at this point in the history
  • Loading branch information
develar committed Mar 19, 2018
1 parent f20d7cc commit fc918c7
Show file tree
Hide file tree
Showing 14 changed files with 1,541 additions and 187 deletions.
1 change: 1 addition & 0 deletions .idea/electron-builder.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@
"whitespace": "^2.1.0",
"worker-farm": "^1.6.0"
},
"/////": "proton-native is required only for proton tests",
"optionalDependencies": {
"proton-native": "1.0.15"
},
"jest": {
"testEnvironment": "node",
"roots": [
Expand Down
7 changes: 7 additions & 0 deletions packages/electron-builder-lib/src/Framework.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AsarIntegrity } from "./asar/integrity"
import { PlatformPackager } from "./platformPackager"

export interface Framework {
Expand All @@ -8,6 +9,8 @@ export interface Framework {
readonly isNpmRebuildRequired: boolean

unpackFramework(options: UnpackFrameworkTaskOptions): Promise<any>

beforeCopyExtraFiles?(packager: PlatformPackager<any>, appOutDir: string, asarIntegrity: AsarIntegrity | null): Promise<any>
}

export interface UnpackFrameworkTaskOptions {
Expand All @@ -16,4 +19,8 @@ export interface UnpackFrameworkTaskOptions {
readonly platformName: string
readonly arch: string
readonly version: string
}

export function isElectronBased(framework: Framework) {
return framework.name === "electron" || framework.name === "muon"
}
45 changes: 13 additions & 32 deletions packages/electron-builder-lib/src/ProtonFramework.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,32 @@
import { chmod, copyFile, ensureDir, writeFile } from "fs-extra-p"
import { getBin } from "builder-util/out/binDownload"
import { Framework } from "./Framework"
import { Framework, AppInfo } from "./index"
import * as path from "path"
import MacPackager from "./macPackager"
import { build as buildPlist } from "plist"

export function createProtonFrameworkSupport(nodeVersion: string): Framework {
export function createProtonFrameworkSupport(nodeVersion: string, appInfo: AppInfo): Framework {
const appFilename = appInfo.productFilename
const appBundleFileName = `${appFilename}.app`
return {
name: "proton",
version: nodeVersion,
distMacOsAppName: "Proton.app",
distMacOsAppName: appBundleFileName,
isNpmRebuildRequired: false,
unpackFramework: async options => {
const appContentsDir = path.join(options.appOutDir, "Proton.app/Contents")
const appContentsDir = path.join(options.appOutDir, appBundleFileName, "Contents")
await ensureDir(path.join(appContentsDir, "Resources"))
await ensureDir(path.join(appContentsDir, "MacOS"))
await copyFile(path.join(await getBin("node", `${nodeVersion}-darwin-x64`, null), "node"), path.join(appContentsDir, "MacOS", "node"))

// todo rename
const appName = "Proton.app"

// todo icon
const appInfo = options.packager.appInfo
await writeFile(path.join(appContentsDir, "Info.plist"), `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>${appName}</string>
<key>CFBundleExecutable</key>
<string>main</string>
<key>CFBundleIconFile</key>
<string>Icon</string>
<key>CFBundleIdentifier</key>
<string>${appInfo.macBundleIdentifier}</string>
<key>CFBundleVersion</key>
<string>${appInfo.version}</string>
<key>CFBundleGetInfoString</key>
<string>0.1 built by me</string>
<key>CFBundleShortVersionString</key>
<string>${(options.packager as MacPackager).platformSpecificBuildOptions.bundleShortVersion || appInfo.version}</string>
</dict>
</plist>
`)
const appMain = ""
const appPlist: any = {
CFBundleExecutable: "main",
}
await (options.packager as MacPackager).applyCommonInfo(appPlist)
await writeFile(path.join(appContentsDir, "Info.plist"), buildPlist(appPlist))
await writeFile(path.join(appContentsDir, "MacOS", "main"), `#!/bin/sh
DIR=$(dirname "$0")
"$DIR/node" "$DIR/../Resources/app/${appMain}"
"$DIR/node" "$DIR/../Resources/app/${options.packager.info.metadata.main || "index.js"}"
`, {mode: 0o755})
await chmod(path.join(appContentsDir, "MacOS", "main"), 0o755)
},
Expand Down
50 changes: 47 additions & 3 deletions packages/electron-builder-lib/src/electron/ElectronFramework.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { path7za } from "7zip-bin"
import BluebirdPromise from "bluebird-lst"
import { debug7zArgs, exec, isEnvTrue, log, spawn } from "builder-util"
import { copyDir, DO_NOT_USE_HARD_LINKS, statOrNull } from "builder-util/out/fs"
import { chmod, emptyDir } from "fs-extra-p"
import { debug7zArgs, exec, isEnvTrue, log, spawn, asArray } from "builder-util"
import { copyDir, DO_NOT_USE_HARD_LINKS, statOrNull, CONCURRENCY } from "builder-util/out/fs"
import { chmod, emptyDir, readdir, remove } from "fs-extra-p"
import { Lazy } from "lazy-val"
import * as path from "path"
import { AsarIntegrity } from "../asar/integrity"
import { Configuration, ElectronDownloadOptions } from "../configuration"
import { Platform } from "../core"
import { Framework, UnpackFrameworkTaskOptions } from "../Framework"
import MacPackager from "../macPackager"
import { Packager } from "../packager"
import { PlatformPackager } from "../platformPackager"
import { createMacApp } from "./electronMac"
import { computeElectronVersion, getElectronVersionFromInstalled } from "./electronVersion"

interface InternalElectronDownloadOptions extends ElectronDownloadOptions {
Expand All @@ -26,7 +30,46 @@ function createDownloadOpts(opts: Configuration, platform: string, arch: string,
}
}

async function beforeCopyExtraFiles(packager: PlatformPackager<any>, appOutDir: string, asarIntegrity: AsarIntegrity | null) {
if (packager.platform !== Platform.MAC) {
return
}

await createMacApp(packager as MacPackager, appOutDir, asarIntegrity)

const wantedLanguages = asArray(packager.platformSpecificBuildOptions.electronLanguages)
if (wantedLanguages.length === 0) {
return
}

// noinspection SpellCheckingInspection
const langFileExt = ".lproj"
const resourcesDir = packager.getResourcesDir(appOutDir)
await BluebirdPromise.map(readdir(resourcesDir), file => {
if (!file.endsWith(langFileExt)) {
return
}

const language = file.substring(0, file.length - langFileExt.length)
if (!wantedLanguages.includes(language)) {
return remove(path.join(resourcesDir, file))
}
return
}, CONCURRENCY)
}

export async function createElectronFrameworkSupport(configuration: Configuration, packager: Packager): Promise<Framework> {
if (configuration.muonVersion != null) {
return {
name: "muon",
version: configuration.muonVersion!!,
distMacOsAppName: "Brave.app",
unpackFramework: unpackMuon,
isNpmRebuildRequired: true,
beforeCopyExtraFiles,
}
}

let version = configuration.electronVersion
if (version == null) {
// for prepacked app asar no dev deps in the app.asar
Expand All @@ -48,6 +91,7 @@ export async function createElectronFrameworkSupport(configuration: Configuratio
distMacOsAppName: "Electron.app",
isNpmRebuildRequired: true,
unpackFramework: options => unpack(options.packager, options.appOutDir, options.platformName, createDownloadOpts(options.packager.config, options.platformName, options.arch, version!!)),
beforeCopyExtraFiles,
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import BluebirdPromise from "bluebird-lst"
import { asArray, getPlatformIconFileName, InvalidConfigurationError, log, use } from "builder-util"
import { asArray, getPlatformIconFileName, InvalidConfigurationError, log } from "builder-util"
import { copyFile, copyOrLinkFile, unlinkIfExists } from "builder-util/out/fs"
import { readFile, rename, utimes, writeFile } from "fs-extra-p"
import * as path from "path"
import { build as buildPlist, parse as parsePlist } from "plist"
import { filterCFBundleIdentifier } from "../appInfo"
import { AsarIntegrity } from "../asar/integrity"
import { normalizeExt, PlatformPackager } from "../platformPackager"
import MacPackager from "../macPackager"
import { normalizeExt } from "../platformPackager"

function doRename(basePath: string, oldName: string, newName: string) {
return rename(path.join(basePath, oldName), path.join(basePath, newName))
Expand All @@ -21,11 +22,11 @@ function moveHelpers(frameworksPath: string, appName: string, prefix: string): P
}

/** @internal */
export async function createMacApp(packager: PlatformPackager<any>, appOutDir: string, asarIntegrity: AsarIntegrity | null) {
export async function createMacApp(packager: MacPackager, appOutDir: string, asarIntegrity: AsarIntegrity | null) {
const appInfo = packager.appInfo
const appFilename = appInfo.productFilename

const contentsPath = path.join(appOutDir, packager.electronDistMacOsAppName, "Contents")
const contentsPath = path.join(appOutDir, packager.info.framework.distMacOsAppName, "Contents")
const frameworksPath = path.join(contentsPath, "Frameworks")

const appPlistFilename = path.join(contentsPath, "Info.plist")
Expand All @@ -50,23 +51,15 @@ export async function createMacApp(packager: PlatformPackager<any>, appOutDir: s
Object.assign(appPlist, macOptions.extendInfo)
}

const appBundleIdentifier = appInfo.macBundleIdentifier

const oldHelperBundleId = (buildMetadata as any)["helper-bundle-id"]
if (oldHelperBundleId != null) {
log.warn("build.helper-bundle-id is deprecated, please set as build.mac.helperBundleId")
}
const helperBundleIdentifier = filterCFBundleIdentifier(packager.platformSpecificBuildOptions.helperBundleId || oldHelperBundleId || `${appBundleIdentifier}.helper`)
const helperBundleIdentifier = filterCFBundleIdentifier(packager.platformSpecificBuildOptions.helperBundleId || oldHelperBundleId || `${appInfo.macBundleIdentifier}.helper`)

const icon = await packager.getIconPath()
const oldIcon = appPlist.CFBundleIconFile
if (icon != null) {
appPlist.CFBundleIconFile = `${appFilename}.icns`
}

appPlist.CFBundleDisplayName = appInfo.productName
appPlist.CFBundleIdentifier = appBundleIdentifier
appPlist.CFBundleName = appInfo.productName
await packager.applyCommonInfo(appPlist)

// https://github.com/electron-userland/electron-builder/issues/1278
appPlist.CFBundleExecutable = !appFilename.endsWith(" Helper") ? appFilename : appFilename.substring(0, appFilename.length - " Helper".length)
Expand All @@ -83,13 +76,6 @@ export async function createMacApp(packager: PlatformPackager<any>, appOutDir: s
helperEHPlist.CFBundleIdentifier = `${helperBundleIdentifier}.EH`
helperNPPlist.CFBundleIdentifier = `${helperBundleIdentifier}.NP`

appPlist.CFBundleShortVersionString = macOptions.bundleShortVersion || appInfo.version
appPlist.CFBundleVersion = appInfo.buildVersion

if (macOptions.minimumSystemVersion != null) {
appPlist.LSMinimumSystemVersion = macOptions.minimumSystemVersion
}

const protocols = asArray(buildMetadata.protocols).concat(asArray(packager.platformSpecificBuildOptions.protocols))
if (protocols.length > 0) {
appPlist.CFBundleURLTypes = protocols.map(protocol => {
Expand Down Expand Up @@ -132,9 +118,6 @@ export async function createMacApp(packager: PlatformPackager<any>, appOutDir: s
})
}

use(packager.platformSpecificBuildOptions.category || (buildMetadata as any).category, it => appPlist.LSApplicationCategoryType = it)
appPlist.NSHumanReadableCopyright = appInfo.copyright

if (asarIntegrity != null) {
appPlist.AsarIntegrity = JSON.stringify(asarIntegrity)
}
Expand All @@ -149,12 +132,13 @@ export async function createMacApp(packager: PlatformPackager<any>, appOutDir: s
unlinkIfExists(path.join(appOutDir, "LICENSES.chromium.html")),
]

const icon = await packager.getIconPath()
if (icon != null) {
promises.push(unlinkIfExists(path.join(resourcesPath, oldIcon)))
promises.push(copyFile(icon, path.join(resourcesPath, appPlist.CFBundleIconFile)))
}

await BluebirdPromise.all(promises)
await Promise.all(promises)

await moveHelpers(frameworksPath, appFilename, packager.electronDistMacOsExecutableName)
const appPath = path.join(appOutDir, `${appFilename}.app`)
Expand Down
1 change: 1 addition & 0 deletions packages/electron-builder-lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export { CancellationToken, ProgressInfo } from "builder-util-runtime"
export { PublishOptions, UploadTask } from "electron-publish"
export { PublishManager } from "./publish/PublishManager"
export { PlatformPackager } from "./platformPackager"
export { Framework } from "./Framework"
export { buildForge, ForgeOptions } from "./forge-maker"

export async function build(options: PackagerOptions & PublishOptions, packager: Packager = new Packager(options)): Promise<Array<string>> {
Expand Down
49 changes: 22 additions & 27 deletions packages/electron-builder-lib/src/macPackager.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
import BluebirdPromise from "bluebird-lst"
import { deepAssign, Arch, AsyncTaskManager, exec, InvalidConfigurationError, log } from "builder-util"
import { deepAssign, Arch, AsyncTaskManager, exec, InvalidConfigurationError, log, use } from "builder-util"
import { signAsync, SignOptions } from "electron-osx-sign"
import { ensureDir, readdir, remove } from "fs-extra-p"
import { ensureDir } from "fs-extra-p"
import { Lazy } from "lazy-val"
import * as path from "path"
import * as semver from "semver"
import { asArray } from "builder-util-runtime/out"
import { AppInfo } from "./appInfo"
import { AsarIntegrity } from "./asar/integrity"
import { appleCertificatePrefixes, CertType, CodeSigningInfo, createKeychain, findIdentity, Identity, isSignAllowed, reportError } from "./codeSign"
import { DIR_TARGET, Platform, Target } from "./core"
import { MacConfiguration, MasConfiguration } from "./options/macOptions"
import { Packager } from "./packager"
import { createMacApp } from "./electron/mac"
import { chooseNotNull, PlatformPackager } from "./platformPackager"
import { ArchiveTarget } from "./targets/ArchiveTarget"
import { PkgTarget, prepareProductBuildArgs } from "./targets/pkg"
import { createCommonTarget, NoOpTarget } from "./targets/targetFactory"
import { CONCURRENCY } from "builder-util/out/fs"

export default class MacPackager extends PlatformPackager<MacConfiguration> {
readonly codeSigningInfo = new Lazy<CodeSigningInfo>(() => {
Expand Down Expand Up @@ -252,35 +247,35 @@ export default class MacPackager extends PlatformPackager<MacConfiguration> {
}

public getElectronSrcDir(dist: string) {
return path.resolve(this.projectDir, dist, this.electronDistMacOsAppName)
return path.resolve(this.projectDir, dist, this.info.framework.distMacOsAppName)
}

public getElectronDestinationDir(appOutDir: string) {
return path.join(appOutDir, this.electronDistMacOsAppName)
return path.join(appOutDir, this.info.framework.distMacOsAppName)
}

protected async beforeCopyExtraFiles(appOutDir: string, asarIntegrity: AsarIntegrity | null): Promise<any> {
await createMacApp(this, appOutDir, asarIntegrity)
// todo fileAssociations
async applyCommonInfo(appPlist: any) {
const appInfo = this.appInfo
const icon = await this.getIconPath()
if (icon != null) {
appPlist.CFBundleIconFile = `${appInfo.productFilename}.icns`
}
appPlist.CFBundleName = appInfo.productName
appPlist.CFBundleDisplayName = appInfo.productName

const wantedLanguages = asArray(this.platformSpecificBuildOptions.electronLanguages)
if (wantedLanguages.length === 0) {
return
const minimumSystemVersion = this.platformSpecificBuildOptions.minimumSystemVersion
if (minimumSystemVersion != null) {
appPlist.LSMinimumSystemVersion = minimumSystemVersion
}

// noinspection SpellCheckingInspection
const langFileExt = ".lproj"
const resourcesDir = this.getResourcesDir(appOutDir)
await BluebirdPromise.map(readdir(resourcesDir), file => {
if (!file.endsWith(langFileExt)) {
return
}
appPlist.CFBundleIdentifier = appInfo.macBundleIdentifier

const language = file.substring(0, file.length - langFileExt.length)
if (!wantedLanguages.includes(language)) {
return remove(path.join(resourcesDir, file))
}
return
}, CONCURRENCY)
appPlist.CFBundleShortVersionString = this.platformSpecificBuildOptions.bundleShortVersion || appInfo.version
appPlist.CFBundleVersion = appInfo.buildVersion

use(this.platformSpecificBuildOptions.category || (this.config as any).category, it => appPlist.LSApplicationCategoryType = it)
appPlist.NSHumanReadableCopyright = appInfo.copyright
}
}

Expand Down
Loading

0 comments on commit fc918c7

Please sign in to comment.