Skip to content
This repository has been archived by the owner on Aug 13, 2021. It is now read-only.

Refactor, eslint, Skip, dry-run and prefix features #4

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"rules" : {
"strict" : 0,
"no-underscore-dangle" : 0,
"no-multi-spaces" : 0,
"key-spacing" : 0,
"no-shadow" : 0,
"consistent-return" : 2,
"no-use-before-define" : 2,
"new-parens" : 2,
"no-cond-assign" : 2,
"space-after-keywords" : 2,
"space-infix-ops" : 2,
"comma-dangle" : [2, "never"],
"no-multiple-empty-lines" : [2, {"max": 2}],
"quotes" : [2, "single"],
"eqeqeq" : [2, "smart"],
"wrap-iife" : [2, "outside"],
"indent" : [2, 2],
"brace-style" : [2, "1tbs"],
"spaced-line-comment" : [2, "always", {"exceptions":["-","+"]}],
"space-before-function-parentheses": [2, {
"anonymous" : "always",
"named" : "never"
}]
},
"env": {
"node": true
}
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ results

npm-debug.log
node_modules
tmp
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# enpeem Changelog

### master
* [BREAKING ENHANCEMENT] Now requires at least Node 0.12.x or io.js 1.x.x
* [BREAKING ENHANCEMENT] All functions now return Promises.
* [ENHANCEMENT] Added eslint and improved tests
* [FEATURE] Added new `skip`, `dryRun` and `cmdPrefix` option.
28 changes: 21 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,41 @@ $ npm install enpeem --save
var npm = require('enpeem');
```

For all supported options look into the `index.js` file, specifically the `install` and `update` function.

#### npm install

```javascript
```js
// Returns a promise
npm.install({
dependencies: [
'[email protected]',
'sails-disk@git://github.com/balderdashy/sails-disk.git#associations',
'lodash'
]
],
prefix: 'custom/path/to/install',
saveDev: true, //--save-dev flag
//saves package to package.json without installing. Only works with save/saveDev option
dryRun: true,
loglevel: 'silent',
'cache-min': 999999999
}, function (err) { /* ... */ });
}).then(function (exitCode){
//do stuff
}, function (error) {
//do stuff with the error
});
```


#### npm update

