diff --git a/index.js b/index.js index 30958dd..3c4a3c9 100644 --- a/index.js +++ b/index.js @@ -1,15 +1,9 @@ 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 ncp = require('ncp').ncp module.exports = function packager (opts, cb) { var electronPath + var platform try { electronPath = require.resolve('electron-prebuilt') @@ -26,110 +20,11 @@ module.exports = function packager (opts, cb) { var electronPkg = require(path.join(electronPath, 'package.json')) console.error('Using electron-prebuilt version', electronPkg.version, 'from', electronPath) - var electronApp = path.join(electronPath, 'dist', 'Electron.app') - var tmpDir = path.join(os.tmpdir(), 'electron-packager-mac') - - var newApp = path.join(tmpDir, opts.name + '.app') - - // 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() - }) - }) - }) - - function buildMacApp () { - 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') - } - - // 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)) - - function filter (file) { - 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 - } - - // copy users app into .app - ncp(opts.dir, paths.app, {filter: filter}, function copied (err) { - if (err) return cb(err) - - if (opts.prune) { - prune(function pruned (err) { - if (err) return cb(err) - moveApp() - }) - } else { - moveApp() - } - - function prune (cb) { - child.exec('npm prune --production', { cwd: paths.app }, cb) - } - - function moveApp () { - // finally, move app into cwd - var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app') - - fs.rename(newApp, finalPath, function moved (err) { - if (err) return cb(err) - updateMacIcon() - }) - } - }) + switch (os.platform()) { + case 'darwin': platform = require('./mac'); break + case 'linux': platform = require('./linux'); break + default: cb(new Error('Unsupported platform')) } - function updateMacIcon () { - var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app') - - if (!opts.icon) { - return cb(null, finalPath) - } - - ncp(opts.icon, path.join(finalPath, 'Contents', 'Resources', 'atom.icns'), function copied (err) { - cb(err, finalPath) - }) - } + platform.createApp(opts, cb, electronPath) } diff --git a/linux.js b/linux.js new file mode 100644 index 0000000..9b2a5de --- /dev/null +++ b/linux.js @@ -0,0 +1,71 @@ +var path = require('path') +var fs = require('fs') +var child = require('child_process') +var mkdirp = require('mkdirp') +var ncp = require('ncp').ncp + +module.exports = { + createApp: function createApp (opts, cb, electronPath) { + var templateApp = path.join(electronPath, 'dist') + var finalDir = opts.out || path.join(process.cwd(), 'dist') + var userAppDir = path.join(finalDir, 'resources', 'default_app') + var originalBinary = path.join(finalDir, 'electron') + var finalBinary = path.join(finalDir, opts.name) + + function copyApp () { + mkdirp(finalDir, function AppFolderCreated (err) { + if (err) return cb(err) + copyAppTemplate() + }) + } + + function copyAppTemplate () { + ncp(templateApp, finalDir, {filter: appFilter}, function AppCreated (err) { + if (err) return cb(err) + copyUserApp() + }) + } + + function copyUserApp () { + ncp(opts.dir, userAppDir, {filter: userFilter}, function copied (err) { + if (err) return cb(err) + if (opts.prune) { + prune(function pruned (err) { + if (err) return cb(err) + renameElectronBinary() + }) + } else { + renameElectronBinary() + } + }) + } + + function renameElectronBinary () { + fs.rename(originalBinary, finalBinary, function electronRenamed (err) { + if (err) return cb(err) + }) + } + + function prune (cb) { + child.exec('npm prune --production', { cwd: userAppDir }, cb) + } + + function appFilter (file) { + return file.match(/default_app/) === null + } + + function userFilter (file) { + var ignore = opts.ignore || [] + if (!Array.isArray(ignore)) ignore = [ignore] + ignore = ignore.concat([finalDir]) + for (var i = 0; i < ignore.length; i++) { + if (file.match(ignore[i])) { + return false + } + } + return true + } + + copyApp() + } +} diff --git a/mac.js b/mac.js new file mode 100644 index 0000000..338f05b --- /dev/null +++ b/mac.js @@ -0,0 +1,120 @@ +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 ncp = require('ncp').ncp + +module.exports = { + createApp: function createApp (opts, cb, electronPath) { + var electronApp = path.join(electronPath, 'dist', 'Electron.app') + var tmpDir = path.join(os.tmpdir(), 'electron-packager-mac') + + var newApp = path.join(tmpDir, opts.name + '.app') + + // 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) + }) + }) + }) + } +} + +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') + } + + // 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)) + + function filter (file) { + 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 + } + + // copy users app into .app + ncp(opts.dir, paths.app, {filter: filter}, function copied (err) { + if (err) return cb(err) + + if (opts.prune) { + prune(function pruned (err) { + if (err) return cb(err) + moveApp() + }) + } else { + moveApp() + } + + function prune (cb) { + child.exec('npm prune --production', { cwd: paths.app }, cb) + } + + function moveApp () { + // finally, move app into cwd + var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app') + + fs.rename(newApp, finalPath, function moved (err) { + if (err) return cb(err) + updateMacIcon() + }) + } + + function updateMacIcon () { + var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app') + + if (!opts.icon) { + return cb(null, finalPath) + } + + ncp(opts.icon, path.join(finalPath, 'Contents', 'Resources', 'atom.icns'), function copied (err) { + cb(err, finalPath) + }) + } + }) +}