lib/hooks.js

Summary

Maintainability
A
0 mins
Test Coverage
'use strict';

var _ = require('lodash');
var Promise = require('bluebird');
var fs = require('mz/fs');
var path = require('path');
var plugins = require('./plugins');
var fmt = require('./fmt');
var isNoEntry = require('./util/codes').isNoEntry;

/**
 * Find the first plugin that can activate the requested version.
 *
 * @private
 * @function hooks.~match
 * @param {String} version The semver version to activate.
 * @return {Promise} A promise that resolves with both `version` and `command`
 * properties.
 */
var match = function(version) {
  var result;
  /** local */
  var ensure = function(key) {
    return function(r) {
      if (r && !r[key]) { throw new Error('result missing ' + key); }
      return r;
    };
  };
  return plugins.first(function(plugin) {
    return Promise.resolve()
    .then(function() { return plugin.match(version); })
    .then(ensure('command'))
    .then(ensure('version'))
    .then(function(r) { return (result = r); });
  })
  .then(function(plugin) {
    return result && _.extend({ plugin: plugin }, result);
  });
};

/**
 * Hook for `chpwd` which is triggered after changing the current working
 * directory.
 *
 * This function writes information to `stdcmd` (file descriptor #3) that
 * should be executed in the context of the current shell in order to activate
 * the proper version of node. It also writes to `stdout` & `stderr` to inform
 * the user of what activation has occurred.
 *
 * This is invoked by `_avn` & triggered by the `chpwd` shell hook that is
 * installed in `avn.sh`.
 *
 * @private
 * @function hooks.chpwd
 * @param {String} dir The directory into which the user has moved.
 * @param {String} [versionFile] The name of the version file to read within
 * the directory.
 * @param {Object} [options]
 * @param {Boolean} [options.verbose] Enable verbose output.
 * @return {Promise}
 */
exports.chpwd = function(/*dir, [versionFile], [options]*/) {
  var args = Array.prototype.slice.call(arguments, 0);
  var dir = args.shift();
  var file = _.isString(args[0]) && args.shift() || '.node-version';
  var opts = args.shift() || {};
  var via;

  if (path.resolve(dir) !== process.cwd() || file !== '.node-version') {
    via = path.join(path.relative(process.cwd(), dir), file);
  }

  return Promise.bind({})
  .then(function() { return fs.readFile(path.join(dir, file), 'utf8'); })
  .then(function(fileContent) {
    this.version = fileContent.split('\n')[0].trim();
  })
  .then(function() { return match(this.version); })
  .then(function(result) {
    process.stdout.write(fmt.success(this.version, result, via));
    process.stdcmd.write(result.command + '\n');
  })
  .catch(isNoEntry, _.noop)
  .catch(function(e) {
    if (e.code !== 'PREDICATE_FAILED') { throw e; }
    else { console.warn(fmt.failure(this.version, e, opts.verbose)); }
  });
};