From a157f716a572515a2d117a8bb51e9da3e34022d3 Mon Sep 17 00:00:00 2001 From: "Kenneth G. Franqueiro" Date: Fri, 19 Jun 2015 22:36:15 -0400 Subject: [PATCH 1/2] Implement multi-target options and refactor code This adds support for --all, --platform=all, and --arch=all. In order to accommodate outputting multiple directories for multiple platforms and architectures, this also implements a new directory structure under the output folder (distinguished by both platform and arch). This structure is applied even to OS X distributions, which formerly were output directly to an .app folder. This could be considered a backwards-incompatible change. One other backwards-incompatible change is the value that the packager function passes to the callback, which is now always an array of paths, rather than just a single path. The behavior of the icon option has also been modified to use its basename and apply .ico or .icns depending on platform, to make it usable with --all and --platform=all. This attempts to maximize backwards compatibility, by allowing a full filename to be specified, but replacing the filename's extension with what is appropriate for each target platform. Alternatively, the extension can now be omitted. In the process of implementing this, it became evident that some things were being done in 3 different places, and weren't always being done consistently, so I've deduplicated everything I could. This also includes a few other changes to improve stability for multi-target runs, and other fixes: * Avoid targeting darwin if the environment doesn't support symlinks, to avoid the process bailing out on Windows * Implement --overwrite centrally in index.js such that it explicitly skips if an output directory already exists, for consistency with all target platforms and to avoid any possible errors that would halt operation during one target of a multi-target run * Use ncp instead of mv to move to finalPath, which avoids flakiness I noticed when testing on Windows 8 especially with multi-target runs * Simplify temp directory logic by using a nested structure, so there is only one top-level directory to clean up * Reinstate fix from #55 which seems to have been clobbered by a later merge * linux.createApp now resolves to the final output directory; it was formerly resolving to the executable path * mac.createApp now replaces space with underscore in bundle IDs * Only the platform modules that are needed are loaded * The win32 module only loads rcedit if needed This also fixes a couple of missing updates to docs (readme/usage). This commit addresses the following issues: * Resolves #40 * Resolves #38 * Resolves #70 * Works around #71 * Resolves #84 by reinstating #55 --- .gitignore | 1 - cli.js | 9 ++- common.js | 159 +++++++++++++++++++++++++++++--------- index.js | 190 +++++++++++++++++++++++++++++++++++---------- linux.js | 71 ++--------------- mac.js | 213 +++++++++++++++++---------------------------------- package.json | 3 +- readme.md | 33 ++++++-- usage.txt | 15 ++-- win32.js | 104 +++++++------------------ 10 files changed, 421 insertions(+), 377 deletions(-) diff --git a/.gitignore b/.gitignore index 7e95763..53d98e1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -downloaded/*.zip node_modules .DS_Store test/dist \ No newline at end of file diff --git a/cli.js b/cli.js index a01e653..9bb0c4f 100755 --- a/cli.js +++ b/cli.js @@ -1,6 +1,6 @@ #!/usr/bin/env node var fs = require('fs') -var args = require('minimist')(process.argv.slice(2), {boolean: ['prune', 'asar', 'overwrite']}) +var args = require('minimist')(process.argv.slice(2), {boolean: ['prune', 'asar', 'all', 'overwrite']}) var packager = require('./') var usage = fs.readFileSync(__dirname + '/usage.txt').toString() @@ -16,17 +16,18 @@ if (protocolSchemes && protocolNames && protocolNames.length === protocolSchemes }) } -if (!args.dir || !args.name || !args.platform || !args.arch || !args.version) { +if (!args.dir || !args.name || !args.version || (!args.all && (!args.platform || !args.arch))) { console.error(usage) process.exit(1) } -packager(args, function done (err, appPath) { +packager(args, function done (err, appPaths) { if (err) { if (err.message) console.error(err.message) else console.error(err, err.stack) process.exit(1) } - console.error('Wrote new app to', appPath) + if (appPaths.length > 1) console.error('Wrote new apps to:\n' + appPaths.join('\n')) + else if (appPaths.length === 1) console.error('Wrote new app to', appPaths[0]) }) diff --git a/common.js b/common.js index 2d194a0..84ccd7f 100644 --- a/common.js +++ b/common.js @@ -1,50 +1,139 @@ -var asar = require('asar') var child = require('child_process') +var fs = require('fs') +var os = require('os') var path = require('path') + +var asar = require('asar') +var mkdirp = require('mkdirp') +var ncp = require('ncp').ncp var rimraf = require('rimraf') +var series = require('run-series') + +function asarApp (appPath, cb) { + var src = path.join(appPath) + var dest = path.join(appPath, '..', 'app.asar') + asar.createPackage(src, dest, function (err) { + if (err) return cb(err) + rimraf(src, function (err) { + if (err) return cb(err) + cb(null, dest) + }) + }) +} + +function generateFinalBasename (opts) { + return opts.name + '-' + opts.platform + '-' + opts.arch +} + +function generateFinalPath (opts) { + return path.join(opts.out || process.cwd(), generateFinalBasename(opts)) +} + +function userIgnoreFilter (opts) { + return function filter (file) { + file = file.split(path.resolve(opts.dir))[1] + + if (path.sep === '\\') { + // convert slashes so unix-format ignores work + file = file.replace(/\\/g, '/') + } + + var ignore = opts.ignore || [] + if (!Array.isArray(ignore)) ignore = [ignore] + for (var i = 0; i < ignore.length; i++) { + if (file.match(ignore[i])) { + return false + } + } + return true + } +} module.exports = { - asarApp: function asarApp (finalDir, cb) { - var src = path.join(finalDir, 'app') - var dest = path.join(finalDir, 'app.asar') - asar.createPackage(src, dest, function (err) { - if (err) return cb(err) - rimraf(src, function (err) { - if (err) return cb(err) - cb(null, dest) + generateFinalPath: generateFinalPath, + + initializeApp: function initializeApp (opts, templatePath, appRelativePath, callback) { + // Performs the following initial operations for an app: + // * Creates temporary directory + // * Copies template into temporary directory + // * Copies user's app into temporary directory + // * Prunes non-production node_modules (if opts.prune is set) + // * Creates an asar (if opts.asar is set) + + var tempParent = path.join(os.tmpdir(), 'electron-packager', opts.platform + '-' + opts.arch) + var tempPath = path.join(tempParent, generateFinalBasename(opts)) + // Path to `app` directory + var appPath = path.join(tempPath, appRelativePath) + + var operations = [ + function (cb) { + rimraf(tempParent, function () { + // Ignore errors (e.g. directory didn't exist anyway) + cb() + }) + }, + function (cb) { + mkdirp(tempPath, cb) + }, + function (cb) { + ncp(templatePath, tempPath, cb) + }, + function (cb) { + ncp(opts.dir, appPath, {filter: userIgnoreFilter(opts), dereference: true}, cb) + } + ] + + // Prune and asar are now performed before platform-specific logic, primarily so that + // appPath is predictable (e.g. before .app is renamed for mac) + if (opts.prune) { + operations.push(function (cb) { + child.exec('npm prune --production', {cwd: appPath}, cb) }) + } + + if (opts.asar) { + operations.push(function (cb) { + asarApp(path.join(appPath), cb) + }) + } + + series(operations, function (err) { + if (err) return callback(err) + // Resolve to path to temporary app folder for platform-specific processes to use + callback(null, tempPath) }) }, - prune: function prune (opts, cwd, cb, nextStep) { - if (opts.prune) { - child.exec('npm prune --production', { cwd: cwd }, function pruned (err) { - if (err) return cb(err) - nextStep() - }) - } else { - nextStep() - } + moveApp: function finalizeApp (opts, tempPath, callback) { + var finalPath = generateFinalPath(opts) + // Prefer ncp over mv (which seems to cause issues on Win8) + series([ + function (cb) { + mkdirp(finalPath, cb) + }, + function (cb) { + ncp(tempPath, finalPath, cb) + } + ], function (err) { + callback(err, finalPath) + }) }, - userIgnoreFilter: function userIgnoreFilter (opts, finalDir) { - return function filter (file) { - if (path.sep === '\\') { - // convert slashes so unix-format ignores work - file = file.replace(/\\/g, '/') - } + normalizeExt: function normalizeExt (filename, targetExt, cb) { + // Forces a filename to a given extension and fires the given callback with the normalized filename, + // if it exists. Otherwise reports the error from the fs.stat call. + // (Used for resolving icon filenames, particularly during --all runs.) - var ignore = opts.ignore || [] - if (!Array.isArray(ignore)) ignore = [ignore] - if (typeof finalDir !== 'undefined') { - ignore = ignore.concat([finalDir]) - } - for (var i = 0; i < ignore.length; i++) { - if (file.match(ignore[i])) { - return false - } - } - return true + // This error path is used by win32.js if no icon is specified + if (!filename) return cb(new Error('No filename specified to normalizeExt')) + + var ext = path.extname(filename) + if (ext !== targetExt) { + filename = filename.slice(0, filename.length - ext.length) + targetExt } + + fs.stat(filename, function (err) { + cb(err, err ? null : filename) + }) } } diff --git a/index.js b/index.js index 6d5ed16..b506245 100644 --- a/index.js +++ b/index.js @@ -1,59 +1,169 @@ var path = require('path') +var fs = require('fs') var os = require('os') var download = require('electron-download') var extract = require('extract-zip') var mkdirp = require('mkdirp') var rimraf = require('rimraf') +var series = require('run-series') +var common = require('./common') -var mac = require('./mac.js') -var linux = require('./linux.js') -var win32 = require('./win32.js') +var supportedArchs = { + ia32: 1, + x64: 1 +} + +var supportedPlatforms = { + // Maps to module ID for each platform (lazy-required if used) + darwin: './mac', + linux: './linux', + win32: './win32' +} + +var tempBase = path.join(os.tmpdir(), 'electron-packager') + +function testSymlink (cb) { + var testPath = path.join(tempBase, 'symlink-test') + var testFile = path.join(testPath, 'test') + var testLink = path.join(testPath, 'testlink') + series([ + function (cb) { + mkdirp(testPath, cb) + }, + function (cb) { + fs.writeFile(testFile, '', cb) + }, + function (cb) { + fs.symlink(testFile, testLink, cb) + } + ], function (err) { + var result = !err + rimraf(testPath, function () { + cb(result) // ignore errors on cleanup + }) + }) +} + +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 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 (platform === 'darwin' && arch === 'ia32') return + combinations.push({ + platform: platform, + arch: arch, + version: opts.version + }) + }) + }) + + return [ + function (cb) { + rimraf(tempBase, cb) + } + ].concat(combinations.map(function (combination) { + var arch = combination.arch + var platform = combination.platform + var version = combination.version + + return function (callback) { + download(combination, function (err, zipPath) { + if (err) return callback(err) + + var tmpDir = path.join(tempBase, platform + '-' + arch + '-template') + + var operations = [ + function (cb) { + mkdirp(tmpDir, cb) + }, + function (cb) { + extract(zipPath, {dir: tmpDir}, cb) + } + ] + + function createApp (comboOpts) { + console.error('Packaging app for platform', platform + ' ' + arch, 'using electron v' + version) + series(operations, function () { + require(supportedPlatforms[platform]).createApp(comboOpts, tmpDir, callback) + }) + } + + function checkOverwrite () { + // Create delegated options object with specific platform and arch, for output directory naming + var comboOpts = Object.create(opts) + comboOpts.arch = arch + comboOpts.platform = platform + + var finalPath = common.generateFinalPath(comboOpts) + fs.exists(finalPath, function (exists) { + if (exists) { + if (opts.overwrite) { + rimraf(finalPath, function () { + createApp(comboOpts) + }) + } else { + console.error('Skipping ' + platform + ' ' + arch + + ' (output dir already exists, use --overwrite to force)') + callback() + } + } else { + createApp(comboOpts) + } + }) + } + + if (combination.platform === 'darwin') { + testSymlink(function (result) { + if (result) return checkOverwrite() + + console.error('Cannot create symlinks; skipping darwin platform') + callback() + }) + } else { + checkOverwrite() + } + }) + } + })) +} module.exports = function packager (opts, cb) { - var platformPackager - var platform = opts.platform - var arch = opts.arch - var version = opts.version - - if (!platform || !arch || !version) cb(new Error('Must specify platform, arch and version')) - - switch (arch) { - case 'ia32': break - case 'x64': break - default: return cb(new Error('Unsupported arch. Must be either ia32 or x64')) - } - - switch (platform) { - case 'darwin': platformPackager = mac; break - case 'linux': platformPackager = linux; break - case 'win32': platformPackager = win32; break - default: return cb(new Error('Unsupported platform. Must be either darwin, linux, or win32')) - } + var archs = validateList(opts.all ? 'all' : opts.arch, supportedArchs, 'arch') + var platforms = validateList(opts.all ? 'all' : opts.platform, supportedPlatforms, 'platform') + if (!opts.version) return cb(new Error('Must specify version')) + if (!Array.isArray(archs)) return cb(new Error(archs)) + if (!Array.isArray(platforms)) return cb(new Error(platforms)) // Ignore this and related modules by default var defaultIgnores = ['/node_modules/electron-prebuilt($|/)', '/node_modules/electron-packager($|/)', '/\.git($|/)'] if (opts.ignore && !Array.isArray(opts.ignore)) opts.ignore = [opts.ignore] opts.ignore = (opts.ignore) ? opts.ignore.concat(defaultIgnores) : defaultIgnores - download({ - platform: platform, - arch: arch, - version: version - }, function (err, zipPath) { + series(createSeries(opts, archs, platforms), function (err, appPaths) { if (err) return cb(err) - console.error('Packaging app for platform', platform + ' ' + arch, 'using electron v' + version) - // extract zip into tmp so that packager can use it as a template - var tmpDir = path.join(os.tmpdir(), 'electron-packager-' + platform + '-template') - rimraf(tmpDir, function (err) { - if (err) {} // ignore err - mkdirp(tmpDir, function (err) { - if (err) return cb(err) - extract(zipPath, {dir: tmpDir}, function (err) { - if (err) return cb(err) - platformPackager.createApp(opts, tmpDir, cb) - }) - }) - }) + + cb(null, appPaths.filter(function (appPath) { + // Remove falsy entries (e.g. skipped platforms) + return appPath + })) }) } diff --git a/linux.js b/linux.js index 29c6f24..5e05ae1 100644 --- a/linux.js +++ b/linux.js @@ -1,70 +1,15 @@ var path = require('path') -var fs = require('fs') -var mkdirp = require('mkdirp') -var ncp = require('ncp').ncp -var rimraf = require('rimraf') +var mv = require('mv') var common = require('./common') module.exports = { - createApp: function createApp (opts, templateApp, cb) { - var finalDir = path.join(opts.out || process.cwd(), opts.name + '-linux') - var userAppDir = path.join(finalDir, 'resources', 'default_app') - var originalBinary = path.join(finalDir, 'electron') - var finalBinary = path.join(finalDir, opts.name) - - function copyApp () { - var createApp = function (err) { - if (err) return cb(err) - mkdirp(finalDir, function AppFolderCreated (err) { - if (err) return cb(err) - copyAppTemplate() - }) - } - if (opts.overwrite) { - fs.exists(finalDir, function (exists) { - if (exists) { - console.log('Overwriting existing ' + finalDir + ' ...') - rimraf(finalDir, createApp) - } else { - createApp() - } - }) - } else { - createApp() - } - } - - function copyAppTemplate () { - ncp(templateApp, finalDir, {filter: appFilter}, function AppCreated (err) { - if (err) return cb(err) - copyUserApp() + createApp: function createApp (opts, templatePath, callback) { + common.initializeApp(opts, templatePath, path.join('resources', 'app'), function buildLinuxApp (err, tempPath) { + if (err) return callback(err) + mv(path.join(tempPath, 'electron'), path.join(tempPath, opts.name), function (err) { + if (err) return callback(err) + common.moveApp(opts, tempPath, callback) }) - } - - function copyUserApp () { - ncp(opts.dir, userAppDir, {filter: common.userIgnoreFilter(opts, finalDir), dereference: true}, function copied (err) { - if (err) return cb(err) - common.prune(opts, userAppDir, cb, renameElectronBinary) - }) - } - - function renameElectronBinary () { - fs.rename(originalBinary, finalBinary, function electronRenamed (err) { - var asarDir - if (err) return cb(err) - if (opts.asar) { - asarDir = path.join(finalDir, 'resources') - common.asarApp(asarDir, cb) - } else { - cb(null, finalBinary) - } - }) - } - - function appFilter (file) { - return file.match(/default_app/) === null - } - - copyApp() + }) } } diff --git a/mac.js b/mac.js index e541750..6045488 100644 --- a/mac.js +++ b/mac.js @@ -1,160 +1,87 @@ -var os = require('os') var path = require('path') var fs = require('fs') var child = require('child_process') var plist = require('plist') -var mkdirp = require('mkdirp') -var rimraf = require('rimraf') var mv = require('mv') var ncp = require('ncp').ncp +var series = require('run-series') var common = require('./common') module.exports = { - createApp: function createApp (opts, electronPath, cb) { - var electronApp = path.join(electronPath, 'Electron.app') - var tmpDir = path.join(os.tmpdir(), 'electron-packager-mac') + createApp: function createApp (opts, templatePath, callback) { + var appRelativePath = path.join('Electron.app', 'Contents', 'Resources', 'app') + common.initializeApp(opts, templatePath, appRelativePath, function buildMacApp (err, tempPath) { + if (err) return callback(err) - var newApp = path.join(tmpDir, opts.name + '.app') + var contentsPath = path.join(tempPath, 'Electron.app', 'Contents') + var helperPath = path.join(contentsPath, 'Frameworks', 'Electron Helper.app') + var appPlistFilename = path.join(contentsPath, 'Info.plist') + var helperPlistFilename = path.join(helperPath, 'Contents', 'Info.plist') + var appPlist = plist.parse(fs.readFileSync(appPlistFilename).toString()) + var helperPlist = plist.parse(fs.readFileSync(helperPlistFilename).toString()) - // reset build folders + copy template app - rimraf(tmpDir, function rmrfd () { - // ignore errors - mkdirp(newApp, function mkdirpd () { - // ignore errors - // copy .app folder and use as template (this is exactly what Atom editor does) - ncp(electronApp, newApp, function copied (err) { - if (err) return cb(err) - buildMacApp(opts, cb, newApp) + // Update plist files + var defaultBundleName = 'com.electron.' + opts.name.toLowerCase().replace(/ /g, '_') + var appVersion = opts['app-version'] + + appPlist.CFBundleDisplayName = opts.name + appPlist.CFBundleIdentifier = opts['app-bundle-id'] || defaultBundleName + appPlist.CFBundleName = opts.name + helperPlist.CFBundleIdentifier = opts['helper-bundle-id'] || defaultBundleName + '.helper' + helperPlist.CFBundleName = opts.name + + if (appVersion) { + appPlist.CFBundleVersion = appVersion + } + + if (opts.protocols) { + helperPlist.CFBundleURLTypes = appPlist.CFBundleURLTypes = opts.protocols.map(function (protocol) { + return { + CFBundleURLName: protocol.name, + CFBundleURLSchemes: [].concat(protocol.schemes) + } }) + } + + fs.writeFileSync(appPlistFilename, plist.build(appPlist)) + fs.writeFileSync(helperPlistFilename, plist.build(helperPlist)) + + var operations = [] + + if (opts.icon) { + operations.push(function (cb) { + common.normalizeExt(opts.icon, '.icns', function (err, icon) { + if (err) { + // Ignore error if icon doesn't exist, in case it's only available for other OS + cb(null) + } else { + ncp(icon, path.join(contentsPath, 'Resources', 'atom.icns'), cb) + } + }) + }) + } + + // Move Helper binary, then Helper.app, then top-level .app + var finalAppPath = path.join(tempPath, opts.name + '.app') + operations.push(function (cb) { + var helperBinaryPath = path.join(helperPath, 'Contents', 'MacOS') + mv(path.join(helperBinaryPath, 'Electron Helper'), path.join(helperBinaryPath, opts.name + ' Helper'), cb) + }, function (cb) { + mv(helperPath, path.join(path.dirname(helperPath), opts.name + ' Helper.app'), cb) + }, function (cb) { + mv(path.dirname(contentsPath), finalAppPath, cb) + }) + + if (opts.sign) { + operations.push(function (cb) { + child.exec('codesign --deep --force --sign "' + opts.sign + '" ' + finalAppPath, cb) + }) + } + + series(operations, function () { + common.moveApp(opts, tempPath, callback) }) }) } } - -function buildMacApp (opts, cb, newApp) { - var paths = { - info1: path.join(newApp, 'Contents', 'Info.plist'), - info2: path.join(newApp, 'Contents', 'Frameworks', 'Electron Helper.app', 'Contents', 'Info.plist'), - app: path.join(newApp, 'Contents', 'Resources', 'app'), - helper: path.join(newApp, 'Contents', 'Frameworks', 'Electron Helper.app') - } - - // update plist files - var pl1 = plist.parse(fs.readFileSync(paths.info1).toString()) - var pl2 = plist.parse(fs.readFileSync(paths.info2).toString()) - - var bundleId = opts['app-bundle-id'] || 'com.electron.' + opts.name.toLowerCase() - var bundleHelperId = opts['helper-bundle-id'] || 'com.electron.' + opts.name.toLowerCase() + '.helper' - var appVersion = opts['app-version'] - - pl1.CFBundleDisplayName = opts.name - pl1.CFBundleIdentifier = bundleId - pl1.CFBundleName = opts.name - pl2.CFBundleIdentifier = bundleHelperId - pl2.CFBundleName = opts.name - - if (appVersion) { - pl1.CFBundleVersion = appVersion - } - - if (opts.protocols) { - pl2.CFBundleURLTypes = pl1.CFBundleURLTypes = opts.protocols.map(function (protocol) { - return { - CFBundleURLName: protocol.name, - CFBundleURLSchemes: [].concat(protocol.schemes) - } - }) - } - - fs.writeFileSync(paths.info1, plist.build(pl1)) - fs.writeFileSync(paths.info2, plist.build(pl2)) - - // copy users app into .app - ncp(opts.dir, paths.app, {filter: common.userIgnoreFilter(opts), dereference: true}, function copied (err) { - if (err) return cb(err) - - function moveHelper () { - // Move helper binary before moving the parent helper app directory itself - var helperDestination = path.join(path.dirname(paths.helper), opts.name + ' Helper.app') - var helperBinary = path.join(paths.helper, 'Contents', 'MacOS', 'Electron Helper') - var helperBinaryDestination = path.join(path.dirname(helperBinary), opts.name + ' Helper') - - fs.rename(helperBinary, helperBinaryDestination, function (err) { - if (err) return cb(err) - fs.rename(paths.helper, helperDestination, function (err) { - if (err) return cb(err) - moveApp() - }) - }) - } - - function moveApp () { - // finally, move app into cwd - var outdir = opts.out || process.cwd() - var finalPath = path.join(outdir, opts.name + '.app') - - mkdirp(outdir, function mkoutdirp () { - if (err) return cb(err) - if (opts.overwrite) { - fs.exists(finalPath, function (exists) { - if (exists) { - console.log('Overwriting existing ' + finalPath + ' ...') - rimraf(finalPath, deploy) - } else { - deploy() - } - }) - } else { - deploy() - } - - function deploy (err) { - if (err) return cb(err) - mv(newApp, finalPath, function moved (err) { - if (err) return cb(err) - if (opts.asar) { - var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app', 'Contents', 'Resources') - common.asarApp(finalPath, function (err) { - if (err) return cb(err) - updateMacIcon(function (err) { - if (err) return cb(err) - codesign() - }) - }) - } else { - updateMacIcon(function (err) { - if (err) return cb(err) - codesign() - }) - } - }) - } - }) - } - - function updateMacIcon (cb) { - var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app') - - if (!opts.icon) { - return cb(null) - } - - ncp(opts.icon, path.join(finalPath, 'Contents', 'Resources', 'atom.icns'), function copied (err) { - cb(err) - }) - } - - function codesign () { - var appPath = path.join(opts.out || process.cwd(), opts.name + '.app') - - if (!opts.sign) return cb(null, appPath) - - child.exec('codesign --deep --force --sign "' + opts.sign + '" ' + appPath, function (err, stdout, stderr) { - cb(err, appPath) - }) - } - - common.prune(opts, paths.app, cb, moveHelper) - }) -} diff --git a/package.json b/package.json index 0a28a60..1628657 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "ncp": "^2.0.0", "plist": "^1.1.0", "rcedit": "^0.3.0", - "rimraf": "^2.3.2" + "rimraf": "^2.3.2", + "run-series": "^1.1.1" }, "devDependencies": { "standard": "^3.3.2", diff --git a/readme.md b/readme.md index fe74fc4..cbe362b 100644 --- a/readme.md +++ b/readme.md @@ -25,14 +25,15 @@ Usage: electron-packager --platform= --arch=/-` +- Use that version of electron to create a app in `/--` You should be able to launch the app on the platform you built for. If not, check your settings and try again. @@ -80,15 +82,21 @@ The source directory. The application name. `platform` - *String* -Allowed values: *linux, win32, darwin* +Allowed values: *linux, win32, darwin, all* +Not required if `all` is used. +Arbitrary combinations of individual platforms are also supported via a comma-delimited string or array of strings. `arch` - *String* -Allowed values: *ia32, x64* +Allowed values: *ia32, x64, all* +Not required if `all` is used. `version` - *String* Electron version (without the 'v'). See https://github.com/atom/electron/releases **Optional** +`all` - *Boolean* +Shortcut for `--arch=all --platform=all` + `out` - *String* `icon` - *String* @@ -103,10 +111,23 @@ Electron version (without the 'v'). See https://github.com/atom/electron/release `prune` - *Boolean* +`overwrite` - *Boolean* + `asar` - *Boolean* `sign` - *String* +`version-string` - *Object* +Object hash of application metadata to embed into the executable (Windows only): +* `CompanyName` +* `LegalCopyright` +* `FileDescription` +* `OriginalFilename` +* `FileVersion` +* `ProductVersion` +* `ProductName` +* `InternalName` + ##### callback `err` - *Error* @@ -121,4 +142,4 @@ If you run this on windows and you want to set the icon for your app using the ` ### related -- [grunt-electron](https://github.com/sindresorhus/grunt-electron) - grunt plugin for electron-packager +- [grunt-electron](https://github.com/sindresorhus/grunt-electron) - grunt plugin for electron-packager \ No newline at end of file diff --git a/usage.txt b/usage.txt index fdc3c85..ef068c2 100644 --- a/usage.txt +++ b/usage.txt @@ -1,15 +1,16 @@ Usage: electron-packager --platform= --arch= --version= - + Required options -platform linux, win32, darwin -arch ia32, x64 +platform all, or one or more of: linux, win32, darwin (comma-delimited if multiple) +arch all, ia32, x64 version see https://github.com/atom/electron/releases - -Example electron-packager ./ FooBar --platform=darwin --arch=x64 --version=0.25.1 + +Example electron-packager ./ FooBar --platform=darwin --arch=x64 --version=0.28.2 Optional options +all equivalent to --platform=all --arch=all out the dir to put the app into at the end. defaults to current working dir icon the icon file to use as the icon for the app app-bundle-id bundle identifier to use in the app plist @@ -17,4 +18,6 @@ app-version version to set for the app helper-bundle-id bundle identifier to use in the app helper plist ignore do not copy files into App whose filenames regex .match this string prune runs `npm prune --production` on the app -asar packages the source code within your app into an archive \ No newline at end of file +overwrite if output directory for a platform already exists, replaces it rather than skipping it +asar packages the source code within your app into an archive +sign should contain the identity to be used when running `codesign` (OS X only) \ No newline at end of file diff --git a/win32.js b/win32.js index 68cfe4d..0f7abaa 100644 --- a/win32.js +++ b/win32.js @@ -1,92 +1,40 @@ -var os = require('os') var path = require('path') -var mkdirp = require('mkdirp') -var rimraf = require('rimraf') -var ncp = require('ncp').ncp var mv = require('mv') -var rcedit = require('rcedit') +var series = require('run-series') var common = require('./common') module.exports = { - createApp: function createApp (opts, electronApp, cb) { - var tmpDir = path.join(os.tmpdir(), 'electron-packager-windows') + createApp: function createApp (opts, templatePath, callback) { + common.initializeApp(opts, templatePath, path.join('resources', 'app'), function buildWinApp (err, tempPath) { + if (err) return callback(err) - var newApp = path.join(tmpDir, opts.name + '-win32') - // reset build folders + copy template app - rimraf(tmpDir, function rmrfd () { - // ignore errors - mkdirp(newApp, function mkdirpd () { - // ignore errors - // copy app folder and use as template (this is exactly what Atom editor does) - ncp(electronApp, newApp, function copied (err) { - if (err) return cb(err) - // rename electron.exe - mv(path.join(newApp, 'electron.exe'), path.join(newApp, opts.name + '.exe'), function (err) { - if (err) return cb(err) + var newExePath = path.join(tempPath, opts.name + '.exe') + var operations = [ + function (cb) { + mv(path.join(tempPath, 'electron.exe'), newExePath, cb) + } + ] - buildWinApp(opts, cb, newApp) + if (opts.icon || opts['version-string']) { + operations.push(function (cb) { + common.normalizeExt(opts.icon, '.ico', function (err, icon) { + var rcOpts = {} + if (opts['version-string']) rcOpts['version-string'] = opts['version-string'] + + // Icon might be omitted or only exist in one OS's format, so skip it if normalizeExt reports an error + if (!err) { + rcOpts.icon = icon + } + + require('rcedit')(newExePath, rcOpts, cb) }) }) + } + + series(operations, function () { + common.moveApp(opts, tempPath, callback) }) }) } } - -function copy (from, to, cb) { - rimraf(to, function () { - mkdirp(to, function () { - ncp(from, to, function (err) { - if (err) { return cb(err) } - cb() - }) - }) - }) -} - -function buildWinApp (opts, cb, newApp) { - var paths = { - app: path.join(newApp, 'resources', 'app') - } - - // copy users app into destination path - ncp(opts.dir, paths.app, {filter: common.userIgnoreFilter(opts), dereference: true}, function copied (err) { - if (err) return cb(err) - - function moveApp () { - // finally, move app into cwd - var finalPath = path.join(opts.out || process.cwd(), opts.name + '-win32') - copy(newApp, finalPath, function moved (err) { - if (err) return cb(err) - if (opts.asar) { - var finalPath = path.join(opts.out || process.cwd(), opts.name + '-win32', 'resources') - common.asarApp(finalPath, function (err) { - if (err) return cb(err) - updateResourceData() - }) - } else { - updateResourceData() - } - }) - } - - function updateResourceData () { - var finalPath = path.join(opts.out || process.cwd(), opts.name + '-win32') - - if (!opts.icon && !opts['version-string']) { - return cb(null, finalPath) - } - - var exePath = path.join(opts.out || process.cwd(), opts.name + '-win32', opts.name + '.exe') - var rcOptions = { - icon: opts.icon, - 'version-string': opts['version-string'] - } - rcedit(exePath, rcOptions, function (err) { - cb(err, finalPath) - }) - } - - common.prune(opts, paths.app, cb, moveApp) - }) -} From a360f6c2ee0d097794ae0bc8fcbc575074679fec Mon Sep 17 00:00:00 2001 From: "Kenneth G. Franqueiro" Date: Wed, 24 Jun 2015 00:05:36 -0400 Subject: [PATCH 2/2] Add more comprehensive tests This implements the following cases: * Basic runs for a specific version/platform/arch with default options (testing for existence of expected output files/folders) * Runs for each target platform with `out` set * Runs for each target platform with `asar` set * Runs for each target platform with `prune` set * Runs for each target platform with `ignore` set * This includes testing `ignore` including a path separator * This also includes testing that `ignore` entries are applied with the app folder trimmed * Runs for each target platform with `overwrite` set / not set * Runs with `all` set, with `arch` or `platform` each set to `all`, and with `platform` set to multiple platforms (comma-delimited or array) * Tests specifically for the darwin target platform, to test `icon` and `sign` The test logic is organized such that the version of Electron being tested can be configured once centrally (in config.json), and the tests will not run until after downloading any necessary electron versions (to avoid timing out due to long downloads). Resolves #77. --- .gitignore | 1 - package.json | 5 +- test/basic.js | 273 ++++++++++++++++++ test/config.json | 4 + .../basic/electron-packager/readme.txt | 2 + test/fixtures/basic/ignore/this.txt | 0 test/fixtures/basic/ignorethis.txt | 1 + test/fixtures/basic/index.html | 4 + test/fixtures/basic/main.js | 22 ++ test/fixtures/basic/package.json | 9 + test/fixtures/monochrome.icns | Bin 0 -> 274820 bytes test/index.js | 27 ++ test/mac.js | 94 ++++++ test/multitarget.js | 145 ++++++++++ test/test.js | 45 --- test/testapp/index.js | 6 - test/testapp/package.json | 11 - test/util.js | 100 +++++++ 18 files changed, 684 insertions(+), 65 deletions(-) create mode 100644 test/basic.js create mode 100644 test/config.json create mode 100644 test/fixtures/basic/electron-packager/readme.txt create mode 100644 test/fixtures/basic/ignore/this.txt create mode 100644 test/fixtures/basic/ignorethis.txt create mode 100644 test/fixtures/basic/index.html create mode 100644 test/fixtures/basic/main.js create mode 100644 test/fixtures/basic/package.json create mode 100644 test/fixtures/monochrome.icns create mode 100644 test/index.js create mode 100644 test/mac.js create mode 100644 test/multitarget.js delete mode 100644 test/test.js delete mode 100644 test/testapp/index.js delete mode 100644 test/testapp/package.json create mode 100644 test/util.js diff --git a/.gitignore b/.gitignore index 53d98e1..fd4f2b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ node_modules .DS_Store -test/dist \ No newline at end of file diff --git a/package.json b/package.json index 1628657..b2429fd 100644 --- a/package.json +++ b/package.json @@ -30,15 +30,16 @@ "run-series": "^1.1.1" }, "devDependencies": { + "run-waterfall": "^1.1.1", "standard": "^3.3.2", "tape": "^4.0.0" }, "scripts": { - "test": "standard && node test/test.js" + "test": "standard && tape test" }, "standard": { "ignore": [ - "test/dist" + "test/fixtures/**/node_modules" ] } } diff --git a/test/basic.js b/test/basic.js new file mode 100644 index 0000000..cd05aa7 --- /dev/null +++ b/test/basic.js @@ -0,0 +1,273 @@ +var fs = require('fs') +var path = require('path') + +var packager = require('..') +var waterfall = require('run-waterfall') + +var config = require('./config.json') +var util = require('./util') + +function generateBasename (opts) { + return opts.name + '-' + opts.platform + '-' + opts.arch +} + +function generateNamePath (opts) { + // Generates path to verify reflects the name given in the options. + // Returns the Helper.app location on darwin since the top-level .app is already tested for the resources path; + // returns the executable for other OSes + if (opts.platform === 'darwin') { + return path.join(opts.name + '.app', 'Contents', 'Frameworks', opts.name + ' Helper.app') + } + + return opts.name + (opts.platform === 'win32' ? '.exe' : '') +} + +function createDefaultsTest (combination) { + return function (t) { + t.timeoutAfter(config.timeout) + + var opts = Object.create(combination) + opts.name = 'basicTest' + opts.dir = path.join(__dirname, 'fixtures', 'basic') + + var finalPath + var resourcesPath + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (paths, cb) { + t.true(Array.isArray(paths), 'packager call should resolve to an array') + t.equal(paths.length, 1, 'Single-target run should resolve to a 1-item array') + + finalPath = paths[0] + t.equal(finalPath, path.join(util.getWorkCwd(), generateBasename(opts)), + 'Path should follow the expected format and be in the cwd') + fs.stat(finalPath, cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The expected output directory should exist') + resourcesPath = path.join(finalPath, util.generateResourcesPath(opts)) + fs.stat(path.join(finalPath, generateNamePath(opts)), cb) + }, function (stats, cb) { + if (opts.platform === 'darwin') { + t.true(stats.isDirectory(), 'The Helper.app should reflect opts.name') + } else { + t.true(stats.isFile(), 'The executable should reflect opts.name') + } + fs.stat(resourcesPath, cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') + fs.stat(path.join(resourcesPath, 'app', 'node_modules', 'run-waterfall'), cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The output directory should contain devDependencies by default (no prune)') + util.areFilesEqual(path.join(opts.dir, 'main.js'), path.join(resourcesPath, 'app', 'main.js'), cb) + }, function (equal, cb) { + t.true(equal, 'File under packaged app directory should match source file') + util.areFilesEqual(path.join(opts.dir, 'ignore', 'this.txt'), + path.join(resourcesPath, 'app', 'ignore', 'this.txt'), + cb) + }, function (equal, cb) { + t.true(equal, + 'File under subdirectory of packaged app directory should match source file and not be ignored by default') + cb() + } + ], function (err) { + t.end(err) + }) + } +} + +function createOutTest (combination) { + return function (t) { + t.timeoutAfter(config.timeout) + + var opts = Object.create(combination) + opts.name = 'basicTest' + opts.dir = path.join(__dirname, 'fixtures', 'basic') + opts.out = 'dist' + + var finalPath + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (paths, cb) { + finalPath = paths[0] + t.equal(finalPath, path.join('dist', generateBasename(opts)), + 'Path should follow the expected format and be under the folder specifed in `out`') + fs.stat(finalPath, cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The expected output directory should exist') + fs.stat(path.join(finalPath, util.generateResourcesPath(opts)), cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') + cb() + } + ], function (err) { + t.end(err) + }) + } +} + +function createAsarTest (combination) { + return function (t) { + t.timeoutAfter(config.timeout) + + var opts = Object.create(combination) + opts.name = 'basicTest' + opts.dir = path.join(__dirname, 'fixtures', 'basic') + opts.asar = true + + var finalPath + var resourcesPath + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (paths, cb) { + finalPath = paths[0] + fs.stat(finalPath, cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The expected output directory should exist') + resourcesPath = path.join(finalPath, util.generateResourcesPath(opts)) + fs.stat(resourcesPath, cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') + fs.stat(path.join(resourcesPath, 'app.asar'), cb) + }, function (stats, cb) { + t.true(stats.isFile(), 'app.asar should exist under the resources subdirectory when opts.asar is true') + fs.exists(path.join(resourcesPath, 'app'), function (exists) { + t.false(exists, 'app subdirectory should NOT exist when app.asar is built') + cb() + }) + } + ], function (err) { + t.end(err) + }) + } +} + +function createPruneTest (combination) { + return function (t) { + t.timeoutAfter(config.timeout) + + var opts = Object.create(combination) + opts.name = 'basicTest' + opts.dir = path.join(__dirname, 'fixtures', 'basic') + opts.prune = true + + var finalPath + var resourcesPath + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (paths, cb) { + finalPath = paths[0] + fs.stat(finalPath, cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The expected output directory should exist') + resourcesPath = path.join(finalPath, util.generateResourcesPath(opts)) + fs.stat(resourcesPath, cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') + fs.stat(path.join(resourcesPath, 'app', 'node_modules', 'run-series'), cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'npm dependency should exist under app/node_modules') + fs.exists(path.join(resourcesPath, 'app', 'node_modules', 'run-waterfall'), function (exists) { + t.false(exists, 'npm devDependency should NOT exist under app/node_modules') + cb() + }) + } + ], function (err) { + t.end(err) + }) + } +} + +function createIgnoreTest (combination, ignorePattern, ignoredFile) { + return function (t) { + t.timeoutAfter(config.timeout) + + var opts = Object.create(combination) + opts.name = 'basicTest' + opts.dir = path.join(__dirname, 'fixtures', 'basic') + opts.ignore = ignorePattern + + var appPath + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (paths, cb) { + appPath = path.join(paths[0], util.generateResourcesPath(opts), 'app') + fs.stat(path.join(appPath, 'package.json'), cb) + }, function (stats, cb) { + t.true(stats.isFile(), 'The expected output directory should exist and contain files') + fs.exists(path.join(appPath, ignoredFile), function (exists) { + t.false(exists, 'Ignored file should not exist in output app directory') + cb() + }) + } + ], function (err) { + t.end(err) + }) + } +} + +function createOverwriteTest (combination) { + return function (t) { + t.timeoutAfter(config.timeout * 2) // Multiplied since this test packages the application twice + + var opts = Object.create(combination) + opts.name = 'basicTest' + opts.dir = path.join(__dirname, 'fixtures', 'basic') + + var finalPath + var testPath + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (paths, cb) { + finalPath = paths[0] + fs.stat(finalPath, cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The expected output directory should exist') + // Create a dummy file to detect whether the output directory is replaced in subsequent runs + testPath = path.join(finalPath, 'test.txt') + fs.writeFile(testPath, 'test', cb) + }, function (cb) { + // Run again, defaulting to overwrite false + packager(opts, cb) + }, function (paths, cb) { + fs.stat(testPath, cb) + }, function (stats, cb) { + t.true(stats.isFile(), 'The existing output directory should exist as before (skipped by default)') + // Run a third time, explicitly setting overwrite to true + opts.overwrite = true + packager(opts, cb) + }, function (paths, cb) { + fs.exists(testPath, function (exists) { + t.false(exists, 'The output directory should be regenerated when overwrite is true') + cb() + }) + } + ], function (err) { + t.end(err) + }) + } +} + +util.testAllPlatforms('defaults test', createDefaultsTest) +util.testAllPlatforms('out test', createOutTest) +util.testAllPlatforms('asar test', createAsarTest) +util.testAllPlatforms('prune test', createPruneTest) +util.testAllPlatforms('ignore test: string in array', createIgnoreTest, ['ignorethis'], 'ignorethis.txt') +util.testAllPlatforms('ignore test: string', createIgnoreTest, 'ignorethis', 'ignorethis.txt') +util.testAllPlatforms('ignore test: RegExp', createIgnoreTest, /ignorethis/, 'ignorethis.txt') +util.testAllPlatforms('ignore test: string with slash', createIgnoreTest, 'ignore/this', + path.join('ignore', 'this.txt')) +util.testAllPlatforms('ignore test: only match subfolder of app', createIgnoreTest, 'electron-packager', + path.join('electron-packager', 'readme.txt')) +util.testAllPlatforms('overwrite test', createOverwriteTest) diff --git a/test/config.json b/test/config.json new file mode 100644 index 0000000..d090330 --- /dev/null +++ b/test/config.json @@ -0,0 +1,4 @@ +{ + "timeout": 15000, + "version": "0.28.3" +} diff --git a/test/fixtures/basic/electron-packager/readme.txt b/test/fixtures/basic/electron-packager/readme.txt new file mode 100644 index 0000000..346ca28 --- /dev/null +++ b/test/fixtures/basic/electron-packager/readme.txt @@ -0,0 +1,2 @@ +This file exists to test ability to ignore paths under app, without also +ignoring the entire app folder due to a match above it (#54 / #55). diff --git a/test/fixtures/basic/ignore/this.txt b/test/fixtures/basic/ignore/this.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/basic/ignorethis.txt b/test/fixtures/basic/ignorethis.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/test/fixtures/basic/ignorethis.txt @@ -0,0 +1 @@ + diff --git a/test/fixtures/basic/index.html b/test/fixtures/basic/index.html new file mode 100644 index 0000000..c0617ee --- /dev/null +++ b/test/fixtures/basic/index.html @@ -0,0 +1,4 @@ + + + Hello, world! + diff --git a/test/fixtures/basic/main.js b/test/fixtures/basic/main.js new file mode 100644 index 0000000..bbe90c7 --- /dev/null +++ b/test/fixtures/basic/main.js @@ -0,0 +1,22 @@ +var app = require('app') +var BrowserWindow = require('browser-window') +var mainWindow + +app.on('window-all-closed', function () { + app.quit() +}) + +app.on('ready', function () { + mainWindow = new BrowserWindow({ + center: true, + title: 'Basic Test', + width: 800, + height: 600 + }) + + mainWindow.loadUrl('file://' + require('path').resolve(__dirname, 'index.html')) + + mainWindow.on('closed', function () { + mainWindow = null + }) +}) diff --git a/test/fixtures/basic/package.json b/test/fixtures/basic/package.json new file mode 100644 index 0000000..b52b350 --- /dev/null +++ b/test/fixtures/basic/package.json @@ -0,0 +1,9 @@ +{ + "main": "main.js", + "dependencies": { + "run-series": "^1.1.1" + }, + "devDependencies": { + "run-waterfall": "^1.1.1" + } +} diff --git a/test/fixtures/monochrome.icns b/test/fixtures/monochrome.icns new file mode 100644 index 0000000000000000000000000000000000000000..dc02de9364e0b544a0dd0620131d53e770ef9aa4 GIT binary patch literal 274820 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 literal 0 HcmV?d00001 diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..3450386 --- /dev/null +++ b/test/index.js @@ -0,0 +1,27 @@ +var exec = require('child_process').exec +var path = require('path') + +var series = require('run-series') + +var config = require('./config.json') +var util = require('./util') + +// Download all Electron distributions before running tests to avoid timing out due to network speed +series([ + function (cb) { + console.log('Calling electron-download before running tests...') + util.downloadAll(config.version, cb) + }, function (cb) { + console.log('Running npm install in fixtures/basic...') + exec('npm install', {cwd: path.join(__dirname, 'fixtures', 'basic')}, cb) + } +], function () { + console.log('Running tests...') + require('./basic') + require('./multitarget') + + if (process.platform !== 'win32') { + // Perform additional tests specific to building for OS X + require('./mac') + } +}) diff --git a/test/mac.js b/test/mac.js new file mode 100644 index 0000000..012b5ee --- /dev/null +++ b/test/mac.js @@ -0,0 +1,94 @@ +var exec = require('child_process').exec +var fs = require('fs') +var path = require('path') + +var packager = require('..') +var test = require('tape') +var waterfall = require('run-waterfall') + +var config = require('./config.json') +var util = require('./util') + +function createIconTest (icon, iconPath) { + return function (t) { + t.timeoutAfter(config.timeout) + + var opts = { + name: 'basicTest', + dir: path.join(__dirname, 'fixtures', 'basic'), + version: config.version, + arch: 'x64', + platform: 'darwin', + icon: icon + } + + var resourcesPath + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (paths, cb) { + resourcesPath = path.join(paths[0], util.generateResourcesPath(opts)) + fs.stat(resourcesPath, cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') + util.areFilesEqual(iconPath, path.join(resourcesPath, 'atom.icns'), cb) + }, function (equal, cb) { + t.true(equal, 'atom.icns should be identical to the specified icon file') + cb() + } + ], function (err) { + t.end(err) + }) + } +} + +var iconBase = path.join(__dirname, 'fixtures', 'monochrome') +var icnsPath = iconBase + '.icns' +util.setup() +test('icon test: .icns specified', createIconTest(icnsPath, icnsPath)) +util.teardown() + +util.setup() +test('icon test: .ico specified (should replace with .icns)', createIconTest(iconBase + '.ico', icnsPath)) +util.teardown() + +util.setup() +test('icon test: basename only (should add .icns)', createIconTest(iconBase, icnsPath)) +util.teardown() + +util.setup() +test('codesign test', function (t) { + t.timeoutAfter(config.timeout) + + var opts = { + name: 'basicTest', + dir: path.join(__dirname, 'fixtures', 'basic'), + version: config.version, + arch: 'x64', + platform: 'darwin', + sign: '-' // Ad-hoc + } + + var appPath + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (paths, cb) { + appPath = path.join(paths[0], opts.name + '.app') + fs.stat(appPath, cb) + }, function (stats, cb) { + t.true(stats.isDirectory(), 'The expected .app directory should exist') + exec('codesign --verify --deep ' + appPath, cb) + }, function (stdout, stderr, cb) { + t.pass('codesign should verify successfully') + cb() + } + ], function (err) { + var notFound = err && err.code === 127 + if (notFound) console.log('codesign not installed; skipped') + t.end(notFound ? null : err) + }) +}) +util.teardown() diff --git a/test/multitarget.js b/test/multitarget.js new file mode 100644 index 0000000..1c9240d --- /dev/null +++ b/test/multitarget.js @@ -0,0 +1,145 @@ +var fs = require('fs') +var path = require('path') + +var packager = require('..') +var series = require('run-series') +var test = require('tape') +var waterfall = require('run-waterfall') + +var config = require('./config.json') +var util = require('./util') + +function verifyPackageExistence (finalPaths, callback) { + series(finalPaths.map(function (finalPath) { + return function (cb) { + fs.stat(finalPath, cb) + } + }), function (err, statsResults) { + if (err) return callback(null, false) + + callback(null, statsResults.every(function (stats) { + return stats.isDirectory() + })) + }) +} + +util.setup() +test('all test', function (t) { + t.timeoutAfter(config.timeout * 5) // 4-5 packages will be built during this test + + var opts = { + name: 'basicTest', + dir: path.join(__dirname, 'fixtures', 'basic'), + version: config.version, + all: true + } + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (finalPaths, cb) { + // Windows skips packaging for OS X, and OS X only has 64-bit releases + t.equal(finalPaths.length, process.platform === 'win32' ? 4 : 5, + 'packager call should resolve with expected number of paths') + verifyPackageExistence(finalPaths, cb) + }, function (exists, cb) { + t.true(exists, 'Packages should be generated for all possible platforms') + cb() + } + ], function (err) { + t.end(err) + }) +}) +util.teardown() + +util.setup() +test('platform=all test (one arch)', function (t) { + t.timeoutAfter(config.timeout * 2) // 2 packages will be built during this test + + var opts = { + name: 'basicTest', + dir: path.join(__dirname, 'fixtures', 'basic'), + version: config.version, + arch: 'ia32', + platform: 'all' + } + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (finalPaths, cb) { + t.equal(finalPaths.length, 2, 'packager call should resolve with expected number of paths') + verifyPackageExistence(finalPaths, cb) + }, function (exists, cb) { + t.true(exists, 'Packages should be generated for both 32-bit platforms') + cb() + } + ], function (err) { + t.end(err) + }) +}) +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 + + var opts = { + name: 'basicTest', + dir: path.join(__dirname, 'fixtures', 'basic'), + version: config.version, + arch: 'all', + platform: 'linux' + } + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (finalPaths, cb) { + t.equal(finalPaths.length, 2, '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') + cb() + } + ], function (err) { + t.end(err) + }) +}) +util.teardown() + +function createMultiTest (arch, platform) { + return function (t) { + t.timeoutAfter(config.timeout * 4) // 4 packages will be built during this test + + var opts = { + name: 'basicTest', + dir: path.join(__dirname, 'fixtures', 'basic'), + version: config.version, + arch: arch, + platform: platform + } + + waterfall([ + function (cb) { + packager(opts, cb) + }, function (finalPaths, cb) { + t.equal(finalPaths.length, 4, 'packager call should resolve with expected number of paths') + verifyPackageExistence(finalPaths, cb) + }, function (exists, cb) { + t.true(exists, 'Packages should be generated for all combinations of specified archs and platforms') + cb() + } + ], function (err) { + t.end(err) + }) + } +} + +util.setup() +test('multi-platform / multi-arch test, from arrays', createMultiTest(['ia32', 'x64'], ['linux', 'win32'])) +util.teardown() + +util.setup() +test('multi-platform / multi-arch test, from strings', createMultiTest('ia32,x64', 'linux,win32')) +util.teardown() diff --git a/test/test.js b/test/test.js deleted file mode 100644 index 8ad1575..0000000 --- a/test/test.js +++ /dev/null @@ -1,45 +0,0 @@ -var test = require('tape') -var mkdirp = require('mkdirp') -var rimraf = require('rimraf') -var packager = require('../index.js') - -var distdir = __dirname + '/dist' -rimraf.sync(distdir) -mkdirp.sync(distdir) - -var opts = { - dir: __dirname + '/testapp', - name: 'Test', - version: '0.28.2', - out: distdir -} - -test('package for windows', function (t) { - opts.platform = 'win32' - opts.arch = 'ia32' - - packager(opts, function done (err, appPath) { - t.notOk(err, 'no err') - t.end() - }) -}) - -test('package for linux', function (t) { - opts.platform = 'linux' - opts.arch = 'x64' - - packager(opts, function done (err, appPath) { - t.notOk(err, 'no err') - t.end() - }) -}) - -test('package for darwin', function (t) { - opts.platform = 'darwin' - opts.arch = 'x64' - - packager(opts, function done (err, appPath) { - t.notOk(err, 'no err') - t.end() - }) -}) diff --git a/test/testapp/index.js b/test/testapp/index.js deleted file mode 100644 index f1f8787..0000000 --- a/test/testapp/index.js +++ /dev/null @@ -1,6 +0,0 @@ -var app = require('app') - -app.on('ready', function () { - console.log('pizza') - app.exit() -}) diff --git a/test/testapp/package.json b/test/testapp/package.json deleted file mode 100644 index 7d87093..0000000 --- a/test/testapp/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "testapp", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "BSD-2-Clause" -} diff --git a/test/util.js b/test/util.js new file mode 100644 index 0000000..f3b23cc --- /dev/null +++ b/test/util.js @@ -0,0 +1,100 @@ +var fs = require('fs') +var path = require('path') +var test = require('tape') + +var download = require('electron-download') +var mkdirp = require('mkdirp') +var rimraf = require('rimraf') +var series = require('run-series') + +var ORIGINAL_CWD = process.cwd() +var WORK_CWD = path.join(__dirname, 'work') + +var archs = ['ia32', 'x64'] +var platforms = ['darwin', 'linux', 'win32'] +var slice = Array.prototype.slice +var version = require('./config.json').version + +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 + // Also skip testing darwin target on Windows since electron-packager itself skips it + // (see https://github.com/maxogden/electron-packager/issues/71) + if (platform === 'darwin' && (arch === 'ia32' || require('os').platform() === 'win32')) return + + combinations.push({ + arch: arch, + platform: platform, + version: version + }) + }) +}) + +exports.areFilesEqual = function areFilesEqual (file1, file2, callback) { + series([ + function (cb) { + fs.readFile(file1, cb) + }, + function (cb) { + fs.readFile(file2, cb) + } + ], function (err, buffers) { + callback(err, slice.call(buffers[0]).every(function (b, i) { + return b === buffers[1][i] + })) + }) +} + +exports.downloadAll = function downloadAll (version, callback) { + series(combinations.map(function (combination) { + return function (cb) { + download(combination, cb) + } + }), callback) +} + +exports.forEachCombination = function forEachCombination (cb) { + combinations.forEach(cb) +} + +exports.generateResourcesPath = function generateResourcesPath (opts) { + return opts.platform === 'darwin' ? path.join(opts.name + '.app', 'Contents', 'Resources') : 'resources' +} + +exports.getWorkCwd = function getWorkCwd () { + return WORK_CWD +} + +// tape doesn't seem to have a provision for before/beforeEach/afterEach/after, +// so run setup/teardown and cleanup tasks as additional "tests" to put them in sequence +// and run them irrespective of test failures + +exports.setup = function setup () { + test('setup', function (t) { + mkdirp(WORK_CWD, function (err) { + if (err) t.end(err) + process.chdir(WORK_CWD) + t.end() + }) + }) +} + +exports.teardown = function teardown () { + test('teardown', function (t) { + process.chdir(ORIGINAL_CWD) + rimraf(WORK_CWD, function (err) { + t.end(err) + }) + }) +} + +exports.testAllPlatforms = function testAllPlatforms (name, createTest /*, ...createTestArgs */) { + var args = slice.call(arguments, 2) + exports.setup() + exports.forEachCombination(function (combination) { + test(name + ': ' + combination.platform + '-' + combination.arch, + createTest.apply(null, [combination].concat(args))) + }) + exports.teardown() +}