Skip to content

Commit

Permalink
Add cnpm support and refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
malept committed Apr 29, 2017
1 parent 330196c commit 4fd4be3
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 64 deletions.
2 changes: 0 additions & 2 deletions .travis.yml
Expand Up @@ -32,5 +32,3 @@ env:
# prevent wine popup dialogs about installing additional packages
- WINEDLLOVERRIDES="mscoree,mshtml="
- WINEDEBUG="-all"
# temporarily enable debug logging to diagnose flaky spec failures
- DEBUG=electron-packager
4 changes: 4 additions & 0 deletions NEWS.md
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Added

* `packageManager` (`--package-manager` via CLI) option (#618)

## [8.6.0] - 2017-03-14

### Added
Expand Down
15 changes: 2 additions & 13 deletions common.js
@@ -1,14 +1,14 @@
'use strict'

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 pruneModules = require('./prune').pruneModules
const sanitize = require('sanitize-filename')
const semver = require('semver')
const series = require('run-series')
Expand Down Expand Up @@ -88,18 +88,6 @@ function asarApp (appPath, asarOptions, cb) {
})
}

function pruneModules (opts, appPath, cb) {
var pmName = opts['package-manager']
if (pmName !== undefined && pmName === 'yarn') {
child.exec('yarn install --production ', { cwd: appPath }, cb)
} else if (pmName !== undefined && pmName !== 'npm') {
warning(`specified package-manager "${pmName}" is not available, use {"npm", "yarn"} instead`)
} else {
// defaults to npm
child.exec('npm prune --production', { cwd: appPath }, cb)
}
}

