<commit_before>// this entire module is depressing. i should have spent my time learning
// how to patch v8 so that these options would just be available on the
// process object.

const os = require('os');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const execFile = require('child_process').execFile;
const configPath = require('./config-path.js')(process.platform);
const env = process.env;
const user = env.LOGNAME || env.USER || env.LNAME || env.USERNAME || '';
const exclusions = ['--help'];

const configfile = '.v8flags.'+process.versions.v8+'.'+crypto.createHash('md5').update(user).digest('hex')+'.json';

const failureMessage = [
  'Unable to cache a config file for v8flags to your home directory',
  'or a temporary folder. To fix this problem, please correct your',
  'environment by setting HOME=/path/to/home or TEMP=/path/to/temp.',
  'NOTE: the user running this must be able to access provided path.',
  'If all else fails, please open an issue here:',
  'http://github.com/tkellen/js-v8flags'
].join('\n');

function fail (err) {
  err.message += '\n\n' + failureMessage;
  return err;
}

function openConfig (cb) {
  fs.mkdir(configPath, function () {
    tryOpenConfig(path.join(configPath, configfile), function (err, fd) {
      if (err) return tryOpenConfig(path.join(os.tmpdir(), configfile), cb);
      return cb(null, fd);
    });
  })
}

function tryOpenConfig (configpath, cb) {
  try {
    // if the config file is valid, it should be json and therefore
    // node should be able to require it directly. if this doesn't
    // throw, we're done!
    var content = require(configpath);
    process.nextTick(function () {
      cb(null, content);
    });
  } catch (e) {
    // if requiring the config file failed, maybe it doesn't exist, or
    // perhaps it has become corrupted. instead of calling back with the
    // content of the file, call back with a file descriptor that we can
    // write the cached data to
    fs.open(configpath, 'w+', function (err, fd) {
      if (err) {
        return cb(err);
      }
      return cb(null, fd);
    });
  }
}

// Node <= 9 outputs _ in flags with multiple words, while node 10
// uses -. Both ways are accepted anyway, so always use `_` for better
// compatibility.
// We must not replace the first two --.
function normalizeFlagName(flag) {
  return "--" + flag.slice(4).replace(/-/g, "_");
}

// i can't wait for the day this whole module is obsolete because these
// options are available on the process object. this executes node with
// `--v8-options` and parses the result, returning an array of command
// line flags.
function getFlags (cb) {
  execFile(process.execPath, ['--v8-options'], function (execErr, result) {
    if (execErr) {
      return cb(execErr);
    }
    var flags = result.match(/\s\s--[\w-]+/gm)
      .map(normalizeFlagName)
      .filter(function (name) {
        return exclusions.indexOf(name) === -1;
      });
    return cb(null, flags);
  });
}

// write some json to a file descriptor. if this fails, call back
// with both the error and the data that was meant to be written.
function writeConfig (fd, flags, cb) {
  var json = JSON.stringify(flags);
  var buf;
  if (Buffer.from && Buffer.from !== Uint8Array.from) {
    // Node.js 4.5.0 or newer
    buf = Buffer.from(json);
  } else {
    // Old Node.js versions
    // The typeof safeguard below is mostly against accidental copy-pasting
    // and code rewrite, it never happens as json is always a string here.
    if (typeof json === 'number') throw new Error('Unexpected type number');
    buf = new Buffer(json);
  }
  return fs.write(fd, buf, 0, buf.length, 0 , function (writeErr) {
    fs.close(fd, function (closeErr) {
      var err = writeErr || closeErr;
      if (err) {
        return cb(fail(err), flags);
      }
      return cb(null, flags);
    });
  });
}

module.exports = function (cb) {
  // bail early if this is not node
  var isElectron = process.versions && process.versions.electron;
  if (isElectron) {
    return process.nextTick(function () {
      cb(null, []);
    });
  }

  // attempt to open/read cache file
  openConfig(function (openErr, result) {
    if (!openErr && typeof result !== 'number') {
      return cb(null, result);
    }
    // if the result is not an array, we need to go fetch
    // the flags by invoking node with `--v8-options`
    getFlags(function (flagsErr, flags) {
      // if there was an error fetching the flags, bail immediately
      if (flagsErr) {
        return cb(flagsErr);
      }
      // if there was a problem opening the config file for writing
      // throw an error but include the flags anyway so that users
      // can continue to execute (at the expense of having to fetch
      // flags on every run until they fix the underyling problem).
      if (openErr) {
        return cb(fail(openErr), flags);
      }
      // write the config file to disk so subsequent runs can read
      // flags out of a cache file.
      return writeConfig(result, flags, cb);
    });
  });
};

