Skip to content

Commit

Permalink
Merge pull request #474 from malept/add-arm-support
Browse files Browse the repository at this point in the history
Add Linux ARMv7 support
  • Loading branch information
malept authored Sep 3, 2016
2 parents bc0085d + 0ef914f commit 65c5b67
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 100 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
### Added

* `win32metadata` option (#331, #463)
* `linux` platform, `armv7l` arch support (#106, #474)

### Changed

* `all` now includes the `linux` platform, `armv7l` arch combination
* Default the `platform` option to the host platform (#464)
* Default the `arch` option to the host arch (#36, #464)
* Default the `prune` option to `true` (#235, #472)
Expand Down
52 changes: 41 additions & 11 deletions common.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
const asar = require('asar')
const child = require('child_process')
const debug = require('debug')('electron-packager')
const download = require('electron-download')
const fs = require('fs-extra')
const ignore = require('./ignore')
const minimist = require('minimist')
const os = require('os')
const path = require('path')
const sanitize = require('sanitize-filename')
const semver = require('semver')
const series = require('run-series')

const archs = ['ia32', 'x64']
const archs = ['ia32', 'x64', 'armv7l']
const platforms = ['darwin', 'linux', 'mas', 'win32']

function parseCLIArgs (argv) {
Expand Down Expand Up @@ -81,6 +83,10 @@ function asarApp (appPath, asarOptions, cb) {
})
}

function isPlatformMac (platform) {
return platform === 'darwin' || platform === 'mas'
}

function sanitizeAppName (name) {
return sanitize(name, {replacement: '-'})
}
Expand Down Expand Up @@ -116,28 +122,52 @@ function createAsarOpts (opts) {
return asarOptions
}

function createDownloadOpts (opts, platform, arch) {
let downloadOpts = Object.assign({}, opts.download)

subOptionWarning(downloadOpts, 'download', 'platform', platform)
subOptionWarning(downloadOpts, 'download', 'arch', arch)
subOptionWarning(downloadOpts, 'download', 'version', opts.version)

return downloadOpts
}

module.exports = {
archs: archs,
platforms: platforms,

parseCLIArgs: parseCLIArgs,

isPlatformMac: function isPlatformMac (platform) {
return platform === 'darwin' || platform === 'mas'
},
isPlatformMac: isPlatformMac,

subOptionWarning: subOptionWarning,

createAsarOpts: createAsarOpts,
createDownloadOpts: createDownloadOpts,
createDownloadCombos: function createDownloadCombos (opts, selectedPlatforms, selectedArchs, ignoreFunc) {
let combinations = []
for (let arch of selectedArchs) {
for (let platform of selectedPlatforms) {
// Electron does not have 32-bit releases for Mac OS X, so skip that combination
if (isPlatformMac(platform) && arch === 'ia32') continue
// Electron only has armv7l releases for Linux
if (arch === 'armv7l' && platform !== 'linux') continue
if (typeof ignoreFunc === 'function' && ignoreFunc(platform, arch)) continue
combinations.push(createDownloadOpts(opts, platform, arch))
}
}

createDownloadOpts: function createDownloadOpts (opts, platform, arch) {
let downloadOpts = opts.download || {}

subOptionWarning(downloadOpts, 'download', 'platform', platform)
subOptionWarning(downloadOpts, 'download', 'arch', arch)
subOptionWarning(downloadOpts, 'download', 'version', opts.version)
return combinations
},

return downloadOpts
downloadElectronZip: function downloadElectronZip (downloadOpts, cb) {
// armv7l builds have only been backfilled for Electron >= 1.0.0.
// See: https://github.com/electron/electron/pull/6986
if (downloadOpts.arch === 'armv7l' && semver.lt(downloadOpts.version, '1.0.0')) {
downloadOpts.arch = 'arm'
}
debug(`Downloading Electron with options ${JSON.stringify(downloadOpts)}`)
download(downloadOpts, cb)
},

generateFinalBasename: generateFinalBasename,
Expand Down
2 changes: 1 addition & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ The release version of the application. By default the `version` property in the

*String* (default: the arch of the host computer running Node)

Allowed values: `ia32`, `x64`, `all`
Allowed values: `ia32`, `x64`, `armv7l`, `all`

The target system architecture(s) to build for.
Not required if the [`all`](#all) option is set.
Expand Down
58 changes: 9 additions & 49 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

const common = require('./common')
const debug = require('debug')('electron-packager')
const download = require('electron-download')
const extract = require('extract-zip')
const fs = require('fs-extra')
const getPackageInfo = require('get-package-info')
Expand All @@ -12,43 +11,14 @@ const os = require('os')
const path = require('path')
const resolve = require('resolve')
const series = require('run-series')

var supportedArchs = common.archs.reduce(function (result, arch) {
result[arch] = 1
return result
}, {})

var supportedPlatforms = {
// Maps to module ID for each platform (lazy-required if used)
darwin: './mac',
linux: './linux',
mas: './mac', // map to darwin
win32: './win32'
}
const targets = require('./targets')

function debugHostInfo () {
debug(`Electron Packager ${metadata.version}`)
debug(`Node ${process.version}`)
debug(`Host Operating system: ${process.platform} (${process.arch})`)
}

function validateList (list, supported, name) {
// Validates list of architectures or platforms.
// Returns a normalized array if successful, or an error message string otherwise.

if (!list) return `Must specify ${name}`
if (list === 'all') return Object.keys(supported)

if (!Array.isArray(list)) list = list.split(',')
for (var i = list.length; i--;) {
if (!supported[list[i]]) {
return `Unsupported ${name} ${list[i]}; must be one of: ${Object.keys(supported).join(', ')}`
}
}

return list
}

function getMetadata (opts, dir, cb) {
var props = []
if (!opts.name) props.push(['productName', 'name'])
Expand Down Expand Up @@ -121,30 +91,20 @@ function createSeries (opts, archs, platforms) {
})
}

var combinations = []
archs.forEach(function (arch) {
platforms.forEach(function (platform) {
// Electron does not have 32-bit releases for Mac OS X, so skip that combination
if (common.isPlatformMac(platform) && arch === 'ia32') return
combinations.push(common.createDownloadOpts(opts, platform, arch))
})
})

var tasks = []
var useTempDir = opts.tmpdir !== false
if (useTempDir) {
tasks.push(function (cb) {
fs.remove(tempBase, cb)
})
}
return tasks.concat(combinations.map(function (combination) {
return tasks.concat(common.createDownloadCombos(opts, platforms, archs).map(combination => {
var arch = combination.arch
var platform = combination.platform
var version = combination.version

return function (callback) {
debug(`Downloading Electron with options ${JSON.stringify(combination)}`)
download(combination, function (err, zipPath) {
return (callback) => {
common.downloadElectronZip(combination, (err, zipPath) => {
if (err) return callback(err)

function createApp (comboOpts) {
Expand Down Expand Up @@ -176,7 +136,7 @@ function createSeries (opts, archs, platforms) {
}
}
], function () {
require(supportedPlatforms[platform]).createApp(comboOpts, buildDir, callback)
require(targets.supportedPlatforms[platform]).createApp(comboOpts, buildDir, callback)
})
}

Expand Down Expand Up @@ -229,10 +189,10 @@ module.exports = function packager (opts, cb) {
debugHostInfo()
if (debug.enabled) debug(`Packager Options: ${JSON.stringify(opts)}`)

var archs = validateList(opts.all ? 'all' : opts.arch || process.arch, supportedArchs, 'arch')
var platforms = validateList(opts.all ? 'all' : opts.platform || process.platform, supportedPlatforms, 'platform')
if (!Array.isArray(archs)) return cb(new Error(archs))
if (!Array.isArray(platforms)) return cb(new Error(platforms))
let archs = targets.validateListFromOptions(opts, targets.supportedArchs, 'arch')
let platforms = targets.validateListFromOptions(opts, targets.supportedPlatforms, 'platform')
if (!Array.isArray(archs)) return cb(archs)
if (!Array.isArray(platforms)) return cb(platforms)

debug(`Target Platforms: ${platforms.join(', ')}`)
debug(`Target Architectures: ${archs.join(', ')}`)
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"rcedit": "^0.7.0",
"resolve": "^1.1.6",
"run-series": "^1.1.1",
"sanitize-filename": "^1.6.0"
"sanitize-filename": "^1.6.0",
"semver": "^5.3.0"
},
"devDependencies": {
"buffer-equal": "^1.0.0",
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ It generates executables/bundles for the following **target** platforms:

* Windows (also known as `win32`, for both 32/64 bit)
* OS X (also known as `darwin`) / [Mac App Store](http://electron.atom.io/docs/v0.36.0/tutorial/mac-app-store-submission-guide/) (also known as `mas`)<sup>*</sup>
* Linux (for both x86/x86_64)
* Linux (for x86, x86_64, and armv7l architectures)

<sup>*</sup> *Note for OS X / MAS target bundles: the `.app` bundle can only be signed when building on a host OS X platform.*

Expand Down
35 changes: 35 additions & 0 deletions targets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict'

const common = require('./common')

module.exports = {
supportedArchs: common.archs.reduce((result, arch) => {
result[arch] = true
return result
}, {}),
// Maps to module filename for each platform (lazy-required if used)
supportedPlatforms: {
darwin: './mac',
linux: './linux',
mas: './mac', // map to darwin
win32: './win32'
},

// Validates list of architectures or platforms.
// Returns a normalized array if successful, or throws an Error.
validateListFromOptions: function validateListFromOptions (opts, supported, name) {
if (opts.all) return Object.keys(supported)

let list = opts[name] || process[name]
if (list === 'all') return Object.keys(supported)

if (!Array.isArray(list)) list = list.split(',')
for (let value of list) {
if (!supported[value]) {
return new Error(`Unsupported ${name}=${value}; must be one of: ${Object.keys(supported).join(', ')}`)
}
}

return list
}
}
10 changes: 2 additions & 8 deletions test/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,11 +446,8 @@ test('building for Linux target sanitizes binary name', (t) => {
util.teardown()

util.setup()
test('fails with invalid arch', function (t) {
test('fails with invalid arch', (t) => {
var opts = {
name: 'el0374Test',
dir: path.join(__dirname, 'fixtures', 'el-0374'),
version: '0.37.4',
arch: 'z80',
platform: 'linux'
}
Expand All @@ -463,11 +460,8 @@ test('fails with invalid arch', function (t) {
util.teardown()

util.setup()
test('fails with invalid platform', function (t) {
test('fails with invalid platform', (t) => {
var opts = {
name: 'el0374Test',
dir: path.join(__dirname, 'fixtures', 'el-0374'),
version: '0.37.4',
arch: 'ia32',
platform: 'dos'
}
Expand Down
15 changes: 8 additions & 7 deletions test/multitarget.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function verifyPackageExistence (finalPaths, callback) {

util.setup()
test('all test', function (t) {
t.timeoutAfter(config.timeout * 5) // 4-5 packages will be built during this test
t.timeoutAfter(config.timeout * 7) // 5-7 packages will be built during this test

var opts = {
name: 'basicTest',
Expand All @@ -34,13 +34,13 @@ test('all test', function (t) {
all: true
}

var expectedAppCount = 6
var expectedAppCount = 7

waterfall([
function (cb) {
if (process.platform === 'win32') {
isAdmin().then((admin) => {
if (!admin) expectedAppCount = 4
if (!admin) expectedAppCount = 5
cb()
})
} else {
Expand Down Expand Up @@ -92,8 +92,9 @@ test('platform=all test (one arch)', function (t) {
util.teardown()

util.setup()
test('arch=all test (one platform)', function (t) {
t.timeoutAfter(config.timeout * 2) // 2 packages will be built during this test
test('arch=all test (one platform)', (t) => {
const LINUX_ARCH_COUNT = 3
t.timeoutAfter(config.timeout * LINUX_ARCH_COUNT)

var opts = {
name: 'basicTest',
Expand All @@ -107,10 +108,10 @@ test('arch=all test (one platform)', function (t) {
function (cb) {
packager(opts, cb)
}, function (finalPaths, cb) {
t.equal(finalPaths.length, 2, 'packager call should resolve with expected number of paths')
t.equal(finalPaths.length, LINUX_ARCH_COUNT, 'packager call should resolve with expected number of paths')
verifyPackageExistence(finalPaths, cb)
}, function (exists, cb) {
t.true(exists, 'Packages should be generated for both architectures')
t.true(exists, 'Packages should be generated for all expected architectures')
cb()
}
], function (err) {
Expand Down
Loading

0 comments on commit 65c5b67

Please sign in to comment.