function isPlatformMac (platform) {
return platform === 'darwin' || platform === 'mas'
}
Expand Down Expand Up @@ -210,6 +198,7 @@ module.exports = {
'app-copyright': 'appCopyright',
'app-version': 'appVersion',
'build-version': 'buildVersion',
'package-manager': 'packageManager',
'app-bundle-id': 'appBundleId',
'app-category-type': 'appCategoryType',
'extend-info': 'extendInfo',
Expand Down
17 changes: 15 additions & 2 deletions docs/api.md
Expand Up @@ -211,7 +211,19 @@ The base directory where the finished package(s) are created.

Whether to replace an already existing output directory for a given platform (`true`) or skip recreating it (`false`).

#### `platform`
##### `packageManager`

*String* (default: `npm`)

The package manager used to [prune](#prune) `devDependencies` modules from the outputted Electron
app. Supported package managers:

* [`npm`](https://npmjs.com/)
* [`cnpm`](https://github.com/cnpm/cnpm) (Does not currently work with Windows, see
[GitHub issue](https://github.com/electron-userland/electron-packager/issues/515#issuecomment-297604044))
* [`yarn`](https://yarnpkg.com/)

##### `platform`

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

Expand All @@ -227,7 +239,8 @@ The non-`all` values correspond to the platform names used by [Electron releases

*Boolean* (default: `true`)

Runs [`npm prune --production`](https://docs.npmjs.com/cli/prune) before starting to package the app.
Runs the [package manager](#packagemanager) command to remove all of the packages specified in the
`devDependencies` section of `package.json` from the outputted Electron app.

##### `quiet`

Expand Down
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -44,7 +44,8 @@
"pkg-up": "^1.0.0",
"rimraf": "^2.3.2",
"run-waterfall": "^1.1.1",
"tape": "^4.0.0"
"tape": "^4.0.0",
"which": "^1.2.14"
},
"engines": {
"node": ">= 4.0"
Expand Down
38 changes: 38 additions & 0 deletions prune.js
@@ -0,0 +1,38 @@
'use strict'

const child = require('child_process')
const debug = require('debug')('electron-packager')

const knownPackageManagers = ['npm', 'cnpm', 'yarn']

function pruneCommand (packageManager) {
switch (packageManager) {
case 'npm':
case 'cnpm':
return `${packageManager} prune --production`
case 'yarn':
return `${packageManager} install --production`
}
}

function pruneModules (opts, appPath, cb) {
const packageManager = opts.packageManager || 'npm'

if (packageManager === 'cnpm' && process.platform === 'win32') {
return cb(new Error('cnpm support does not currently work with Windows, see: https://github.com/electron-userland/electron-packager/issues/515#issuecomment-297604044'))
}

const command = pruneCommand(packageManager)

if (command) {
debug(`Pruning modules via: ${command}`)
child.exec(command, { cwd: appPath }, cb)
} else {
cb(new Error(`Unknown package manager "${packageManager}". Known package managers: ${knownPackageManagers.join(', ')}`))
}
}

module.exports = {
pruneCommand: pruneCommand,
pruneModules: pruneModules
}
44 changes: 0 additions & 44 deletions test/basic.js
Expand Up @@ -122,44 +122,6 @@ function createOutTest (opts) {
}
}

function createPruneOptionTest (baseOpts, prune, testMessage) {
return (t) => {
t.timeoutAfter(config.timeout)

let opts = Object.create(baseOpts)
opts.name = 'basicTest'
opts.dir = path.join(__dirname, 'fixtures', 'basic')
opts.prune = prune

let finalPath
let resourcesPath

waterfall([
(cb) => {
packager(opts, cb)
}, (paths, cb) => {
finalPath = paths[0]
fs.stat(finalPath, cb)
}, (stats, cb) => {
t.true(stats.isDirectory(), 'The expected output directory should exist')
resourcesPath = path.join(finalPath, util.generateResourcesPath(opts))
fs.stat(resourcesPath, cb)
}, (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)
}, (stats, cb) => {
t.true(stats.isDirectory(), 'npm dependency should exist under app/node_modules')
fs.exists(path.join(resourcesPath, 'app', 'node_modules', 'run-waterfall'), (exists) => {
t.equal(!prune, exists, testMessage)
cb()
})
}
], (err) => {
t.end(err)
})
}
}

function createOverwriteTest (opts) {
return function (t) {
t.timeoutAfter(config.timeout * 2) // Multiplied since this test packages the application twice
Expand Down Expand Up @@ -370,12 +332,6 @@ test('cannot build apps where the name ends in " Helper"', (t) => {

util.testSinglePlatform('defaults test', createDefaultsTest)
util.testSinglePlatform('out test', createOutTest)
util.testSinglePlatform('prune test', (baseOpts) => {
return createPruneOptionTest(baseOpts, true, 'npm devDependency should NOT exist under app/node_modules')
})
util.testSinglePlatform('prune=false test', (baseOpts) => {
return createPruneOptionTest(baseOpts, false, 'npm devDependency should exist under app/node_modules')
})
util.testSinglePlatform('overwrite test', createOverwriteTest)
util.testSinglePlatform('tmpdir test', createTmpdirTest)
util.testSinglePlatform('tmpdir test', createDisableTmpdirUsingTest)
Expand Down
8 changes: 7 additions & 1 deletion test/ci/before_install.sh
Expand Up @@ -6,9 +6,11 @@ case "$TRAVIS_OS_NAME" in
# Not using Trusty containers because it can't install wine1.6(-i386),
# see: https://github.com/travis-ci/travis-ci/issues/6460
sudo rm /etc/apt/sources.list.d/google-chrome.list
sudo apt-key adv --fetch-keys http://dl.yarnpkg.com/debian/pubkey.gpg
echo "deb http://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install -y wine1.6
sudo apt-get install -y wine1.6 yarn
;;
"osx")
# Create CA
Expand All @@ -29,5 +31,9 @@ case "$TRAVIS_OS_NAME" in
npm install wine-darwin@1.9.17-1
# Setup ~/.wine by running a command
./node_modules/.bin/wine hostname
# Install yarn
npm install -g yarn
;;
esac

npm install -g cnpm
1 change: 1 addition & 0 deletions test/index.js
Expand Up @@ -53,6 +53,7 @@ series(setupFuncs, (error) => {
require('./infer')
require('./hooks')
require('./multitarget')
require('./prune')
require('./win32')

if (process.platform !== 'win32') {
Expand Down
97 changes: 97 additions & 0 deletions test/prune.js
@@ -0,0 +1,97 @@
'use strict'

const config = require('./config.json')
const fs = require('fs-extra')
const packager = require('..')
const path = require('path')
const prune = require('../prune')
const test = require('tape')
const util = require('./util')
const waterfall = require('run-waterfall')
const which = require('which')

function createPruneOptionTest (baseOpts, prune, testMessage) {
return (t) => {
t.timeoutAfter(config.timeout)

let opts = Object.create(baseOpts)
opts.name = 'basicTest'
opts.dir = path.join(__dirname, 'fixtures', 'basic')
opts.prune = prune

let finalPath
let resourcesPath

waterfall([
(cb) => {
packager(opts, cb)
}, (paths, cb) => {
finalPath = paths[0]
fs.stat(finalPath, cb)
}, (stats, cb) => {
t.true(stats.isDirectory(), 'The expected output directory should exist')
resourcesPath = path.join(finalPath, util.generateResourcesPath(opts))
fs.stat(resourcesPath, cb)
}, (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)
}, (stats, cb) => {
t.true(stats.isDirectory(), 'package.json dependency should exist under app/node_modules')
fs.exists(path.join(resourcesPath, 'app', 'node_modules', 'run-waterfall'), (exists) => {
t.equal(!prune, exists, testMessage)
cb()
})
}
], (err) => {
t.end(err)
})
}
}

test('pruneCommand returns the correct command when passing a known package manager', (t) => {
t.equal(prune.pruneCommand('npm'), 'npm prune --production', 'passing npm gives the npm prune command')
t.equal(prune.pruneCommand('cnpm'), 'cnpm prune --production', 'passing cnpm gives the cnpm prune command')
t.equal(prune.pruneCommand('yarn'), 'yarn install --production', 'passing yarn gives the yarn "prune command"')
t.end()
})

test('pruneCommand returns null when the package manager is unknown', (t) => {
t.notOk(prune.pruneCommand('unknown-package-manager'))
t.end()
})

test('pruneModules returns an error when the package manager is unknown', (t) => {
prune.pruneModules({packageManager: 'unknown-package-manager'}, '/tmp/app-path', (err) => {
t.ok(err, 'error returned')
t.end()
})
})

if (process.platform === 'win32') {
test('pruneModules returns an error when trying to use cnpm on Windows', (t) => {
prune.pruneModules({packageManager: 'cnpm'}, '/tmp/app-path', (err) => {
t.ok(err, 'error returned')
t.end()
})
})
}

// This is not in the below loop so that it tests the default packageManager option.
util.testSinglePlatform('prune test with npm', (baseOpts) => {
return createPruneOptionTest(baseOpts, true, 'package.json devDependency should NOT exist under app/node_modules')
})

for (const packageManager of ['cnpm', 'yarn']) {
which(packageManager, (err, resolvedPath) => {
if (err) return

util.testSinglePlatform(`prune test with ${packageManager}`, (baseOpts) => {
const opts = Object.assign({packageManager: packageManager}, baseOpts)
return createPruneOptionTest(opts, true, 'package.json devDependency should NOT exist under app/node_modules')
})
})
}

util.testSinglePlatform('prune=false test', (baseOpts) => {
return createPruneOptionTest(baseOpts, false, 'npm devDependency should exist under app/node_modules')
})
4 changes: 3 additions & 1 deletion usage.txt
Expand Up @@ -46,10 +46,12 @@ icon the local path to an icon file to use as the icon for the app
ignore do not copy files into app whose filenames regex .match this string. See also:
https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#ignore
and --no-prune.
no-prune do not run `npm prune --production` on the app
no-prune do not prune devDependencies from the packaged app
out the dir to put the app into at the end. defaults to current working dir
overwrite if output directory for a platform already exists, replaces it rather than
skipping it
package-manager the package manager to use when pruning devDependencies. Supported package
managers: npm (default), cnpm, yarn
platform all, or one or more of: darwin, linux, mas, win32 (comma-delimited if multiple).
Defaults to the host platform
quiet Do not print informational or warning messages
Expand Down

0 comments on commit 4fd4be3

Please sign in to comment.