diff --git a/cli.js b/cli.js index f24e7f5..f1e0c96 100755 --- a/cli.js +++ b/cli.js @@ -1,6 +1,8 @@ #!/usr/bin/env node +var fs = require('fs') var args = require('minimist')(process.argv.slice(2), {boolean: ['prune', 'asar']}) var packager = require('./') +var usage = fs.readFileSync(__dirname + '/usage.txt').toString() args.dir = args._[0] args.name = args._[1] @@ -14,14 +16,14 @@ if (protocolSchemes && protocolNames && protocolNames.length === protocolSchemes }) } -if (!args.dir || !args.name) { - console.error('Usage: electron-packager ') +if (!args.dir || !args.name || !args.platform || !args.arch || !args.version) { + console.error(usage) process.exit(1) } -console.log('args', args) + packager(args, function done (err, appPath) { if (err) { - console.error(err.stack) + console.error(err, err.stack) process.exit(1) } diff --git a/index.js b/index.js index d54bc3c..d8e2b8a 100644 --- a/index.js +++ b/index.js @@ -1,31 +1,48 @@ -var os = require('os') var path = require('path') +var os = require('os') + +var download = require('electron-download') +var extract = require('extract-zip') +var mkdirp = require('mkdirp') +var rimraf = require('rimraf') + +var mac = require('./mac.js') +var linux = require('./linux.js') +var win32 = require('./win32.js') module.exports = function packager (opts, cb) { - var electronPath - var platform + var packager + var platform = opts.platform + var arch = opts.arch + var version = opts.version - try { - electronPath = require.resolve('electron-prebuilt') - electronPath = path.join(electronPath, '..') - } catch (e) { - try { - electronPath = require.resolve(path.join(process.execPath, '../../lib/node_modules/electron-prebuilt')) - electronPath = path.join(electronPath, '..') - } catch (e) { - cb(new Error('Cannot find electron-prebuilt from here, please install it from npm')) - } - } + if (!platform || !arch || !version) cb(new Error('Must specify platform, arch and version')) - var electronPkg = require(path.join(electronPath, 'package.json')) - console.error('Using electron-prebuilt version', electronPkg.version, 'from', electronPath) - - switch (os.platform()) { - case 'darwin': platform = require('./mac'); break - case 'linux': platform = require('./linux'); break - case 'win32': platform = require('./windows'); break + switch (platform) { + case 'darwin': packager = mac; break + case 'linux': packager = linux; break + case 'win32': packager = win32; break default: cb(new Error('Unsupported platform')) } - platform.createApp(opts, cb, electronPath) + download({ + platform: platform, + arch: arch, + version: version + }, function (err, zipPath) { + 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) + packager.createApp(opts, tmpDir, cb) + }) + }) + }) + }) } diff --git a/linux.js b/linux.js index 88ec7f1..75bea31 100644 --- a/linux.js +++ b/linux.js @@ -7,9 +7,8 @@ var rimraf = require('rimraf') var asar = require('asar') module.exports = { - createApp: function createApp (opts, cb, electronPath) { - var templateApp = path.join(electronPath, 'dist') - var finalDir = opts.out || path.join(process.cwd(), 'dist') + createApp: function createApp (opts, templateApp, cb) { + var finalDir = opts.out || path.join(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) @@ -48,7 +47,7 @@ module.exports = { if (opts.asar) { asarApp(cb) } else { - cb() + cb(null, finalBinary) } }) } @@ -78,7 +77,10 @@ module.exports = { var dest = path.join(finalDir, 'resources', 'app.asar') asar.createPackage(src, dest, function (err) { if (err) return cb(err) - rimraf(src, cb) + rimraf(src, function (err) { + if (err) return cb(err) + cb(null, dest) + }) }) } diff --git a/mac.js b/mac.js index c62a33a..daf11f0 100644 --- a/mac.js +++ b/mac.js @@ -10,8 +10,8 @@ var ncp = require('ncp').ncp var asar = require('asar') module.exports = { - createApp: function createApp (opts, cb, electronPath) { - var electronApp = path.join(electronPath, 'dist', 'Electron.app') + createApp: function createApp (opts, electronPath, cb) { + var electronApp = path.join(electronPath, 'Electron.app') var tmpDir = path.join(os.tmpdir(), 'electron-packager-mac') var newApp = path.join(tmpDir, opts.name + '.app') diff --git a/package.json b/package.json index be6fca0..f5046db 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "electron-packager", "version": "3.4.0", - "description": "package and distribute your electron app in OS executables (.app, .exe, etc) via JS or CLI", + "description": "package your electron app in OS executables (.app, .exe, etc) via JS or CLI", "main": "index.js", "bin": { "electron-packager": "cli.js" @@ -18,6 +18,8 @@ "homepage": "https://github.com/maxogden/electron-packager", "dependencies": { "asar": "^0.6.1", + "electron-download": "^1.0.0", + "extract-zip": "^1.0.3", "minimist": "^1.1.1", "mkdirp": "^0.5.0", "mv": "^2.0.3", diff --git a/readme.md b/readme.md index 4c2d42e..903e4eb 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ # electron-packager -Build a distributable app from an electron app source code directory. **Currently only Mac OS and Linux are implemented** but you can send PRs to implement windows :) +Package your electron app in OS executables (.app, .exe, etc) via JS or CLI. Supports building Windows, Linux or Mac executables. *formerly known as atom-shell-packager* @@ -8,8 +8,6 @@ Build a distributable app from an electron app source code directory. **Currentl [![Build Status](https://travis-ci.org/maxogden/electron-packager.svg?branch=master)](https://travis-ci.org/maxogden/electron-packager) -For an example project using this, check out [Monu](https://github.com/maxogden/monu) - ### installation ``` @@ -18,35 +16,38 @@ npm i electron-packager --save-dev # for use from cli npm i electron-packager -g - -# you also need electron installed -npm i electron-prebuilt ``` ### usage ``` -$ electron-packager my-app-source-dir AppName +Usage: electron-packager --platform= --arch= --version= + +Required options + +platform linux, win32, darwin +arch ia32, x64 +version see https://github.com/atom/electron/releases + +Example electron-packager ./ FooBar --platform=darwin --arch=x64 --version=0.25.1 + +Optional options + +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 +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 ``` This will: -- Find the closest local version of `electron` installed (using `require.resolve`) -- Use that version of electron to create a Mac app in `cwd` called `AppName.app` +- Find or download the correct release of Electron +- Use that version of electron to create a app in `cwd` named using `appname` for the platform you specified -You should be able to double-click `AppName.app` to launch the app. If not, check your settings and try again. +You should be able to launch the app on the platform you built for. If not, check your settings and try again. **Be careful** not to include node_modules you don't want into your final app. For example, do not include the `node_modules/electron-packager` folder or `node_modules/electron-prebuilt`. You can use `--ignore=node_modules/electron-prebuilt` to ignore of these - -### options - -these are optional CLI options you can pass in - -- `out` (default current working dir) - the dir to put the app into at the end -- `icon` - the icon file to use as the icon for the app -- `app-bundle-id` - bundle identifier to use in the app plist -- `app-version` - version to set for the app -- `helper-bundle-id` - bundle identifier to use in the app helper plist -- `ignore` (default none) - 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 diff --git a/usage.txt b/usage.txt new file mode 100644 index 0000000..fdc3c85 --- /dev/null +++ b/usage.txt @@ -0,0 +1,20 @@ +Usage: electron-packager --platform= --arch= --version= + +Required options + +platform linux, win32, darwin +arch ia32, x64 +version see https://github.com/atom/electron/releases + +Example electron-packager ./ FooBar --platform=darwin --arch=x64 --version=0.25.1 + +Optional options + +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 +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 diff --git a/windows.js b/win32.js similarity index 87% rename from windows.js rename to win32.js index d5a8f91..7f19474 100644 --- a/windows.js +++ b/win32.js @@ -10,18 +10,16 @@ var mv = require('mv') var rcedit = require('rcedit') module.exports = { - createApp: function createApp (opts, cb, electronPath) { - var electronApp = path.join(electronPath, 'dist') + createApp: function createApp (opts, electronApp, cb) { var tmpDir = path.join(os.tmpdir(), 'electron-packager-windows') - var newApp = path.join(tmpDir, opts.name + '.app') - console.log('newApp', newApp) + 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) + // 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 @@ -82,8 +80,7 @@ function buildWinApp (opts, cb, newApp) { function moveApp () { // finally, move app into cwd - var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app') - console.log('finalPath', finalPath) + 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) { @@ -98,13 +95,13 @@ function buildWinApp (opts, cb, newApp) { } function updateIcon () { - var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app') + var finalPath = path.join(opts.out || process.cwd(), opts.name + '-win32') if (!opts.icon) { return cb(null, finalPath) } - var exePath = path.join(opts.out || process.cwd(), opts.name + '.app', opts.name + '.exe') + var exePath = path.join(opts.out || process.cwd(), opts.name + '-win32', opts.name + '.exe') rcedit(exePath, {icon: opts.icon}, function (err) { cb(err, finalPath) @@ -113,7 +110,7 @@ function buildWinApp (opts, cb, newApp) { } function asarApp (cb) { - var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app', 'resources') + var finalPath = path.join(opts.out || process.cwd(), opts.name + '-win32', 'resources') var src = path.join(finalPath, 'app') var dest = path.join(finalPath, 'app.asar') asar.createPackage(src, dest, function (err) {