Skip to content

Commit

Permalink
Merge pull request #807 from malept/login-helper
Browse files Browse the repository at this point in the history
Add MAS Login Helper support
  • Loading branch information
malept committed Feb 27, 2018
2 parents cdd6709 + c82cc36 commit a7437b9
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 32 deletions.
72 changes: 56 additions & 16 deletions mac.js
Expand Up @@ -84,6 +84,14 @@ class MacApp extends App {
return path.join(this.contentsPath, 'Frameworks')
}

get loginItemsPath () {
return path.join(this.contentsPath, 'Library', 'LoginItems')
}

get loginHelperPath () {
return path.join(this.loginItemsPath, 'Electron Login Helper.app')
}

updatePlist (base, displayName, identifier, name) {
return Object.assign(base, {
CFBundleDisplayName: displayName,
Expand Down Expand Up @@ -130,17 +138,19 @@ class MacApp extends App {
}

ehPlistFilename (helper) {
return path.join(this.frameworksPath, helper, 'Contents', 'Info.plist')
return this.helperPlistFilename(path.join(this.frameworksPath, helper))
}

updatePlistFiles () {
helperPlistFilename (helperApp) {
return path.join(helperApp, 'Contents', 'Info.plist')
}

determinePlistFilesToUpdate () {
const appPlistFilename = path.join(this.contentsPath, 'Info.plist')
const helperPlistFilename = this.ehPlistFilename('Electron Helper.app')
const helperEHPlistFilename = this.ehPlistFilename('Electron Helper EH.app')
const helperNPPlistFilename = this.ehPlistFilename('Electron Helper NP.app')

const appBundleIdentifier = filterCFBundleIdentifier(this.opts.appBundleId || this.defaultBundleName)
this.helperBundleIdentifier = filterCFBundleIdentifier(this.opts.helperBundleId || `${appBundleIdentifier}.helper`)
const loginHelperPlistFilename = this.helperPlistFilename(this.loginHelperPath)

const plists = [
[appPlistFilename, 'appPlist'],
Expand All @@ -149,14 +159,39 @@ class MacApp extends App {
[helperNPPlistFilename, 'helperNPPlist']
]

return Promise.all(plists.map(plistArgs => this.loadPlist.apply(this, plistArgs)))
.then(() => this.extendAppPlist(this.opts.extendInfo))
return fs.pathExists(loginHelperPlistFilename)
.then(exists => {
if (exists) {
plists.push([loginHelperPlistFilename, 'loginHelperPlist'])
}
return plists
})
}

updatePlistFiles () {
let plists

const appBundleIdentifier = filterCFBundleIdentifier(this.opts.appBundleId || this.defaultBundleName)
this.helperBundleIdentifier = filterCFBundleIdentifier(this.opts.helperBundleId || `${appBundleIdentifier}.helper`)

return this.determinePlistFilesToUpdate()
.then(plistsToUpdate => {
plists = plistsToUpdate
return Promise.all(plists.map(plistArgs => this.loadPlist.apply(this, plistArgs)))
}).then(() => this.extendAppPlist(this.opts.extendInfo))
.then(() => {
this.appPlist = this.updatePlist(this.appPlist, this.executableName, appBundleIdentifier, this.appName)
this.helperPlist = this.updateHelperPlist(this.helperPlist)
this.helperEHPlist = this.updateHelperPlist(this.helperEHPlist, 'EH')
this.helperNPPlist = this.updateHelperPlist(this.helperNPPlist, 'NP')

if (this.loginHelperPlist) {
const loginHelperName = common.sanitizeAppName(`${this.appName} Login Helper`)
this.loginHelperPlist.CFBundleExecutable = loginHelperName
this.loginHelperPlist.CFBundleIdentifier = `${appBundleIdentifier}.loginhelper`
this.loginHelperPlist.CFBundleName = loginHelperName
}

if (this.appVersion) {
this.appPlist.CFBundleShortVersionString = this.appPlist.CFBundleVersion = '' + this.appVersion
}
Expand Down Expand Up @@ -186,15 +221,20 @@ class MacApp extends App {
}

moveHelpers () {
return Promise.all([' Helper', ' Helper EH', ' Helper NP'].map((suffix) => {
const originalBasename = `Electron${suffix}`
const newBasename = `${common.sanitizeAppName(this.appName)}${suffix}`
const originalAppname = `${originalBasename}.app`
const executableBasePath = path.join(this.frameworksPath, originalAppname, 'Contents', 'MacOS')

return this.relativeRename(executableBasePath, originalBasename, newBasename)
.then(() => this.relativeRename(this.frameworksPath, originalAppname, `${newBasename}.app`))
}))
const helpers = [' Helper', ' Helper EH', ' Helper NP']
return Promise.all(helpers.map(suffix => this.moveHelper(this.frameworksPath, suffix)))
.then(() => fs.pathExists(this.loginItemsPath))
.then(exists => exists ? this.moveHelper(this.loginItemsPath, ' Login Helper') : null)
}

moveHelper (helperDirectory, suffix) {
const originalBasename = `Electron${suffix}`
const newBasename = `${common.sanitizeAppName(this.appName)}${suffix}`
const originalAppname = `${originalBasename}.app`
const executableBasePath = path.join(helperDirectory, originalAppname, 'Contents', 'MacOS')

return this.relativeRename(executableBasePath, originalBasename, newBasename)
.then(() => this.relativeRename(helperDirectory, originalAppname, `${newBasename}.app`))
}

copyIcon () {
Expand Down
45 changes: 31 additions & 14 deletions test/_setup.js
Expand Up @@ -13,33 +13,50 @@ function fixtureSubdir (subdir) {
return path.join(__dirname, 'fixtures', subdir)
}

/**
* Skip testing darwin/mas target on Windows since Electron Packager itself skips it
* (see https://github.com/electron-userland/electron-packager/issues/71)
*/
function skipDownloadingMacZips (platform, arch) {
return common.isPlatformMac(platform) && process.platform === 'win32'
}

function downloadAll (version) {
console.log(`Calling electron-download for ${version} before running tests...`)
const combinations = download.createDownloadCombos({electronVersion: config.version, all: true}, targets.officialPlatforms, targets.officialArchs, (platform, arch) => {
// Skip testing darwin/mas target on Windows since electron-packager itself skips it
// (see https://github.com/electron-userland/electron-packager/issues/71)
return common.isPlatformMac(platform) && process.platform === 'win32'
})
const combinations = download.createDownloadCombos({electronVersion: config.version, all: true}, targets.officialPlatforms, targets.officialArchs, skipDownloadingMacZips)

return Promise.all(combinations.map(combination => downloadElectronZip(version, combination)))
}

return Promise.all(combinations.map(combination => {
return download.downloadElectronZip(Object.assign({}, combination, {
cache: path.join(os.homedir(), '.electron'),
quiet: !!process.env.CI,
version: version
}))
function downloadElectronZip (version, options) {
return download.downloadElectronZip(Object.assign({}, options, {
cache: path.join(os.homedir(), '.electron'),
quiet: !!process.env.CI,
version: version
}))
}

// Download all Electron distributions before running tests to avoid timing out due to network
// speed. Most tests run with the config.json version, but we have some tests using 0.37.4, and an
// electron module specific test using 1.3.1.
function downloadMASLoginHelperElectronZip () {
if (process.platform !== 'win32') {
const version = '2.0.0-beta.1'
console.log(`Calling electron-download for ${version} (MAS only) before running tests...`)
return downloadElectronZip(version, { platform: 'mas', arch: 'x64' })
}
}

/**
* Download all Electron distributions before running tests to avoid timing out due to network
* speed. Most tests run with the config.json version, but we have some tests using 0.37.4, an
* `electron` module specific test using 1.3.1., and an MAS-specific test using 2.0.0-beta.1.
*/
function preDownloadElectron () {
const versions = [
config.version,
'0.37.4',
'1.3.1'
]
return Promise.all(versions.map(downloadAll))
.then(downloadMASLoginHelperElectronZip)
}

function npmInstallForFixture (fixture) {
Expand Down
30 changes: 28 additions & 2 deletions test/mas.js
@@ -1,14 +1,16 @@
'use strict'

const config = require('./config.json')
const fs = require('fs-extra')
const packager = require('..')
const path = require('path')
const plist = require('plist')
const util = require('./_util')

if (!(process.env.CI && process.platform === 'win32')) {
const masOpts = {
name: 'masTest',
dir: util.fixtureSubdir('basic'),
electronVersion: config.version,
electronVersion: '2.0.0-beta.1',
arch: 'x64',
platform: 'mas'
}
Expand All @@ -29,4 +31,28 @@ if (!(process.env.CI && process.platform === 'win32')) {
).then(finalize)
.catch(finalize)
})

util.packagerTest('update Login Helper if it exists', (t, baseOpts) => {
let contentsPath
let plistPath
const helperName = `${masOpts.name} Login Helper`
return packager(Object.assign({}, baseOpts, masOpts))
.then(paths => {
contentsPath = path.join(paths[0], `${masOpts.name}.app`, 'Contents', 'Library', 'LoginItems', `${helperName}.app`, 'Contents')
return fs.pathExists(contentsPath)
}).then(exists => {
t.true(exists, 'renamed Login Helper app exists')
plistPath = path.join(contentsPath, 'Info.plist')
return fs.pathExists(contentsPath)
}).then(exists => {
t.true(exists, 'Login Helper Info.plist exists')
return fs.readFile(plistPath, 'utf8')
}).then(plistXML => {
const plistData = plist.parse(plistXML)
t.is(plistData.CFBundleExecutable, helperName, 'CFBundleExecutable is renamed Login Helper')
t.is(plistData.CFBundleName, helperName, 'CFBundleName is renamed Login Helper')
t.is(plistData.CFBundleIdentifier, 'com.electron.mastest.loginhelper')
return fs.pathExists(path.join(contentsPath, 'MacOS', helperName))
}).then(exists => t.true(exists, 'renamed Login Helper executable exists'))
})
}

0 comments on commit a7437b9

Please sign in to comment.