module.exports.configfile = configfile;
module.exports.configPath = configPath;
<commit_msg>Fix: Add version to the cache file name (#50)<commit_after>// this entire module is depressing. i should have spent my time learning
// how to patch v8 so that these options would just be available on the
// process object.

const os = require('os');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const execFile = require('child_process').execFile;
const configPath = require('./config-path.js')(process.platform);
const version = require("./package.json").version;
const env = process.env;
const user = env.LOGNAME || env.USER || env.LNAME || env.USERNAME || '';
const exclusions = ['--help'];

// This number must be incremented whenever the generated cache file changes.
const CACHE_VERSION = 1;

const configfile = '.v8flags-'+CACHE_VERSION+'-'+process.versions.v8+'.'+crypto.createHash('md5').update(user).digest('hex')+'.json';

const failureMessage = [
  'Unable to cache a config file for v8flags to your home directory',
  'or a temporary folder. To fix this problem, please correct your',
  'environment by setting HOME=/path/to/home or TEMP=/path/to/temp.',
  'NOTE: the user running this must be able to access provided path.',
  'If all else fails, please open an issue here:',
  'http://github.com/tkellen/js-v8flags'
].join('\n');

function fail (err) {
  err.message += '\n\n' + failureMessage;
  return err;
}

function openConfig (cb) {
  fs.mkdir(configPath, function () {
    tryOpenConfig(path.join(configPath, configfile), function (err, fd) {
      if (err) return tryOpenConfig(path.join(os.tmpdir(), configfile), cb);
      return cb(null, fd);
    });
  })
}

function tryOpenConfig (configpath, cb) {
  try {
    // if the config file is valid, it should be json and therefore
    // node should be able to require it directly. if this doesn't
    // throw, we're done!
    var content = require(configpath);
    process.nextTick(function () {
      cb(null, content);
    });
  } catch (e) {
    // if requiring the config file failed, maybe it doesn't exist, or
    // perhaps it has become corrupted. instead of calling back with the
    // content of the file, call back with a file descriptor that we can
    // write the cached data to
    fs.open(configpath, 'w+', function (err, fd) {
      if (err) {
        return cb(err);
      }
      return cb(null, fd);
    });
  }
}

// Node <= 9 outputs _ in flags with multiple words, while node 10
// uses -. Both ways are accepted anyway, so always use `_` for better
// compatibility.
// We must not replace the first two --.
function normalizeFlagName(flag) {
  return "--" + flag.slice(4).replace(/-/g, "_");
}

// i can't wait for the day this whole module is obsolete because these
// options are available on the process object. this executes node with
// `--v8-options` and parses the result, returning an array of command
// line flags.
function getFlags (cb) {
  execFile(process.execPath, ['--v8-options'], function (execErr, result) {
    if (execErr) {
      return cb(execErr);
    }
    var flags = result.match(/\s\s--[\w-]+/gm)
      .map(normalizeFlagName)
      .filter(function (name) {
        return exclusions.indexOf(name) === -1;
      });
    return cb(null, flags);
  });
}

// write some json to a file descriptor. if this fails, call back
// with both the error and the data that was meant to be written.
function writeConfig (fd, flags, cb) {
  var json = JSON.stringify(flags);
  var buf;
  if (Buffer.from && Buffer.from !== Uint8Array.from) {
    // Node.js 4.5.0 or newer
    buf = Buffer.from(json);
  } else {
    // Old Node.js versions
    // The typeof safeguard below is mostly against accidental copy-pasting
    // and code rewrite, it never happens as json is always a string here.
    if (typeof json === 'number') throw new Error('Unexpected type number');
    buf = new Buffer(json);
  }
  return fs.write(fd, buf, 0, buf.length, 0 , function (writeErr) {
    fs.close(fd, function (closeErr) {
      var err = writeErr || closeErr;
      if (err) {
        return cb(fail(err), flags);
      }
      return cb(null, flags);
    });
  });
}

module.exports = function (cb) {
  // bail early if this is not node
  var isElectron = process.versions && process.versions.electron;
  if (isElectron) {
    return process.nextTick(function () {
      cb(null, []);
    });
  }

  // attempt to open/read cache file
  openConfig(function (openErr, result) {
    if (!openErr && typeof result !== 'number') {
      return cb(null, result);
    }
    // if the result is not an array, we need to go fetch
    // the flags by invoking node with `--v8-options`
    getFlags(function (flagsErr, flags) {
      // if there was an error fetching the flags, bail immediately
      if (flagsErr) {
        return cb(flagsErr);
      }
      // if there was a problem opening the config file for writing
      // throw an error but include the flags anyway so that users
      // can continue to execute (at the expense of having to fetch
      // flags on every run until they fix the underyling problem).
      if (openErr) {
        return cb(fail(openErr), flags);
      }
      // write the config file to disk so subsequent runs can read
      // flags out of a cache file.
      return writeConfig(result, flags, cb);
    });
  });
};

module.exports.configfile = configfile;
module.exports.configPath = configPath;
<|endoftext|>


<commit_before>var fs = require('fs'),
    sysPath = require('path');

module.exports = {
    explore: explore,
    _explore: _explore
};

/**
 * Explore a file or a directory. i.e. stats
 * Usage
 *     explore(String start, Function callfile)
 *     explore(String start, Function callfile, Function done)
 *     explore(String start, Function callfile, Function calldir, Function done)
 *     explore(String start, Function callfile, Object options, Function done)
 *     explore(String start, Function callfile, Function calldir, Object options, Function done)
 *
 * Calling next with err cancels the reading
 * Not calling next will make the process hang forever
 * If you want fast reading, call next before processing the file or folder
 * If you want listing control, call next after you processed the file or folder
 * @param  {String}     start    File or folder to read
 * @param  {Function}   callfile called every time a file is encounter with (path[relative to initial start], stats, next)
 * @param  {Function}   calldir  called every time a folder is encounter with (path[relative to initial start], stats, files, 'start|end', next)
 * @param  {Object}     options  options.resolve[=true] => resolve symlink; options.followSymlink => explore symlink if directory
 * @param  {Function}   done     called when there are no more file nor folders to read
 */
function explore(start, callfile, calldir, options, done) {
    var count = 0;

    function take() {
        ++count;
    }

    function give(err) {
        if (--count === 0 || err) {
            done(err);
        }
    }

    // Start process
    take();

    if (arguments.length < 2) {
        throw new Error('Too few arguments');
    } else if (arguments.length === 3) {
        done = calldir;
        calldir = null;
    } else if (arguments.length === 4) {
        if ('function' === typeof options) {
            done = options;
            options = null;
        }
    }

    (options && 'object' === typeof options) || (options = {});

    if (typeof callfile !== 'function') {
        callfile = doneFileFn;
    }
    if (typeof calldir !== 'function') {
        calldir = doneDirectoryFn;
    }
    if (typeof done !== 'function') {
        done = emptyFn;
    }

    // Read folder
    take();
    _explore(start, callfile, calldir, options, give /* Folder reading is done */ );

    // Main process is done
    give();
}

/**
 * Explore a file or a directory with no checking of paramters correctness
 *
 * Calling next with err cancels the reading
 * Not calling next will make the process hang forever
 * If you want fast reading, call next before processing the file or folder
 * If you want listing control, call next after you processed the file or folder
 * @param  {String}     start    File or folder to read
 * @param  {Function}   callfile called every time a file is encounter with (path[relative to initial start], stats, next)
 * @param  {Function}   calldir  called every time a folder is encounter with (path[relative to initial start], stats, files, 'start|end', next)
 * @param  {Object}     options  options.resolve[=true] => resolve symlink; options.followSymlink => explore symlink if directory
 * @param  {Function}   done     called when there are no more file nor folders to read
 */
function _explore(start, callfile, calldir, options, done) {
    var count = 0;

    function take() {
        ++count;
    }

    function give(err) {
        if (--count === 0 || err) {
            done(err);
        }
    }

    // Start process
    take();
    fs.lstat(start, function(err, stats) {
        var linkStats;
        if (err) {
            give(err);
            return;
        }

        if (stats.isSymbolicLink() && (options.followLink === true || options.resolve !== false)) {
            linkStats = stats;
            try {
                stats = fs.lstatSync(fs.realpathSync(start));
            } catch (err) {
                // invalid symlink
                callfile(start, stats, give);
                return;
            }
        }

        if (stats.isFile()) {
            callfile(start, linkStats || stats, give);
            return;
        }

        if (!stats.isDirectory()) {
            give(new Error('Not a File nor a directory ' + start));
            return;
        }

        stats = linkStats || stats;

        if (stats.isSymbolicLink() && options.followLink !== true) {
            calldir(start, linkStats || stats, [], 'end', give);
            return;
        }

        fs.readdir(start, function(err, files) {
            var _i = 0,
                _len = files.length;
            if (err) {
                give(err);
                return;
            }

            calldir(start, stats, files, 'begin', next);

            function next(err, skip) {
                if (err) {
                    give(err);
                    return;
                }

                if (skip || files.length === 0) {
                    calldir(start, stats, files, 'end', give);
                    return;
                }

                _explore(sysPath.join(start, files[_i]), callfile, calldir, options, iterate);
            }

            function iterate(err, skip) {
                if (err) {
                    give(err);
                    return;
                }

                if (skip || ++_i === _len) {
                    calldir(start, stats, files, 'end', give);
                    return;
                }

                _explore(sysPath.join(start, files[_i]), callfile, calldir, options, iterate);
            }
        });

    });
}

function doneFileFn(file, stats, done) {
    done();
}

function doneDirectoryFn(path, stats, files, state, done) {
    done();
}

function emptyFn() {}<commit_msg>add comments<commit_after>'use strict';

var fs = require('fs'),
    sysPath = require('path');

module.exports = {
    explore: explore,
    _explore: _explore
};

/**
 * Explore a file or a directory. i.e. stats
 * Usage
 *     explore(String start, Function callfile)
 *     explore(String start, Function callfile, Function done)
 *     explore(String start, Function callfile, Function calldir, Function done)
 *     explore(String start, Function callfile, Object options, Function done)
 *     explore(String start, Function callfile, Function calldir, Object options, Function done)
 *
 * Calling next with err cancels the reading
 * Not calling next will make the process hang forever
 * If you want fast reading, call next before processing the file or folder
 * If you want listing control, call next after you processed the file or folder
 * @param  {String}     start    File or folder to read
 * @param  {Function}   callfile called every time a file is encounter with (path[relative to initial start], stats, next)
 * @param  {Function}   calldir  called every time a folder is encounter with (path[relative to initial start], stats, files, 'begin|end', next). To skip folder, call next(null, true) on begin
 * @param  {Object}     options  options.resolve[=true] => resolve symlink; options.followSymlink => explore symlink if directory
 * @param  {Function}   done     called when there are no more file nor folders to read
 */
function explore(start, callfile, calldir, options, done) {
    var argsLen = arguments.length;

    if (argsLen < 2) {
        throw new Error('Too few arguments');
    } else if (argsLen === 3) {
        done = calldir;
        calldir = null;
    } else if (argsLen === 4) {
        if ('function' === typeof options) {
            done = options;
            options = null;
        }
    }

    if (!isFunction(callfile)) {
        throw new Error('callfile must be a function');
    }

    isObject(options) || (options = {});

    if (typeof callfile !== 'function') {
        callfile = doneFileFn;
    }
    if (typeof calldir !== 'function') {
        calldir = doneDirectoryFn;
    }
    if (typeof done !== 'function') {
        done = emptyFn;
    }

    _explore(start, callfile, calldir, options, done);
}

/**
 * Explore a file or a directory with no checking of paramters correctness
 *
 * Calling next with err cancels the reading
 * Not calling next will make the process hang forever
 * If you want fast reading, call next before processing the file or folder
 * If you want listing control, call next after you processed the file or folder
 * @param  {String}     start    File or folder to read
 * @param  {Function}   callfile called every time a file is encounter with (path[relative to initial start], stats, next)
 * @param  {Function}   calldir  called every time a folder is encounter with (path[relative to initial start], stats, files, 'begin|end', next)To skip folder, call next(null, true) on begin
 * @param  {Object}     options  options.resolve[=true] => resolve symlink; options.followSymlink => explore symlink if directory
 * @param  {Function}   done     called when there are no more file nor folders to read
 */
function _explore(start, callfile, calldir, options, done) {
    var count = 0;

    function take() {
        ++count;
    }

    function give(err) {
        if (--count === 0 || err) {
            done(err);
        }
    }

    // Start process
    take();
    fs.lstat(start, function(err, stats) {
        var linkStats;
        if (err) {
            give(err);
            return;
        }

        if (stats.isSymbolicLink() && (options.followLink === true || options.resolve !== false)) {
            linkStats = stats;
            try {
                stats = fs.lstatSync(fs.realpathSync(start));
            } catch (err) {
                // invalid symlink
                callfile(start, stats, give);
                return;
            }
        }

        if (stats.isFile()) {
            callfile(start, linkStats || stats, give);
            return;
        }

        if (!stats.isDirectory()) {
            give(new Error('Not a File nor a directory ' + start));
            return;
        }

        stats = linkStats || stats;

        if (stats.isSymbolicLink() && options.followLink !== true) {
            calldir(start, linkStats || stats, [], 'end', give);
            return;
        }

        fs.readdir(start, function(err, files) {
            var _i = 0,
                _len = files.length;
            if (err) {
                give(err);
                return;
            }

            calldir(start, stats, files, 'begin', next);

            function next(err, skip) {
                if (err) {
                    give(err);
                    return;
                }

                if (skip || files.length === 0) {
                    calldir(start, stats, files, 'end', give);
                    return;
                }

                _explore(sysPath.join(start, files[_i]), callfile, calldir, options, iterate);
            }

            function iterate(err, skip) {
                if (err) {
                    give(err);
                    return;
                }

                if (skip || ++_i === _len) {
                    calldir(start, stats, files, 'end', give);
                    return;
                }

                _explore(sysPath.join(start, files[_i]), callfile, calldir, options, iterate);
            }
        });

    });
}

function doneFileFn(file, stats, done) {
    done();
}

function doneDirectoryFn(path, stats, files, state, done) {
    done();
}

function emptyFn() {}

// ==============
// From lodash
// ==============
var objToString = Object.prototype.toString

function isObject(value) {
    // Avoid a V8 JIT bug in Chrome 19-20.
    // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
    var type = typeof value;
    return !!value && (type === 'object' || type === 'function');
}

function isFunction(value) {
    // The use of `Object#toString` avoids issues with the `typeof` operator
    // in older versions of Chrome and Safari which return 'function' for regexes
    // and Safari 8 which returns 'object' for typed array constructors.
    return isObject(value) && objToString.call(value) === '[object Function]';
}<|endoftext|>


<commit_before>'use strict';
var dnode = require('dnode');
var _ = require('lodash');
var logger = require('hoist-logger');
var jsonlint = require("jsonlint");
var fsgit = require('fs-git');
var Application = require('hoist-model').Application;
var Organisation = require('hoist-model').Organisation;
var path = require('path');
var BBPromise = require('bluebird');
var errors = require('hoist-errors');
var childProcess = BBPromise.promisifyAll(require('child_process'));
var moment = require('moment');
var config = require('config');
var mkdirp = BBPromise.promisify(require('mkdirp'));
var mongoose = BBPromise.promisifyAll(require('hoist-model')._mongoose);
var Agenda = require('agenda');

var GitDeployer = function () {
  _.bindAll(this);
};

GitDeployer.prototype.getAgenda = function () {
  return this.agenda || (this.agenda = BBPromise.promisifyAll(new Agenda({
    db: {
      address: config.get('Hoist.mongo.db')
    }
  })));
};

GitDeployer.prototype.start = function (done) {
  /* istanbul ignore else */
  if (!this.queue) {
    return BBPromise.try(function () {
        var connected = false;
        /* istanbul ignore if */
        if (mongoose.connection && mongoose.connection.readyState > 0) {
          connected = true;
        }
        return connected;
      }).bind(this)
      .then(function (connected) {
        /* istanbul ignore else */
        if (!connected) {
          return mongoose.connectAsync(config.get('Hoist.mongo.db'));
        } else {
          return null;
        }
      }).then(function () {
        this.dnodeServer = dnode({
          deploy: this.deploy
        });
        this.dnodeServer.listen(config.get('Hoist.dnode.port'));
      }).nodeify(done);
  } else {
    return BBPromise.resolve(null).nodeify(done);
  }
};
GitDeployer.prototype.stop = function (done) {
  /* istanbul ignore else */
  if (this.dnodeServer) {
    return BBPromise.try(function () {
      var connected = false;
      /* istanbul ignore else */
      if (mongoose.connection && mongoose.connection.readyState > 0 && mongoose.connection.readyState < 3) {
        connected = true;
      }
      return connected;
    }).bind(this).then(function (connected) {
      /* istanbul ignore else */
      if (connected) {
        console.log('disconnecting');
        return mongoose.disconnectAsync();
      }
    }).then(function () {
      return new BBPromise.try(function () {
        this.dnodeServer.end();
        this.dnodeServer = null;
      }, [], this);
    }).nodeify(done);
  } else {
    return BBPromise.resolve(null).nodeify(done);
  }
};
GitDeployer.prototype.deploy = function (job, log, done) {
  var self = this;
  job.log = log;
  job.timestamp = moment();
  logger.info('parsing hoist.json file');
  log('parsing hoist.json file');
  log('extracting application content');
  return self.checkout(job)
    .then(function npmInstall() {
      return self.npm(job);
    }).then(function updateConfig() {
      return self.updateConfig(job);
    }).then(function updateSchedules(application) {
      return self.updateSchedules(application);
    }).catch(function catchError(err) {
      logger.error(err);
      throw err;
    }).nodeify(done);
};

GitDeployer.prototype.updateSchedules = function updateSchedules(job, application) {
  return BBPromise.try(function deleteExistingSchedules() {
    logger.info('deleting schedules');
    job.log('cancelling existing schedules');
    return this.getAgenda().cancelAsync({
      'data.application': application._id
    });
  }, [], this).bind(this).then(function addNewSchedules() {
    if (application.settings.live.schedules) {
      return BBPromise.all(_.map(application.settings.live.schedules, function (schedule, key) {
        var scheduleJob = BBPromise.promisifyAll(this.agenda.create('create:event', {
          application: application._id,
          environment: 'live',
          events: schedule.events
        }));
        scheduleJob.repeatEvery(key);
        return scheduleJob.saveAsync();
      }, this));
    }
  });
};

GitDeployer.prototype.npm = function npm(job) {
  var gitRepoPath = job.path;
  var parts = gitRepoPath.split(path.sep);
  var targetPath = path.join(config.get('Hoist.executor.root'), parts[parts.length - 2], parts[parts.length - 1].replace('.git', ''), job.timestamp.format('X'));
  job.log('npm installing');
  return new BBPromise(function (resolve, reject) {
    var npmProcess = require('child_process').exec('npm install --production --spin false', {
      cwd: targetPath
    }, function (error) {
      if (error) {
        logger.error(error);
        job.log(error.message);
        reject();
      } else {
        resolve();
      }
    });
    npmProcess.stdout.on('data', function (data) {
      job.log('' + data);
    });
    npmProcess.stderr.on('data', function (data) {
      job.log('' + data);
    });
    npmProcess.stdout.pipe(process.stdout);
    npmProcess.stderr.pipe(process.stderr);
  });
};
GitDeployer.prototype.checkout = function checkout(job) {
  var gitRepoPath = job.path;
  var parts = gitRepoPath.split(path.sep);

  var targetPath = path.join(config.get('Hoist.executor.root'), parts[parts.length - 2], parts[parts.length - 1].replace('.git', ''), job.timestamp.format('X'));
  job.log('moving application files into position');
  return mkdirp(targetPath).then(function () {
    return childProcess.execAsync('git clone ' + gitRepoPath + ' ' + targetPath);
  });
};
GitDeployer.prototype.loadHoistJson = function loadHoistJson(gitRepoPath, callback) {
  return BBPromise.resolve(fsgit.open(gitRepoPath))
    .then(function (fs) {
      return fs.exists('hoist.json')
        .then(function (exists) {
          if (!exists) {
            throw new errors.files.hoistJson.NotFoundError();
          }
          return fs.readFile('hoist.json');

        }).then(function (content) {
          return BBPromise.try(function () {
            return jsonlint.parse(content);
          }).catch(function (err) {

            throw new errors.files.hoistJson.InvalidJsonError(err.message);
          });
        });
    }).catch(function (err) {
      logger.error(err.message);

      if (!errors.isHoistError(err)) {
        /* istanbul ignore else */
        if (err.message.indexOf('Not a git repository') > -1) {
          err = new errors.git.NotFoundError();
        } else if (err.message.indexOf('Command failed:') > -1) {
          err = new errors.git.InvalidError();
        } else {
          logger.error(err.message);
          err = new errors.HoistError();
        }
      }
      throw err;
    }).nodeify(callback);
};
GitDeployer.prototype.getDetailsFromPath = function getDetailsFromPath(gitRepoPath, callback) {
  var parts = gitRepoPath.split(path.sep);

  return BBPromise.resolve({
    repoName: parts[parts.length - 1].replace('.git', ''),
    folderName: parts[parts.length - 2]
  }).nodeify(callback);
};
GitDeployer.prototype.updateConfig = function updateConfig(job) {
  //extract subDomain from job
  //load the application

  return this.getDetailsFromPath(job.path)
    .then(function loadOrg(details) {
      job.log('finding application');
      return Organisation.findOneAsync({
        gitFolder: details.folderName
      }).then(function loadApp(org) {
        if (!org) {
          throw new errors.model.organisation.NotFoundError();
        }
        return Application.findOneAsync({
          organisation: org._id,
          gitRepo: details.repoName
        });
      });
    }).bind(this)
    .then(function processSettings(application) {
      if (!application) {
        throw new errors.model.application.NotFoundError();
      }
      job.log('extracting new settings');
      //load the hoist.json file
      return this.loadHoistJson(job.path).bind(this)
        .then(function saveSettings(settingsFromJson) {
          job.log('setting new settings');
          //update live settings and mark as dirty
          application.settings.live = settingsFromJson;
          application.markModified('settings.live');
          //set deploy date
          job.log('updating deployment log');
          application.lastDeploy.live = job.timestamp.toDate();
          //save application
          return application.saveAsync();
        });
    });
};

module.exports = GitDeployer;
<commit_msg>fix call to update schedules<commit_after>'use strict';
var dnode = require('dnode');
var _ = require('lodash');
var logger = require('hoist-logger');
var jsonlint = require("jsonlint");
var fsgit = require('fs-git');
var Application = require('hoist-model').Application;
var Organisation = require('hoist-model').Organisation;
var path = require('path');
var BBPromise = require('bluebird');
var errors = require('hoist-errors');
var childProcess = BBPromise.promisifyAll(require('child_process'));
var moment = require('moment');
var config = require('config');
var mkdirp = BBPromise.promisify(require('mkdirp'));
var mongoose = BBPromise.promisifyAll(require('hoist-model')._mongoose);
var Agenda = require('agenda');

var GitDeployer = function () {
  _.bindAll(this);
};

GitDeployer.prototype.getAgenda = function () {
  return this.agenda || (this.agenda = BBPromise.promisifyAll(new Agenda({
    db: {
      address: config.get('Hoist.mongo.db')
    }
  })));
};

GitDeployer.prototype.start = function (done) {
  /* istanbul ignore else */
  if (!this.queue) {
    return BBPromise.try(function () {
        var connected = false;
        /* istanbul ignore if */
        if (mongoose.connection && mongoose.connection.readyState > 0) {
          connected = true;
        }
        return connected;
      }).bind(this)
      .then(function (connected) {
        /* istanbul ignore else */
        if (!connected) {
          return mongoose.connectAsync(config.get('Hoist.mongo.db'));
        } else {
          return null;
        }
      }).then(function () {
        this.dnodeServer = dnode({
          deploy: this.deploy
        });
        this.dnodeServer.listen(config.get('Hoist.dnode.port'));
      }).nodeify(done);
  } else {
    return BBPromise.resolve(null).nodeify(done);
  }
};
GitDeployer.prototype.stop = function (done) {
  /* istanbul ignore else */
  if (this.dnodeServer) {
    return BBPromise.try(function () {
      var connected = false;
      /* istanbul ignore else */
      if (mongoose.connection && mongoose.connection.readyState > 0 && mongoose.connection.readyState < 3) {
        connected = true;
      }
      return connected;
    }).bind(this).then(function (connected) {
      /* istanbul ignore else */
      if (connected) {
        console.log('disconnecting');
        return mongoose.disconnectAsync();
      }
    }).then(function () {
      return new BBPromise.try(function () {
        this.dnodeServer.end();
        this.dnodeServer = null;
      }, [], this);
    }).nodeify(done);
  } else {
    return BBPromise.resolve(null).nodeify(done);
  }
};
GitDeployer.prototype.deploy = function (job, log, done) {
  var self = this;
  job.log = log;
  job.timestamp = moment();
  logger.info('parsing hoist.json file');
  log('parsing hoist.json file');
  log('extracting application content');
  return self.checkout(job)
    .then(function npmInstall() {
      return self.npm(job);
    }).then(function updateConfig() {
      return self.updateConfig(job);
    }).then(function updateSchedules(application) {
      return self.updateSchedules(job, application);
    }).catch(function catchError(err) {
      logger.error(err);
      throw err;
    }).nodeify(done);
};

GitDeployer.prototype.updateSchedules = function updateSchedules(job, application) {
  return BBPromise.try(function deleteExistingSchedules() {
    logger.info('deleting schedules');
    job.log('cancelling existing schedules');
    return this.getAgenda().cancelAsync({
      'data.application': application._id
    });
  }, [], this).bind(this).then(function addNewSchedules() {
    if (application.settings.live.schedules) {
      return BBPromise.all(_.map(application.settings.live.schedules, function (schedule, key) {
        var scheduleJob = BBPromise.promisifyAll(this.agenda.create('create:event', {
          application: application._id,
          environment: 'live',
          events: schedule.events
        }));
        scheduleJob.repeatEvery(key);
        return scheduleJob.saveAsync();
      }, this));
    }
  });
};

GitDeployer.prototype.npm = function npm(job) {
  var gitRepoPath = job.path;
  var parts = gitRepoPath.split(path.sep);
  var targetPath = path.join(config.get('Hoist.executor.root'), parts[parts.length - 2], parts[parts.length - 1].replace('.git', ''), job.timestamp.format('X'));
  job.log('npm installing');
  return new BBPromise(function (resolve, reject) {
    var npmProcess = require('child_process').exec('npm install --production --spin false', {
      cwd: targetPath
    }, function (error) {
      if (error) {
        logger.error(error);
        job.log(error.message);
        reject();
      } else {
        resolve();
      }
    });
    npmProcess.stdout.on('data', function (data) {
      job.log('' + data);
    });
    npmProcess.stderr.on('data', function (data) {
      job.log('' + data);
    });
    npmProcess.stdout.pipe(process.stdout);
    npmProcess.stderr.pipe(process.stderr);
  });
};
GitDeployer.prototype.checkout = function checkout(job) {
  var gitRepoPath = job.path;
  var parts = gitRepoPath.split(path.sep);

  var targetPath = path.join(config.get('Hoist.executor.root'), parts[parts.length - 2], parts[parts.length - 1].replace('.git', ''), job.timestamp.format('X'));
  job.log('moving application files into position');
  return mkdirp(targetPath).then(function () {
    return childProcess.execAsync('git clone ' + gitRepoPath + ' ' + targetPath);
  });
};
GitDeployer.prototype.loadHoistJson = function loadHoistJson(gitRepoPath, callback) {
  return BBPromise.resolve(fsgit.open(gitRepoPath))
    .then(function (fs) {
      return fs.exists('hoist.json')
        .then(function (exists) {
          if (!exists) {
            throw new errors.files.hoistJson.NotFoundError();
          }
          return fs.readFile('hoist.json');

        }).then(function (content) {
          return BBPromise.try(function () {
            return jsonlint.parse(content);
          }).catch(function (err) {

            throw new errors.files.hoistJson.InvalidJsonError(err.message);
          });
        });
    }).catch(function (err) {
      logger.error(err.message);

      if (!errors.isHoistError(err)) {
        /* istanbul ignore else */
        if (err.message.indexOf('Not a git repository') > -1) {
          err = new errors.git.NotFoundError();
        } else if (err.message.indexOf('Command failed:') > -1) {
          err = new errors.git.InvalidError();
        } else {
          logger.error(err.message);
          err = new errors.HoistError();
        }
      }
      throw err;
    }).nodeify(callback);
};
GitDeployer.prototype.getDetailsFromPath = function getDetailsFromPath(gitRepoPath, callback) {
  var parts = gitRepoPath.split(path.sep);

  return BBPromise.resolve({
    repoName: parts[parts.length - 1].replace('.git', ''),
    folderName: parts[parts.length - 2]
  }).nodeify(callback);
};
GitDeployer.prototype.updateConfig = function updateConfig(job) {
  //extract subDomain from job
  //load the application

  return this.getDetailsFromPath(job.path)
    .then(function loadOrg(details) {
      job.log('finding application');
      return Organisation.findOneAsync({
        gitFolder: details.folderName
      }).then(function loadApp(org) {
        if (!org) {
          throw new errors.model.organisation.NotFoundError();
        }
        return Application.findOneAsync({
          organisation: org._id,
          gitRepo: details.repoName
        });
      });
    }).bind(this)
    .then(function processSettings(application) {
      if (!application) {
        throw new errors.model.application.NotFoundError();
      }
      job.log('extracting new settings');
      //load the hoist.json file
      return this.loadHoistJson(job.path).bind(this)
        .then(function saveSettings(settingsFromJson) {
          job.log('setting new settings');
          //update live settings and mark as dirty
          application.settings.live = settingsFromJson;
          application.markModified('settings.live');
          //set deploy date
          job.log('updating deployment log');
          application.lastDeploy.live = job.timestamp.toDate();
          //save application
          return application.saveAsync();
        });
    });
};

module.exports = GitDeployer;
<|endoftext|>


<commit_before>var handlebars = require('handlebars');

/**
 *  config options:
 *   - transformPath - function that transforms original file path to path of the processed file
 *   - templateName - function that translates original file path to template name
 *   - templates - name of the variable to store the templates hash
 */
var createHandlebarsPreprocessor = function(args, config, logger, basePath) {
  config = config || {};

  var log = logger.create('preprocessor.handlebars');

  var transformPath = args.transformPath || config.transformPath || function(filepath) {
    return filepath.replace(/\.hbs$/, '.js')
  };

  var templateName = args.templateName || config.templateName || function(filepath) {
    return filepath.replace(/^.*\/([^\/]+)\.hbs$/, '$1');
  };

  var isPartial = args.isPartial || config.isPartial || function(filepath) {
    return false;
  };

  function registerPartialScript(templateName, content) {
    return "(function() { Handlebars.registerPartial('" + templateName + "', "
      + "Handlebars.template(" + handlebars.precompile(content) + ")"
      + ");})();";
  }

  function registerTemplateScript(templatesVariable, templateName, content) {
    return "(function() {" + templatesVariable + " = " + templatesVariable + " || {};"
      + templatesVariable + "['" + templateName + "'] = Handlebars.template("
      + handlebars.precompile(content)
      + ");})();";
  }

  var templates = args.templates || config.templates || "Handlebars.templates";

  return function(content, file, done) {
    var processed = null;

    log.debug('Processing "%s".', file.originalPath);
    file.path = transformPath(file.originalPath);

    var template = templateName(file.originalPath);

    try {
      if (isPartial(file.originalPath)) {
        processed = registerPartialScript(template, content);
      } else {
        processed = registerTemplateScript(templates, template, content);
      }
    } catch (e) {
      log.error('%s\n  at %s', e.message, file.originalPath);
    }

    done(processed);
  };
};

createHandlebarsPreprocessor.$inject = ['args', 'config.handlebarsPreprocessor', 'logger', 'config.basePath'];

// PUBLISH DI MODULE
module.exports = {
  'preprocessor:handlebars': ['factory', createHandlebarsPreprocessor]
};
<commit_msg>Explicitly look for templates object on window.<commit_after>var handlebars = require('handlebars');

/**
 *  config options:
 *   - transformPath - function that transforms original file path to path of the processed file
 *   - templateName - function that translates original file path to template name
 *   - templates - name of the variable to store the templates hash
 */
var createHandlebarsPreprocessor = function(args, config, logger, basePath) {
  config = config || {};

  var log = logger.create('preprocessor.handlebars');

  var transformPath = args.transformPath || config.transformPath || function(filepath) {
    return filepath.replace(/\.hbs$/, '.js')
  };

  var templateName = args.templateName || config.templateName || function(filepath) {
    return filepath.replace(/^.*\/([^\/]+)\.hbs$/, '$1');
  };

  var isPartial = args.isPartial || config.isPartial || function(filepath) {
    return false;
  };

  function registerPartialScript(templateName, content) {
    return "(function() { Handlebars.registerPartial('" + templateName + "', "
      + "Handlebars.template(" + handlebars.precompile(content) + ")"
      + ");})();";
  }

  function registerTemplateScript(templatesVariable, templateName, content) {
    return "(function() {" + templatesVariable + " = window." + templatesVariable + " || {};"
      + templatesVariable + "['" + templateName + "'] = Handlebars.template("
      + handlebars.precompile(content)
      + ");})();";
  }

  var templates = args.templates || config.templates || "Handlebars.templates";

  return function(content, file, done) {
    var processed = null;

    log.debug('Processing "%s".', file.originalPath);
    file.path = transformPath(file.originalPath);

    var template = templateName(file.originalPath);

    try {
      if (isPartial(file.originalPath)) {
        processed = registerPartialScript(template, content);
      } else {
        processed = registerTemplateScript(templates, template, content);
      }
    } catch (e) {
      log.error('%s\n  at %s', e.message, file.originalPath);
    }

    done(processed);
  };
};

createHandlebarsPreprocessor.$inject = ['args', 'config.handlebarsPreprocessor', 'logger', 'config.basePath'];

// PUBLISH DI MODULE
module.exports = {
  'preprocessor:handlebars': ['factory', createHandlebarsPreprocessor]
};
<|endoftext|>


<commit_before>var events = require('events');
var fs = require('fs');
var path = require('path'), basename = path.basename;
var util = require('util');
var camelcase = require('cli-util').camelcase;

var mutators = {
  cmd: {
    options: false,
    commands: false,
    names: false,
    key: true,
    name: true,
    description: true,
    action: true
  },
  arg: {
    names: false,
    key: true,
    name: true,
    optional: true,
    multiple: true,
    value: true,
    converter: true,
    extra: true,
    description: true,
    action: true
  },
  prg: {
    converter: true
  }
}

var k, keys;
var re = {
  delimiter: function(){return /[ ,|]+/;},
  required: function(){return /^=?</;},
  multiple: function(){return /\.\.\./;},
  extra: function(){return /^([^=\[<]*)((=|\[|<).*)/;},
  no: function(){return /(\[no-?\]-?)/;},
  nor: function(){return /(-\[?no-?\]?-?)/;}
}

function initialize(options, properties) {
  for(var z in options) {
    if(~properties.indexOf(z) && options[z]) this[z](options[z]);
  }
}

/**
 *  Retrieve the key for an option.
 *
 *  Scope is the option. Alternatively you may pass a
 *  string of the raw name passed when instantiating the options.
 *
 *  @param names Array of names or raw string name (optional).
 */
function getKey(names, name) {
  var k, names = names || this._names;
  name = name || this._name;
  if(typeof names == 'string') {
    name = names;
    names = names.split(re.delimiter());
  }
  names = names.slice(0);
  if(this._extra) {
    var j = names.length -1;
    var nm = names[j];
    while(re.extra().test(nm) || re.multiple().test(nm)) {
      // allow for flush extra values
      if(/^-+/.test(nm)) {
        names[j] = nm.replace(re.extra(), "$1");
      }else{
        names.pop();
      }
      nm = names[--j];
    }
    this._names = sortNames(names);
  }
  var k = names.reduce(
    function (a, b) { return a.length > b.length ? a : b; });
  k = k.replace(/^-+/, '');
  return camelcase(k.toLowerCase());
}

function sortNames(names) {
  // sort short options before long options
  return names.sort(function(a, b) {
    var re = /^-[^-]/;
    return re.test(a) ? -1 : re.test(b) ? 1 : 0;
  });
}

/**
 *  Retrieve the extra portion of the option name.
 *
 *  Note this also updates the names array to not include
 *  the extra portion.
 */
function getExtra() {
  if(re.no().test(this._name)) {
    this._extra = false;
    return;
  }
  if(!re.extra().test(this._name)) return;
  this._extra = this._name.replace(re.extra(), "$2");
  //console.log(this._extra);
  var name = this._name.replace(re.extra(), "$1");
  //console.log('name: %s', name);
  this._names = name.split(re.delimiter());
  if(!this._names[this._names.length - 1]) this._names.pop();
  this._names = sortNames(this._names);
}

var EventProxy = {
  setMaxListeners: function() {
    return this._emitter.setMaxListeners.apply(this, arguments);
  },
  emit: function() {
    return this._emitter.emit.apply(this, arguments);
  },
  addListener: function() {
    return this._emitter.addListener.apply(this, arguments);
  },
  on: function() {
    return this._emitter.on.apply(this, arguments);
  },
  once: function() {
    return this._emitter.once.apply(this, arguments);
  },
  removeListener: function() {
    return this._emitter.removeListener.apply(this, arguments);
  },
  removeAllListeners: function() {
    return this._emitter.removeAllListeners.apply(this, arguments);
  },
  listeners: function() {
    return this._emitter.listeners.apply(this, arguments);
  }
}

var enumerable = process.env.CLI_TOOLKIT_DEBUG ? true : false;

function define(obj, name, value, writable) {
  writable = writable || false;
  Object.defineProperty(obj, name,
    {
      enumerable: enumerable,
      configurable: false,
      writable: writable,
      value: value
    }
  );
}

/**
 *  Abstract super class.
 *
 *  @param name The argument name.
 *  @param description The argument description.
 *  @param options The argument options or conversion function.
 */
var Argument = function(name, description, options) {
  if(typeof name == 'object') options = name;
  define(this, '_name', name, true);
  define(this, '_description', description || '', true);
  define(this, '_key', '', true);
  define(this, '_optional', true, true);
  define(this, '_multiple', false, true);
  define(this, '_value', undefined, true);
  define(this, '_converter', undefined, true);
  define(this, '_action', undefined, true);
  define(this, '_extra', undefined, true);
  define(this, '_names', undefined, true);

  // event emitter
  define(this, '_emitter', new events.EventEmitter(), false);
  define(this, '_events', undefined, true);
  define(this, '_maxListeners', undefined, true);
  define(this, 'domain', undefined, true);

  if(options === JSON) {
    this._converter = JSON;
  }else if(options && (typeof options == 'object') && !Array.isArray(options)) {
    initialize.call(this, options, Object.keys(mutators.arg));
  }else if((typeof options == 'function') || this.isFunctionArray(options)){
    this._converter = options;
    if(arguments.length > 3 && this._value === undefined) {
      this._value = arguments[3];
    }
  }else {
    this._value = options;
    if(arguments.length > 3
      && (typeof(arguments[3]) == 'function'
      || this.isFunctionArray(options))) {
      this._converter = arguments[3];
    }
  }

  if(!this._name || typeof this._name !== 'string') {
    throw new TypeError('Invalid argument name \'' + this._name + '\'');
  }

  // strip no prefixes
  var no = re.no();
  var name = '' + this._name;
  if((this instanceof Flag) && no.test(this._name)) {
    name = this._name.replace(no, '');
  }

  this._names = this._name.split(re.delimiter());
  //console.dir(this._names);
  getExtra.call(this);
  if(re.required().test(this._extra)) {
    this._optional = false;
  }
  if(re.multiple().test(this._extra)) {
    this._multiple = true;
  }
  this._key = getKey.call(this, name);
  //console.log('key', this._key);
}

for(k in EventProxy) {
  define(Argument.prototype, k, EventProxy[k], false);
}

function toString(delimiter) {
  if(!arguments.length) return Object.prototype.toString.call(this);
  delimiter = delimiter || ' | ';
  var names = sortNames(this.names());
  return names.join(delimiter);
}
define(Argument.prototype, 'toString', toString, false);

/**
 *  Retrieve a standardized string to use when listing options.
 */
getOptionString = function(delimiter, assignment) {
  assignment = assignment || '=';
  delimiter = delimiter || ', ';
  var extra = this.extra() ? this.extra() || '' : '';
  if(extra) {
    extra = extra.replace(/^(.?)=(.*)$/, "$1$2");
    extra = assignment + extra;
  }
  return this.toString(delimiter) + extra;
}
define(Argument.prototype, 'getOptionString', getOptionString, false);

/**
 *  Determines whether an array consists solely of functions
 *  allowing for the special case JSON.
 *
 *  @param arr The array candidate.
 */
Argument.prototype.isFunctionArray = function(arr) {
  if(!Array.isArray(arr)) return false;
  var i, item;
  for(i = 0;i < arr.length;i++) {
    item = arr[i];
    if(item !== JSON && !(typeof item == 'function')) return false;
  }
  return true;
}

keys = Object.keys(mutators.arg);
keys.forEach(function(name) {
  var read = function() {
    return this['_' + name];
  }
  var write = function(value) {
    var key = '_' + name;
    if(!arguments.length) return this[key];
    this[key] = value;
    return this;
  }
  define(Argument.prototype, name, mutators.arg[name] ? write : read, false);
})

/**
 *  Represents an option argument.
 */
var Option = function() {
  Argument.apply(this, arguments);
}

util.inherits(Option, Argument);

/**
 *  Represents a flag argument.
 */
var Flag = function() {
  Argument.apply(this, arguments);
  //console.log('Flag %s %s', this._name, this._description);
  //this._value = false;
}

util.inherits(Flag, Argument);

/**
 *  Represents a command argument.
 */
var Command = function(name, description, options) {
  //events.EventEmitter.call(this);
  if(typeof name == 'object') options = name;

  // private
  define(this, '_commands', {}, true);
  define(this, '_options', {}, true);
  define(this, '_name', name || '', true);
  define(this, '_description', description || '', true);
  define(this, '_key', '', true);
  define(this, '_action', undefined, true);
  define(this, '_names', undefined, true);
  //define(this, '_package', undefined, true);

  // event emitter
  define(this, '_emitter', new events.EventEmitter(), false);
  define(this, '_events', undefined, true);
  define(this, '_maxListeners', undefined, true);
  define(this, 'domain', undefined, true);

  if((typeof options == 'object')) {
    initialize.call(this, options, Object.keys(mutators.cmd));
  }

  if(!this._name || typeof this._name !== 'string') {
    throw new TypeError('Invalid command name \'' + this._name + '\'');
  }

  this._names = this._name.split(re.delimiter());
  this._key = getKey.call(this);
}

define(Command.prototype, 'getOptionString', getOptionString, false);
define(Command.prototype, 'toString', toString, false);

for(k in EventProxy) {
  define(Command.prototype, k, EventProxy[k], false);
}

keys = Object.keys(mutators.cmd);
keys.forEach(function(name) {
  var read = function() {
    return this['_' + name];
  }
  var write = function(value) {
    var key = '_' + name;
    if(value === undefined) return this[key];
    this[key] = value;
    return this;
  }
  define(Command.prototype, name, mutators.cmd[name] ? write : read, false);
})

/**
 *  Define a command argument.
 */
function command(name, description, options) {
  var opt = (name instanceof Command) ? name
    : new Command(name, description, options);
  this._commands[opt.key()] = opt;
  return description ? this : opt;
}
define(Command.prototype, 'command', command, false);

/**
 *  Define an option argument.
 */
function option(name, description, options, coerce, value) {
  var clazz = Option;
  if(typeof name === 'string') {
    if(re.no().test(name) || !re.extra().test(name)) {
      clazz = Flag;
    }
  }
  var opt = (name instanceof clazz) ? name
    : new clazz(name, description, options, coerce, value);
  this._options[opt.key()] = opt;
  return this;
}
define(Command.prototype, 'option', option, false);

/**
 *  Define a flag argument explicitly.
 */
function flag(name, description, options, coerce, value) {
  var opt = (name instanceof Flag) ? name
    : new Flag(name, description, options, coerce, value);
  this._options[opt.key()] = opt;
  return this;
}
define(Command.prototype, 'flag', flag, false);

/**
 *  Represents the program.
 */
var Program = function() {
  Command.apply(this, arguments);
  define(this, '_version', '0.0.1', true);
  define(this, '_package', undefined, true);
  define(this, '_converter', undefined, true);
}

util.inherits(Program, Command);

keys = Object.keys(mutators.prg);
keys.forEach(function(name) {
  var write = function(value) {
    var key = '_' + name;
    if(!arguments.length) return this[key];
    this[key] = value;
    return this;
  }
  define(Program.prototype, name, write, false);
})

/**
 *  Set the program package descriptor.
 *
 *  @param path The path to the package descriptor or an existing
 *  package object.
 */
function package(path) {
  if(!arguments.length) return this._package;
  if(arguments.length === 1 && !path) {
    this._package = path;
    return this._package;
  }
  var pkg;
  if(path && typeof(path) === 'string' && fs.existsSync(path)) {
    try {
      pkg = this._package = require(path);
    }catch(e) {
      throw new Error(util.format(
        'package parse error %s (malformed json)', path));
    }
  }else if(path && typeof path === 'object') {
    pkg = this._package = path;
  }
  if(!pkg) {
    throw new Error(util.format(
      'package descriptor %s does not exist', path));
  }
  this._version = pkg.version;
  if(pkg.description) this._description = pkg.description;
  return this;
}
define(Program.prototype, 'package', package, false);

/**
 *  Initialize the program from a package.json
 *  project descriptor, optionally overriding
 *  the name, description and class to instantiate.
 *
 *  @param package The path to package.json.
 *  @param name A specific name for the root command (optional).
 *  @param description A specific description for the root command (optional).
 *  @param clazz A specific class to instantiate.
 */
function create(package, name, description, clazz) {
  clazz = clazz || Program;
  var program = new clazz(basename(process.argv[1]));
  program.package(package);
  if(name) program.name(name);
  if(description) program.description(description);
  return program;
}

module.exports = create;
module.exports.re = re;
module.exports.define = define;
module.exports.key = getKey;
module.exports.Program = Program;
module.exports.Command = Command;
module.exports.Option = Option;
module.exports.Flag = Flag;
<commit_msg>Test for extra method.<commit_after>var events = require('events');
var fs = require('fs');
var path = require('path'), basename = path.basename;
var util = require('util');
var camelcase = require('cli-util').camelcase;

var mutators = {
  cmd: {
    options: false,
    commands: false,
    names: false,
    key: true,
    name: true,
    description: true,
    action: true
  },
  arg: {
    names: false,
    key: true,
    name: true,
    optional: true,
    multiple: true,
    value: true,
    converter: true,
    extra: true,
    description: true,
    action: true
  },
  prg: {
    converter: true
  }
}

var k, keys;
var re = {
  delimiter: function(){return /[ ,|]+/;},
  required: function(){return /^=?</;},
  multiple: function(){return /\.\.\./;},
  extra: function(){return /^([^=\[<]*)((=|\[|<).*)/;},
  no: function(){return /(\[no-?\]-?)/;},
  nor: function(){return /(-\[?no-?\]?-?)/;}
}

function initialize(options, properties) {
  for(var z in options) {
    if(~properties.indexOf(z) && options[z]) this[z](options[z]);
  }
}

/**
 *  Retrieve the key for an option.
 *
 *  Scope is the option. Alternatively you may pass a
 *  string of the raw name passed when instantiating the options.
 *
 *  @param names Array of names or raw string name (optional).
 */
function getKey(names, name) {
  var k, names = names || this._names;
  name = name || this._name;
  if(typeof names == 'string') {
    name = names;
    names = names.split(re.delimiter());
  }
  names = names.slice(0);
  if(this._extra) {
    var j = names.length -1;
    var nm = names[j];
    while(re.extra().test(nm) || re.multiple().test(nm)) {
      // allow for flush extra values
      if(/^-+/.test(nm)) {
        names[j] = nm.replace(re.extra(), "$1");
      }else{
        names.pop();
      }
      nm = names[--j];
    }
    this._names = sortNames(names);
  }
  var k = names.reduce(
    function (a, b) { return a.length > b.length ? a : b; });
  k = k.replace(/^-+/, '');
  return camelcase(k.toLowerCase());
}

function sortNames(names) {
  // sort short options before long options
  return names.sort(function(a, b) {
    var re = /^-[^-]/;
    return re.test(a) ? -1 : re.test(b) ? 1 : 0;
  });
}

/**
 *  Retrieve the extra portion of the option name.
 *
 *  Note this also updates the names array to not include
 *  the extra portion.
 */
function getExtra() {
  if(re.no().test(this._name)) {
    this._extra = false;
    return;
  }
  if(!re.extra().test(this._name)) return;
  this._extra = this._name.replace(re.extra(), "$2");
  //console.log(this._extra);
  var name = this._name.replace(re.extra(), "$1");
  //console.log('name: %s', name);
  this._names = name.split(re.delimiter());
  if(!this._names[this._names.length - 1]) this._names.pop();
  this._names = sortNames(this._names);
}

var EventProxy = {
  setMaxListeners: function() {
    return this._emitter.setMaxListeners.apply(this, arguments);
  },
  emit: function() {
    return this._emitter.emit.apply(this, arguments);
  },
  addListener: function() {
    return this._emitter.addListener.apply(this, arguments);
  },
  on: function() {
    return this._emitter.on.apply(this, arguments);
  },
  once: function() {
    return this._emitter.once.apply(this, arguments);
  },
  removeListener: function() {
    return this._emitter.removeListener.apply(this, arguments);
  },
  removeAllListeners: function() {
    return this._emitter.removeAllListeners.apply(this, arguments);
  },
  listeners: function() {
    return this._emitter.listeners.apply(this, arguments);
  }
}

var enumerable = process.env.CLI_TOOLKIT_DEBUG ? true : false;

function define(obj, name, value, writable) {
  writable = writable || false;
  Object.defineProperty(obj, name,
    {
      enumerable: enumerable,
      configurable: false,
      writable: writable,
      value: value
    }
  );
}

/**
 *  Abstract super class.
 *
 *  @param name The argument name.
 *  @param description The argument description.
 *  @param options The argument options or conversion function.
 */
var Argument = function(name, description, options) {
  if(typeof name == 'object') options = name;
  define(this, '_name', name, true);
  define(this, '_description', description || '', true);
  define(this, '_key', '', true);
  define(this, '_optional', true, true);
  define(this, '_multiple', false, true);
  define(this, '_value', undefined, true);
  define(this, '_converter', undefined, true);
  define(this, '_action', undefined, true);
  define(this, '_extra', undefined, true);
  define(this, '_names', undefined, true);

  // event emitter
  define(this, '_emitter', new events.EventEmitter(), false);
  define(this, '_events', undefined, true);
  define(this, '_maxListeners', undefined, true);
  define(this, 'domain', undefined, true);

  if(options === JSON) {
    this._converter = JSON;
  }else if(options && (typeof options == 'object') && !Array.isArray(options)) {
    initialize.call(this, options, Object.keys(mutators.arg));
  }else if((typeof options == 'function') || this.isFunctionArray(options)){
    this._converter = options;
    if(arguments.length > 3 && this._value === undefined) {
      this._value = arguments[3];
    }
  }else {
    this._value = options;
    if(arguments.length > 3
      && (typeof(arguments[3]) == 'function'
      || this.isFunctionArray(options))) {
      this._converter = arguments[3];
    }
  }

  if(!this._name || typeof this._name !== 'string') {
    throw new TypeError('Invalid argument name \'' + this._name + '\'');
  }

  // strip no prefixes
  var no = re.no();
  var name = '' + this._name;
  if((this instanceof Flag) && no.test(this._name)) {
    name = this._name.replace(no, '');
  }

  this._names = this._name.split(re.delimiter());
  //console.dir(this._names);
  getExtra.call(this);
  if(re.required().test(this._extra)) {
    this._optional = false;
  }
  if(re.multiple().test(this._extra)) {
    this._multiple = true;
  }
  this._key = getKey.call(this, name);
  //console.log('key', this._key);
}

for(k in EventProxy) {
  define(Argument.prototype, k, EventProxy[k], false);
}

function toString(delimiter) {
  if(!arguments.length) return Object.prototype.toString.call(this);
  delimiter = delimiter || ' | ';
  var names = sortNames(this.names());
  return names.join(delimiter);
}
define(Argument.prototype, 'toString', toString, false);

/**
 *  Retrieve a standardized string to use when listing options.
 */
getOptionString = function(delimiter, assignment) {
  assignment = assignment || '=';
  delimiter = delimiter || ', ';
  var extra = (this.extra && this.extra()) ? this.extra() || '' : '';
  if(extra) {
    extra = extra.replace(/^(.?)=(.*)$/, "$1$2");
    extra = assignment + extra;
  }
  return this.toString(delimiter) + extra;
}
define(Argument.prototype, 'getOptionString', getOptionString, false);

/**
 *  Determines whether an array consists solely of functions
 *  allowing for the special case JSON.
 *
 *  @param arr The array candidate.
 */
Argument.prototype.isFunctionArray = function(arr) {
  if(!Array.isArray(arr)) return false;
  var i, item;
  for(i = 0;i < arr.length;i++) {
    item = arr[i];
    if(item !== JSON && !(typeof item == 'function')) return false;
  }
  return true;
}

keys = Object.keys(mutators.arg);
keys.forEach(function(name) {
  var read = function() {
    return this['_' + name];
  }
  var write = function(value) {
    var key = '_' + name;
    if(!arguments.length) return this[key];
    this[key] = value;
    return this;
  }
  define(Argument.prototype, name, mutators.arg[name] ? write : read, false);
})

/**
 *  Represents an option argument.
 */
var Option = function() {
  Argument.apply(this, arguments);
}

util.inherits(Option, Argument);

/**
 *  Represents a flag argument.
 */
var Flag = function() {
  Argument.apply(this, arguments);
  //console.log('Flag %s %s', this._name, this._description);
  //this._value = false;
}

util.inherits(Flag, Argument);

/**
 *  Represents a command argument.
 */
var Command = function(name, description, options) {
  //events.EventEmitter.call(this);
  if(typeof name == 'object') options = name;

  // private
  define(this, '_commands', {}, true);
  define(this, '_options', {}, true);
  define(this, '_name', name || '', true);
  define(this, '_description', description || '', true);
  define(this, '_key', '', true);
  define(this, '_action', undefined, true);
  define(this, '_names', undefined, true);
  //define(this, '_package', undefined, true);

  // event emitter
  define(this, '_emitter', new events.EventEmitter(), false);
  define(this, '_events', undefined, true);
  define(this, '_maxListeners', undefined, true);
  define(this, 'domain', undefined, true);

  if((typeof options == 'object')) {
    initialize.call(this, options, Object.keys(mutators.cmd));
  }

  if(!this._name || typeof this._name !== 'string') {
    throw new TypeError('Invalid command name \'' + this._name + '\'');
  }

  this._names = this._name.split(re.delimiter());
  this._key = getKey.call(this);
}

define(Command.prototype, 'getOptionString', getOptionString, false);
define(Command.prototype, 'toString', toString, false);

for(k in EventProxy) {
  define(Command.prototype, k, EventProxy[k], false);
}

keys = Object.keys(mutators.cmd);
keys.forEach(function(name) {
  var read = function() {
    return this['_' + name];
  }
  var write = function(value) {
    var key = '_' + name;
    if(value === undefined) return this[key];
    this[key] = value;
    return this;
  }
  define(Command.prototype, name, mutators.cmd[name] ? write : read, false);
})

/**
 *  Define a command argument.
 */
function command(name, description, options) {
  var opt = (name instanceof Command) ? name
    : new Command(name, description, options);
  this._commands[opt.key()] = opt;
  return description ? this : opt;
}
define(Command.prototype, 'command', command, false);

/**
 *  Define an option argument.
 */
function option(name, description, options, coerce, value) {
  var clazz = Option;
  if(typeof name === 'string') {
    if(re.no().test(name) || !re.extra().test(name)) {
      clazz = Flag;
    }
  }
  var opt = (name instanceof clazz) ? name
    : new clazz(name, description, options, coerce, value);
  this._options[opt.key()] = opt;
  return this;
}
define(Command.prototype, 'option', option, false);

/**
 *  Define a flag argument explicitly.
 */
function flag(name, description, options, coerce, value) {
  var opt = (name instanceof Flag) ? name
    : new Flag(name, description, options, coerce, value);
  this._options[opt.key()] = opt;
  return this;
}
define(Command.prototype, 'flag', flag, false);

/**
 *  Represents the program.
 */
var Program = function() {
  Command.apply(this, arguments);
  define(this, '_version', '0.0.1', true);
  define(this, '_package', undefined, true);
  define(this, '_converter', undefined, true);
}

util.inherits(Program, Command);

keys = Object.keys(mutators.prg);
keys.forEach(function(name) {
  var write = function(value) {
    var key = '_' + name;
    if(!arguments.length) return this[key];
    this[key] = value;
    return this;
  }
  define(Program.prototype, name, write, false);
})

/**
 *  Set the program package descriptor.
 *
 *  @param path The path to the package descriptor or an existing
 *  package object.
 */
function package(path) {
  if(!arguments.length) return this._package;
  if(arguments.length === 1 && !path) {
    this._package = path;
    return this._package;
  }
  var pkg;
  if(path && typeof(path) === 'string' && fs.existsSync(path)) {
    try {
      pkg = this._package = require(path);
    }catch(e) {
      throw new Error(util.format(
        'package parse error %s (malformed json)', path));
    }
  }else if(path && typeof path === 'object') {
    pkg = this._package = path;
  }
  if(!pkg) {
    throw new Error(util.format(
      'package descriptor %s does not exist', path));
  }
  this._version = pkg.version;
  if(pkg.description) this._description = pkg.description;
  return this;
}
define(Program.prototype, 'package', package, false);

/**
 *  Initialize the program from a package.json
 *  project descriptor, optionally overriding
 *  the name, description and class to instantiate.
 *
 *  @param package The path to package.json.
 *  @param name A specific name for the root command (optional).
 *  @param description A specific description for the root command (optional).
 *  @param clazz A specific class to instantiate.
 */
function create(package, name, description, clazz) {
  clazz = clazz || Program;
  var program = new clazz(basename(process.argv[1]));
  program.package(package);
  if(name) program.name(name);
  if(description) program.description(description);
  return program;
}

module.exports = create;
module.exports.re = re;
module.exports.define = define;
module.exports.key = getKey;
module.exports.Program = Program;
module.exports.Command = Command;
module.exports.Option = Option;
module.exports.Flag = Flag;
<|endoftext|>


<commit_before>'use strict';

module.exports = {
	URL: {
		DEFAULT: {
			production: 'https://api.gerencianet.com.br/v1',
			sandbox: 'https://sandbox.gerencianet.com.br/v1'
		},
		PIX: {
			production: 'https://api-pix.gerencianet.com.br',
			sandbox: 'https://api-pix-h.gerencianet.com.br'
		}
	},
	ENDPOINTS: {
		PIX: {
			authorize:{
				route: '/oauth/token',
				method: 'post'
			},
			pixCreateCharge: {
				route: '/v2/cob/:txid',
				method: 'put'
			},
			pixUpdateCharge: {
				route: '/v2/cob/:txid',
				method: 'patch'
			},
			pixCreateImmediateCharge: {
				route: '/v2/cob',
				method: 'post'
			},
			pixDetailCharge: {
				route: '/v2/cob/:txid',
				method: 'get'
			},
			pixListCharges: {
				route: '/v2/cob',
				method: 'get'
			},
			pixDetail: {
				route: '/v2/pix/:e2eId',
				method: 'get'
			},
			pixListReceived: {
				route: '/v2/pix',
				method: 'get'
			},
			pixSend: {
				route: '/v2/pix',
				method: 'post'
			},
			pixDevolution: {
				route: '/v2/pix/:e2eId/devolucao/:id',
				method: 'put'
			},
			pixDetailDevolution: {
				route: '/v2/pix/:e2eId/devolucao/:id',
				method: 'get'
			},
			pixConfigWebhook: {
				route: '/v2/webhook/:chave',
				method: 'put'
			},
			pixDetailWebhook: {
				route: '/v2/webhook/:chave',
				method: 'get'
			},
			pixListWebhook: {
				route: '/v2/webhook',
				method: 'get'
			},
			pixDeleteWebhook: {
				route: '/v2/webhook/:chave',
				method: 'delete'
			},
			pixCreateLocation: {
				route: '/v2/loc',
				method: 'post'
			},
			pixListLocation: {
				route: '/v2/loc',
				method: 'get'
			},
			pixDetailLocation: {
				route: '/v2/loc/:id',
				method: 'get'
			},
			pixGenerateQRCode: {
				route: '/v2/loc/:id/qrcode',
				method: 'get'
			},
			pixUnsetTxid: {
				route: '/v2/loc/:id/txid',
				method: 'delete'
			},
			gnCreateEvp: {
				route: '/v2/gn/evp',
				method: 'post'
			},
			gnListEvp: {
				route: '/v2/gn/evp',
				method: 'get'
			},
			gnDeleteEvp: {
				route: '/v2/gn/evp/:chave',
				method: 'delete'
			},
			gnDetailBalance: {
				route: '/v2/gn/saldo',
				method: 'get'
			},
			gnUpdateSettings: {
				route: '/v2/gn/config',
				method: 'put'
			},
			gnDetailSettings: {
				route: '/v2/gn/config',
				method: 'get'
			}
		},

		DEFAULT: {
			authorize: {
				route: '/authorize',
				method: 'post'
			},
			createCharge: {
				route: '/charge',
				method: 'post'
			},
			detailCharge: {
				route: '/charge/:id',
				method: 'get'
			},
			updateChargeMetadata: {
				route: '/charge/:id/metadata',
				method: 'put'
			},
			updateBillet: {
				route: '/charge/:id/billet',
				method: 'put'
			},
			payCharge: {
				route: '/charge/:id/pay',
				method: 'post'
			},
			cancelCharge: {
				route: '/charge/:id/cancel',
				method: 'put'
			},
			createCarnet: {
				route: '/carnet',
				method: 'post'
			},
			detailCarnet: {
				route: '/carnet/:id',
				method: 'get'
			},
			updateParcel: {
				route: '/carnet/:id/parcel/:parcel',
				method: 'put'
			},
			updateCarnetMetadata: {
				route: '/carnet/:id/metadata',
				method: 'put'
			},
			getNotification: {
				route: '/notification/:token',
				method: 'get'
			},
			getPlans: {
				route: '/plans',
				method: 'get'
			},
			createPlan: {
				route: '/plan',
				method: 'post'
			},
			deletePlan: {
				route: '/plan/:id',
				method: 'del'
			},
			createSubscription: {
				route: '/plan/:id/subscription',
				method: 'post'
			},
			detailSubscription: {
				route: '/subscription/:id',
				method: 'get'
			},
			paySubscription: {
				route: '/subscription/:id/pay',
				method: 'post'
			},
			cancelSubscription: {
				route: '/subscription/:id/cancel',
				method: 'put'
			},
			updateSubscriptionMetadata: {
				route: '/subscription/:id/metadata',
				method: 'put'
			},
			getInstallments: {
				route: '/installments',
				method: 'get'
			},
			resendBillet: {
				route: '/charge/:id/billet/resend',
				method: 'post'
			},
			createChargeHistory: {
				route: '/charge/:id/history',
				method: 'post'
			},
			resendCarnet: {
				route: '/carnet/:id/resend',
				method: 'post'
			},
			resendParcel: {
				route: '/carnet/:id/parcel/:parcel/resend',
				method: 'post'
			},
			createCarnetHistory: {
				route: '/carnet/:id/history',
				method: 'post'
			},
			cancelCarnet: {
				route: '/carnet/:id/cancel',
				method: 'put'
			},
			cancelParcel: {
				route: '/carnet/:id/parcel/:parcel/cancel',
				method: 'put'
			},
			linkCharge: {
				route: '/charge/:id/link',
				method: 'post'
			},
			chargeLink: {
				route: '/charge/:id/link',
				method: 'post'
			},
			updateChargeLink: {
				route: '/charge/:id/link',
				method: 'put'
			},
			updatePlan: {
				route: '/plan/:id',
				method: 'put'
			},
			createSubscriptionHistory: {
				route: '/subscription/:id/history',
				method: 'post'
			},
			createChargeBalanceSheet: {
				route: '/charge/:id/balance-sheet',
				method: 'post'
			},
			settleCharge: {
				route: '/charge/:id/settle',
				method: 'put'
			},
			settleCarnetParcel: {
				route: '/carnet/:id/parcel/:parcel/settle',
				method: 'put'
			},
			oneStep: {
				route: '/charge/one-step',
				method: 'post'
			}
		}
	}
};
<commit_msg>Correção endpoint deletePlan<commit_after>'use strict';

module.exports = {
	URL: {
		DEFAULT: {
			production: 'https://api.gerencianet.com.br/v1',
			sandbox: 'https://sandbox.gerencianet.com.br/v1'
		},
		PIX: {
			production: 'https://api-pix.gerencianet.com.br',
			sandbox: 'https://api-pix-h.gerencianet.com.br'
		}
	},
	ENDPOINTS: {
		PIX: {
			authorize:{
				route: '/oauth/token',
				method: 'post'
			},
			pixCreateCharge: {
				route: '/v2/cob/:txid',
				method: 'put'
			},
			pixUpdateCharge: {
				route: '/v2/cob/:txid',
				method: 'patch'
			},
			pixCreateImmediateCharge: {
				route: '/v2/cob',
				method: 'post'
			},
			pixDetailCharge: {
				route: '/v2/cob/:txid',
				method: 'get'
			},
			pixListCharges: {
				route: '/v2/cob',
				method: 'get'
			},
			pixDetail: {
				route: '/v2/pix/:e2eId',
				method: 'get'
			},
			pixListReceived: {
				route: '/v2/pix',
				method: 'get'
			},
			pixSend: {
				route: '/v2/pix',
				method: 'post'
			},
			pixDevolution: {
				route: '/v2/pix/:e2eId/devolucao/:id',
				method: 'put'
			},
			pixDetailDevolution: {
				route: '/v2/pix/:e2eId/devolucao/:id',
				method: 'get'
			},
			pixConfigWebhook: {
				route: '/v2/webhook/:chave',
				method: 'put'
			},
			pixDetailWebhook: {
				route: '/v2/webhook/:chave',
				method: 'get'
			},
			pixListWebhook: {
				route: '/v2/webhook',
				method: 'get'
			},
			pixDeleteWebhook: {
				route: '/v2/webhook/:chave',
				method: 'delete'
			},
			pixCreateLocation: {
				route: '/v2/loc',
				method: 'post'
			},
			pixListLocation: {
				route: '/v2/loc',
				method: 'get'
			},
			pixDetailLocation: {
				route: '/v2/loc/:id',
				method: 'get'
			},
			pixGenerateQRCode: {
				route: '/v2/loc/:id/qrcode',
				method: 'get'
			},
			pixUnsetTxid: {
				route: '/v2/loc/:id/txid',
				method: 'delete'
			},
			gnCreateEvp: {
				route: '/v2/gn/evp',
				method: 'post'
			},
			gnListEvp: {
				route: '/v2/gn/evp',
				method: 'get'
			},
			gnDeleteEvp: {
				route: '/v2/gn/evp/:chave',
				method: 'delete'
			},
			gnDetailBalance: {
				route: '/v2/gn/saldo',
				method: 'get'
			},
			gnUpdateSettings: {
				route: '/v2/gn/config',
				method: 'put'
			},
			gnDetailSettings: {
				route: '/v2/gn/config',
				method: 'get'
			}
		},

		DEFAULT: {
			authorize: {
				route: '/authorize',
				method: 'post'
			},
			createCharge: {
				route: '/charge',
				method: 'post'
			},
			detailCharge: {
				route: '/charge/:id',
				method: 'get'
			},
			updateChargeMetadata: {
				route: '/charge/:id/metadata',
				method: 'put'
			},
			updateBillet: {
				route: '/charge/:id/billet',
				method: 'put'
			},
			payCharge: {
				route: '/charge/:id/pay',
				method: 'post'
			},
			cancelCharge: {
				route: '/charge/:id/cancel',
				method: 'put'
			},
			createCarnet: {
				route: '/carnet',
				method: 'post'
			},
			detailCarnet: {
				route: '/carnet/:id',
				method: 'get'
			},
			updateParcel: {
				route: '/carnet/:id/parcel/:parcel',
				method: 'put'
			},
			updateCarnetMetadata: {
				route: '/carnet/:id/metadata',
				method: 'put'
			},
			getNotification: {
				route: '/notification/:token',
				method: 'get'
			},
			getPlans: {
				route: '/plans',
				method: 'get'
			},
			createPlan: {
				route: '/plan',
				method: 'post'
			},
			deletePlan: {
				route: '/plan/:id',
				method: 'delete'
			},
			createSubscription: {
				route: '/plan/:id/subscription',
				method: 'post'
			},
			detailSubscription: {
				route: '/subscription/:id',
				method: 'get'
			},
			paySubscription: {
				route: '/subscription/:id/pay',
				method: 'post'
			},
			cancelSubscription: {
				route: '/subscription/:id/cancel',
				method: 'put'
			},
			updateSubscriptionMetadata: {
				route: '/subscription/:id/metadata',
				method: 'put'
			},
			getInstallments: {
				route: '/installments',
				method: 'get'
			},
			resendBillet: {
				route: '/charge/:id/billet/resend',
				method: 'post'
			},
			createChargeHistory: {
				route: '/charge/:id/history',
				method: 'post'
			},
			resendCarnet: {
				route: '/carnet/:id/resend',
				method: 'post'
			},
			resendParcel: {
				route: '/carnet/:id/parcel/:parcel/resend',
				method: 'post'
			},
			createCarnetHistory: {
				route: '/carnet/:id/history',
				method: 'post'
			},
			cancelCarnet: {
				route: '/carnet/:id/cancel',
				method: 'put'
			},
			cancelParcel: {
				route: '/carnet/:id/parcel/:parcel/cancel',
				method: 'put'
			},
			linkCharge: {
				route: '/charge/:id/link',
				method: 'post'
			},
			chargeLink: {
				route: '/charge/:id/link',
				method: 'post'
			},
			updateChargeLink: {
				route: '/charge/:id/link',
				method: 'put'
			},
			updatePlan: {
				route: '/plan/:id',
				method: 'put'
			},
			createSubscriptionHistory: {
				route: '/subscription/:id/history',
				method: 'post'
			},
			createChargeBalanceSheet: {
				route: '/charge/:id/balance-sheet',
				method: 'post'
			},
			settleCharge: {
				route: '/charge/:id/settle',
				method: 'put'
			},
			settleCarnetParcel: {
				route: '/carnet/:id/parcel/:parcel/settle',
				method: 'put'
			},
			oneStep: {
				route: '/charge/one-step',
				method: 'post'
			}
		}
	}
};
<|endoftext|>


<commit_before>const Readable = require('stream').Readable
const pump = require('pump')
const collect = require('collect-stream')
const ln = require('hyperdrive-ln')
const proof = require('./proof')
const bufferJSON = require('buffer-json')

module.exports = HyperIdentity

function HyperIdentity (archive) {
  if (!(this instanceof HyperIdentity)) return new HyperIdentity(archive)

  this._archive = archive
  this.id = this._archive.id
  this.key = this._archive.key
  this.discoveryKey = this._archive.discoveryKey
}

HyperIdentity.prototype.list = function (opts, cb) {
  return this._archive.list(opts, cb)
}

HyperIdentity.prototype.createFileReadStream = function (entry, opts) {
  return this._archive.createFileReadStream(entry, opts)
}

HyperIdentity.prototype.setMeta = function (meta, cb) {
  pump(source(JSON.stringify(meta)), this._archive.createFileWriteStream('identity.json'), cb)
}

HyperIdentity.prototype.getMeta = function (cb) {
  collect(this._archive.createFileReadStream('identity.json'), cb)
}

HyperIdentity.prototype.serviceLinkToken = function (service, archiveKey) {
  var payload = proof.msg(service, {publicKey: this._archive.key}, archiveKey)

  return JSON.stringify({
    service: service.publicKey,
    payload: payload
  }, bufferJSON.replacer)
}

HyperIdentity.prototype.acceptLinkToken = function (token, cb) {
  var archive = this._archive
  token = JSON.parse(token, bufferJSON.reviver)
  var secretKey = this._archive.metadata.secretKey
  var link = proof.openMsg({publicKey: token.service}, {secretKey}, token.payload)

  if (!link) return cb(new Error('unable to read token'))

  var resp = JSON.stringify(createResponse(
    { publicKey: token.service }, // service
    { secretKey: archive.metadata.secretKey } // self
  ), bufferJSON.replacer)

  pump(source(resp), archive.createFileWriteStream(proofPath(token.service)), err => {
    if (err) return cb(err)

    ln.link(archive, linkPath(token.service), link, cb)
  })

  function createResponse (service, self) {
    return proof.msg(self, service, 'APPROVED')
  }
}

HyperIdentity.prototype.verifyAcceptingness = function (service, cb) {
  var archive = this._archive
  archive.list((err, entries) => {
    if (err) return cb(err)

    for (var i = 0; i < entries.length; i++) {
      if (entries[i].name === proofPath(service.publicKey)) {
        collect(archive.createFileReadStream(proofPath(service.publicKey)), (err, data) => {
          if (err) return cb(err)
          cb(null, proof.openMsg({publicKey: archive.key}, {secretKey: service.secretKey}, JSON.parse(data, bufferJSON.reviver)))
        })

        break
      }
    }
  })
}

// TODO: find a better name for this
HyperIdentity.prototype.link = function (name, key, cb) {
  ln.link(this._archive, 'links/' + name, key, cb)
}

HyperIdentity.prototype.readlink = function (name, cb) {
  return ln.readlink(this._archive, 'links/' + name, cb)
}

HyperIdentity.prototype.replicate = function (opts) {
  return this._archive.replicate(opts)
}

function source (str) {
  var s = new Readable()
  s.push(str)
  s.push(null)
  return s
}

function proofPath (key) {
  return `proofs/${key.toString('hex')}`
}

function linkPath (key) {
  return `links/${key.toString('hex')}`
}
<commit_msg>verifyAcceptingness should always cb<commit_after>const Readable = require('stream').Readable
const pump = require('pump')
const collect = require('collect-stream')
const ln = require('hyperdrive-ln')
const proof = require('./proof')
const bufferJSON = require('buffer-json')

module.exports = HyperIdentity

function HyperIdentity (archive) {
  if (!(this instanceof HyperIdentity)) return new HyperIdentity(archive)

  this._archive = archive
  this.id = this._archive.id
  this.key = this._archive.key
  this.discoveryKey = this._archive.discoveryKey
}

HyperIdentity.prototype.list = function (opts, cb) {
  return this._archive.list(opts, cb)
}

HyperIdentity.prototype.createFileReadStream = function (entry, opts) {
  return this._archive.createFileReadStream(entry, opts)
}

HyperIdentity.prototype.setMeta = function (meta, cb) {
  pump(source(JSON.stringify(meta)), this._archive.createFileWriteStream('identity.json'), cb)
}

HyperIdentity.prototype.getMeta = function (cb) {
  collect(this._archive.createFileReadStream('identity.json'), cb)
}

HyperIdentity.prototype.serviceLinkToken = function (service, archiveKey) {
  var payload = proof.msg(service, {publicKey: this._archive.key}, archiveKey)

  return JSON.stringify({
    service: service.publicKey,
    payload: payload
  }, bufferJSON.replacer)
}

HyperIdentity.prototype.acceptLinkToken = function (token, cb) {
  var archive = this._archive
  token = JSON.parse(token, bufferJSON.reviver)
  var secretKey = this._archive.metadata.secretKey
  var link = proof.openMsg({publicKey: token.service}, {secretKey}, token.payload)

  if (!link) return cb(new Error('unable to read token'))

  var resp = JSON.stringify(createResponse(
    { publicKey: token.service }, // service
    { secretKey: archive.metadata.secretKey } // self
  ), bufferJSON.replacer)

  pump(source(resp), archive.createFileWriteStream(proofPath(token.service)), err => {
    if (err) return cb(err)

    ln.link(archive, linkPath(token.service), link, cb)
  })

  function createResponse (service, self) {
    return proof.msg(self, service, 'APPROVED')
  }
}

HyperIdentity.prototype.verifyAcceptingness = function (service, cb) {
  var archive = this._archive
  archive.list((err, entries) => {
    if (err) return cb(err)

    for (var i = 0; i < entries.length; i++) {
      if (entries[i].name === proofPath(service.publicKey)) {
        collect(archive.createFileReadStream(proofPath(service.publicKey)), (err, data) => {
          if (err) return cb(err)
          cb(null, proof.openMsg({publicKey: archive.key}, {secretKey: service.secretKey}, JSON.parse(data, bufferJSON.reviver)))
        })

        break
      }
    }

    cb(null) // no error, but not verified
  })
}

// TODO: find a better name for this
HyperIdentity.prototype.link = function (name, key, cb) {
  ln.link(this._archive, 'links/' + name, key, cb)
}

HyperIdentity.prototype.readlink = function (name, cb) {
  return ln.readlink(this._archive, 'links/' + name, cb)
}

HyperIdentity.prototype.replicate = function (opts) {
  return this._archive.replicate(opts)
}

function source (str) {
  var s = new Readable()
  s.push(str)
  s.push(null)
  return s
}

function proofPath (key) {
  return `proofs/${key.toString('hex')}`
}

function linkPath (key) {
  return `links/${key.toString('hex')}`
}
<|endoftext|>


<commit_before>var documentReady = require('document-ready')
var nanorouter = require('nanorouter')
var nanomount = require('nanomount')
var nanomorph = require('nanomorph')
var nanoraf = require('nanoraf')
var nanobus = require('nanobus')
var assert = require('assert')

var onHistoryChange = require('./lib/history')
var onHref = require('./lib/href')

module.exports = Framework

function Framework (opts) {
  opts = opts || {}

  var routerOpts = {
    default: opts.defaultRoute || '/404',
    curry: true
  }

  var router = nanorouter(routerOpts)
  var bus = nanobus()
  var rerender = null
  var tree = null
  var state = {}

  return {
    toString: toString,
    use: register,
    mount: mount,
    route: route,
    start: start
  }

  function route (route, handler) {
    router.on(route, function (params) {
      return function () {
        state.params = params
        return handler(state, emit)
      }
    })
  }

  function register (cb) {
    cb(state, bus)
  }

  function start () {
    tree = router(createLocation(), state, emit)
    rerender = nanoraf(function () {
      var newTree = router(createLocation(), state, emit)
      tree = nanomorph(tree, newTree)
    })

    bus.on('render', rerender)

    if (opts.history !== false) {
      onHistoryChange(function (href) {
        bus.emit('pushState', window.location.href)
        scrollIntoView()
      })

      if (opts.href !== false) {
        onHref(function (location) {
          var href = location.href
          var currHref = window.location.href
          if (href === currHref) return
          window.history.pushState({}, null, href)
          bus.emit('pushState', window.location.href)
          bus.emit('render')
          scrollIntoView()
        })
      }
    }

    documentReady(function () {
      bus.emit('DOMContentLoaded')
    })

    return tree
  }

  function emit (eventName, data) {
    bus.emit(eventName, data)
  }

  function mount (selector) {
    var newTree = start()
    documentReady(function () {
      var root = document.querySelector(selector)
      assert.ok(root, 'could not query selector: ' + selector)
      nanomount(root, newTree)
      tree = root
    })
  }

  function toString (location, _state) {
    state = _state || {}
    var html = router(location)
    assert.equal()
    return html.toString()
  }
}

function scrollIntoView () {
  var hash = window.location.hash
  if (hash) {
    try {
      var el = document.querySelector(hash)
      if (el) el.scrollIntoView(true)
    } catch (e) {}
  }
}

function createLocation () {
  var pathname = window.location.pathname.replace(/\/$/, '')
  var hash = window.location.hash.replace(/^#/, '/')
  return pathname + hash
}
<commit_msg>fix pushState event (#434)<commit_after>var documentReady = require('document-ready')
var nanorouter = require('nanorouter')
var nanomount = require('nanomount')
var nanomorph = require('nanomorph')
var nanoraf = require('nanoraf')
var nanobus = require('nanobus')
var assert = require('assert')

var onHistoryChange = require('./lib/history')
var onHref = require('./lib/href')

module.exports = Framework

function Framework (opts) {
  opts = opts || {}

  var routerOpts = {
    default: opts.defaultRoute || '/404',
    curry: true
  }

  var router = nanorouter(routerOpts)
  var bus = nanobus()
  var rerender = null
  var tree = null
  var state = {}

  return {
    toString: toString,
    use: register,
    mount: mount,
    route: route,
    start: start
  }

  function route (route, handler) {
    router.on(route, function (params) {
      return function () {
        state.params = params
        return handler(state, emit)
      }
    })
  }

  function register (cb) {
    cb(state, bus)
  }

  function start () {
    tree = router(createLocation(), state, emit)
    rerender = nanoraf(function () {
      var newTree = router(createLocation(), state, emit)
      tree = nanomorph(tree, newTree)
    })

    bus.on('render', rerender)

    if (opts.history !== false) {
      onHistoryChange(function (href) {
        bus.emit('pushState')
      })

      bus.on('pushState', function (href) {
        if (href) window.history.pushState({}, null, href)
        bus.emit('render')
        scrollIntoView()
      })

      if (opts.href !== false) {
        onHref(function (location) {
          var href = location.href
          var currHref = window.location.href
          if (href === currHref) return
          bus.emit('pushState', href)
        })
      }
    }

    documentReady(function () {
      bus.emit('DOMContentLoaded')
    })

    return tree
  }

  function emit (eventName, data) {
    bus.emit(eventName, data)
  }

  function mount (selector) {
    var newTree = start()
    documentReady(function () {
      var root = document.querySelector(selector)
      assert.ok(root, 'could not query selector: ' + selector)
      nanomount(root, newTree)
      tree = root
    })
  }

  function toString (location, _state) {
    state = _state || {}
    var html = router(location)
    assert.equal()
    return html.toString()
  }
}

function scrollIntoView () {
  var hash = window.location.hash
  if (hash) {
    try {
      var el = document.querySelector(hash)
      if (el) el.scrollIntoView(true)
    } catch (e) {}
  }
}

function createLocation () {
  var pathname = window.location.pathname.replace(/\/$/, '')
  var hash = window.location.hash.replace(/^#/, '/')
  return pathname + hash
}
<|endoftext|>


<commit_before>module.exports = function (meta, content, context, callback) {
    throw new Error("Handler not implemented");
};

module.exports.extension = "html";
<commit_msg>implemented html handler<commit_after>module.exports = function (meta, content, context, callback) {
    callback && callback(null, content);
};

module.exports.extension = "html";
<|endoftext|>