```javascript
```js
// Returns a promise
npm.update({
loglevel: 'silent'
}, function (err) { /* ... */ });
}).then(function (exitCode){
//do stuff
}, function (error) {
//do stuff with the error
});
```


21 changes: 0 additions & 21 deletions errors.js

This file was deleted.

93 changes: 14 additions & 79 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
* Module dependencies
*/

var concat = require('./reduceStream').concat;
var exec = require('child_process').exec;
var Err = require('./errors');

var doNpmCommand = require('./lib/do-npm-command');


module.exports = {
Expand All @@ -17,103 +14,41 @@ module.exports = {
* @param {Object} options
* @param {Object|Function} cb
*/
install: function(options, cb) {
install: function (options) {
return doNpmCommand({
npmCommand: 'install',
cmdArgs: options.dependencies,
skip: options.skip || false,
dryRun: options.dryRun || false,
cmdPrefix: options.cmdPrefix || false,
cmdOptions: {
production: options.production || false,
loglevel: options.loglevel || undefined,
save: options.save || false,
'save-dev': options.saveDev || false,
prefix: options.prefix || undefined,
prefix: options.prefix || undefined
}
}, cb);
});
},

/**
* @param {[type]} options [description]
* @param {Function} cb [description]
* @return {[type]} [description]
*/
update: function(options, cb) {
update: function (options) {
return doNpmCommand({
npmCommand: 'update',
path: options.path || '',
cmdArgs: [],
path: options.path || '',
skip: options.skip || false,
dryRun: options.dryRun || false,
cmdPrefix: options.cmdPrefix || false,
cmdOptions: {
production: options.production || false,
loglevel: options.loglevel || undefined,
prefix: options.prefix || undefined,
prefix: options.prefix || undefined
}
}, cb);
});
}
};



function doNpmCommand(options, cb) {
cb = cb || function() {};

if (!options.npmCommand) {
return cb(new Error('`npmCommand` option is required'));
}

// Defaults
options.cmdOptions = options.cmdOptions || {};
options.cmdArgs = options.cmdArgs || [];

// Check to make sure npm CLI is accessible
var NPM_V_OUTPUT = /^[0-9]+\.[0-9]+\.[0-9]+/;
var stdout$npm_v = exec('npm -v').stdout;
concat(stdout$npm_v, function(err, result) {
if (err) return cb(err);
if (typeof result !== 'string' ||
!result.match(NPM_V_OUTPUT)) {
return cb(Err.cantFindNpm(result));
}

// Build command to execute
var cmd = '';
cmd += 'npm ' + options.npmCommand + ' ';
cmd += options.cmdArgs.join(' ');
cmd += ' ';

// if ('save' in options && options.save) {
// cmd += '--save ';
// }
//
// if ('saveDev' in options && options.saveDev) {
// cmd += '--save-dev ';
// }
//
// if (options.path.length > 0) {
// cmd += '--prefix ' + options.path + ' ';
// }

for (var key in options.cmdOptions) {
// Skip undefined options
if (options.cmdOptions[key] !== undefined) {
cmd += '--' + key + '=' + options.cmdOptions[key] + ' ';
}
}
cmd += '';

// DRY:
// console.log('WOULD HAVE RUN::');
// console.log(cmd);

// Spin up child process
var npm = exec(cmd);
var stderr$npm = npm.stderr;
var stdout$npm = npm.stdout;

// Watch in case anything goes wrong
stderr$npm.pipe(process.stderr);

// When finished, trigger success cb
npm.on('exit', function onSuccess() {
cb();
});
});
}
123 changes: 123 additions & 0 deletions lib/do-npm-command.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
var exec = require('child_process').exec;
var whichSync = require('which').sync;

var Err = require('./errors');
var installDryRun = require('./install-dry-run');

/**
* Run an npm command with the given options
*
* @method doNpmCommand
* @param {Object} options
* @param {String} options.npmCommand A command that npm recognizes. E.g. 'install'
* @param {Array} options.cmdArgs the arguments after the npmCommand. E.g. packagenames
* @param {Boolean} options.skip If true the function immediately returns. Useful for testing.
* @param {Boolean} options.dryRun If true, this adds the package to the package.json
* in the current folder or the ptions.npmCommand.prefix folder without installing
* @param {String} options.cmdPrefix Add a custom prefix to the command such as 'docker-compose run server'
* @param {Object} options.cmdOptions Has npm command options
* @param {Boolean} options.cmdOptions.production Turns on the --production flag,
* which is uesed to only install dependencies and excluding devDependencies
* @param {String} options.cmdOptions.loglevel Changes how much the command logs. E.g. 'silent'
* @param {Boolean} options.cmdOptions.save Turns on the --save flag, which saves
* the given dependency as 'dependencies'
* @param {Boolean} options.cmdOptions['save-dev'] Turning on the --save-dev flag, which
* saves the given dependency as 'devDependencies'
* @param {String} options.cmdOptions.prefix Adds the --prefix flag which lets npm install
* the dependecy into a custom path
* @return {Promise} Returns a Promise
*/
module.exports = function doNpmCommand(options) {

options = options || {};

if ('skip' in options && options.skip === true) {
return new Promise(function (resolve) {
resolve(0);
});
}

if (!options.npmCommand) {
return new Promise(function (resolve, reject) {
reject(new Error('`npmCommand` option is required'));
});
}

// Defaults
options.cmdOptions = options.cmdOptions || {};
options.cmdArgs = options.cmdArgs || [];

if ('dryRun' in options && options.dryRun === true) {
if (options.npmCommand === 'install') {
var result = installDryRun(options.cmdArgs, options.cmdOptions);
return new Promise(function (resolve, reject) {
if (result === true) {
resolve(0);
} else {
reject(result);
}
});
} else {
return new Promise(function (resolve) {
resolve(0);
});
}
}

// Check to make sure npm CLI is accessible
try {
whichSync('npm');
} catch (error) {
return new Promise(function (resolve, reject) {
reject(Err.cantFindNpm());
});
}

var promise = new Promise(function (resolve, reject) {

// Build command to execute
var cmd = '';
cmd += 'npm ' + options.npmCommand + ' ';
cmd += options.cmdArgs.join(' ');
cmd += ' ';

for (var key in options.cmdOptions) {
// Skip undefined options
if (options.cmdOptions[key] !== undefined) {
cmd += '--' + key + '=' + options.cmdOptions[key] + ' ';
}
}
cmd += '';

if (options.cmdPrefix) {
cmd = options.cmdPrefix + ' ' + cmd;
}

// DRY:
// console.log('WOULD HAVE RUN::');
// console.log(cmd);

// Spin up child process
var npm = exec(cmd);
var stderr$npm = npm.stderr;
// var stdout$npm = npm.stdout;

// Watch in case anything goes wrong
stderr$npm.pipe(process.stderr);

// When finished, trigger success cb
npm.on('exit', function onSuccess(exitCode) {
if (exitCode === 0) {
resolve(exitCode);
} else {
reject(new Error('The command failed due to exit-code ' + exitCode));
}
});

npm.on('error', function onError(error) {
reject(error);
});
});

return promise;
};
14 changes: 14 additions & 0 deletions lib/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*eslint indent:1*/
/**
* Module errors
* @type {Object}
*/
module.exports = {
cantFindNpm: function () {
return new Error(
'Couldn\'t install dependencies because `npm` could not be found. ' +
'(Is it in your $PATH?)' + '\n' +
'Anyways, you\'ll probably have to install them yourself with `npm install`.'
);
}
};
Loading