<commit_before>var _ = require('underscore'),
  async = require('async'),
  bag = require('bagofholding'),
  cron = require('cron'),
  Db = require('./db'),
  fs = require('fs'),
  fsx = require('fs.extra'),
  p = require('path');

/**
 * class Couchpenter
 *
 * @param {String} url: CouchDB URL in format http(s)://user:pass@host:port, fallback to COUCHDB_URL environment variable, default to http://localhost:5984
 * @param {String} opts: optional
 * - setupFile: Couchpenter setup file
 * - dir: documents directory
 * - prefix: prefix for database names
 * - dbSetup: Couchpenter database setup object
 */
function Couchpenter(url, opts) {
  opts = opts || {};

  this.url = url || process.env.COUCHDB_URL || 'http://localhost:5984';
  this.opts = {
    setupFile: opts.setupFile || 'couchpenter.json',
    dir: opts.dir || process.cwd(),
    prefix: opts.prefix,
    setup: opts.dbSetup
  };
}

/**
 * Create a sample couchpenter.json setup file in current working directory.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.init = function (cb) {
  console.log('Creating sample setup file: couchpenter.json');
  fsx.copy(p.join(__dirname, '../examples/couchpenter.json'), 'couchpenter.json', cb);
};

// NOTE: pardon this method to tasks mapping,
// needed to preserve backward compatibility w/ v0.1.x

/**
 * Create databases and documents, overwrite if documents exist.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.setUp = function (cb) {
  this._task(['createDatabases', 'saveDocuments'], cb);
};

/**
 * Create databases only.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.setUpDatabases = function (cb) {
  this._task(['createDatabases'], cb);
};

/**
 * Create documents only, does not overwrite if exist.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.setUpDocuments = function (cb) {
  this._task(['createDocuments'], cb);
};

/**
 * Create documents only, overwrite if exist.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.setUpDocumentsOverwrite = function (cb) {
  this._task(['saveDocuments'], cb);
};

/**
 * Alias for tearDownDatabases.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.tearDown = function (cb) {
  this.tearDownDatabases(cb);
};

/**
 * Delete databases.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.tearDownDatabases = function (cb) {
  this._task(['removeDatabases'], cb);
};

/**
 * Delete documents.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.tearDownDocuments = function (cb) {
  this._task(['removeDocuments'], cb);
};

/**
 * Alias for resetDocuments.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.reset = function (cb) {
  this.resetDocuments(cb);
};

/**
 * Delete then recreate databases.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.resetDatabases = function (cb) {
  this._task(['removeDatabases', 'createDatabases'], cb);
};

/**
 * Delete then recreate documents only.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.resetDocuments = function (cb) {
  this._task(['removeDatabases', 'createDatabases', 'createDocuments'], cb);
};

/**
 * Alias for cleanDatabases.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.clean = function (cb) {
  this.cleanDatabases(cb);
};

/**
 * Delete unknown databases (not configured in setup file).
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.cleanDatabases = function (cb) {
  this._task(['cleanDatabases'], cb);
};

/**
 * Warm up views specified in design documents.
 * If schedule is specified, then views warm up will be scheduled using cron.
 * Otherwise, it's just a once off.
 * 
 * @param {String} schedule: cron scheduling definition in standard * * * * * format
 * @param {Function} cb: standard cb(err, result) callback
 */ 
Couchpenter.prototype.warmViews = function(schedule, cb) {
  var self = this;
  if (cb) {
    new cron.CronJob(schedule, function () {
      self._task(['warmViews'], cb);
    });
  } else {
    cb = schedule;
    this._task(['warmViews'], cb);
  }
};

/**
 * Execute database tasks in series order.
 *
 * @param {Array} tasks: the tasks to execute
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype._task = function (tasks, cb) {  
  var setup = this.opts.setup || JSON.parse(bag.cli.lookupFile(this.opts.setupFile)),
    db = new Db(this.url),
    asyncTasks = [],
    self = this;

  // prefix database names if optional prefix is specified<commit_msg>Added auto-start for cronjob when scheduling warmViews.<commit_after>var _ = require('underscore'),
  async = require('async'),
  bag = require('bagofholding'),
  cron = require('cron'),
  Db = require('./db'),
  fs = require('fs'),
  fsx = require('fs.extra'),
  p = require('path');

/**
 * class Couchpenter
 *
 * @param {String} url: CouchDB URL in format http(s)://user:pass@host:port, fallback to COUCHDB_URL environment variable, default to http://localhost:5984
 * @param {String} opts: optional
 * - setupFile: Couchpenter setup file
 * - dir: documents directory
 * - prefix: prefix for database names
 * - dbSetup: Couchpenter database setup object
 */
function Couchpenter(url, opts) {
  opts = opts || {};

  this.url = url || process.env.COUCHDB_URL || 'http://localhost:5984';
  this.opts = {
    setupFile: opts.setupFile || 'couchpenter.json',
    dir: opts.dir || process.cwd(),
    prefix: opts.prefix,
    setup: opts.dbSetup
  };
}

/**
 * Create a sample couchpenter.json setup file in current working directory.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.init = function (cb) {
  console.log('Creating sample setup file: couchpenter.json');
  fsx.copy(p.join(__dirname, '../examples/couchpenter.json'), 'couchpenter.json', cb);
};

// NOTE: pardon this method to tasks mapping,
// needed to preserve backward compatibility w/ v0.1.x

/**
 * Create databases and documents, overwrite if documents exist.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.setUp = function (cb) {
  this._task(['createDatabases', 'saveDocuments'], cb);
};

/**
 * Create databases only.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.setUpDatabases = function (cb) {
  this._task(['createDatabases'], cb);
};

/**
 * Create documents only, does not overwrite if exist.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.setUpDocuments = function (cb) {
  this._task(['createDocuments'], cb);
};

/**
 * Create documents only, overwrite if exist.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.setUpDocumentsOverwrite = function (cb) {
  this._task(['saveDocuments'], cb);
};

/**
 * Alias for tearDownDatabases.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.tearDown = function (cb) {
  this.tearDownDatabases(cb);
};

/**
 * Delete databases.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.tearDownDatabases = function (cb) {
  this._task(['removeDatabases'], cb);
};

/**
 * Delete documents.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.tearDownDocuments = function (cb) {
  this._task(['removeDocuments'], cb);
};

/**
 * Alias for resetDocuments.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.reset = function (cb) {
  this.resetDocuments(cb);
};

/**
 * Delete then recreate databases.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.resetDatabases = function (cb) {
  this._task(['removeDatabases', 'createDatabases'], cb);
};

/**
 * Delete then recreate documents only.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.resetDocuments = function (cb) {
  this._task(['removeDatabases', 'createDatabases', 'createDocuments'], cb);
};

/**
 * Alias for cleanDatabases.
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.clean = function (cb) {
  this.cleanDatabases(cb);
};

/**
 * Delete unknown databases (not configured in setup file).
 *
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype.cleanDatabases = function (cb) {
  this._task(['cleanDatabases'], cb);
};

/**
 * Warm up views specified in design documents.
 * If schedule is specified, then views warm up will be scheduled using cron.
 * Otherwise, it's just a once off.
 * 
 * @param {String} schedule: cron scheduling definition in standard * * * * * format
 * @param {Function} cb: standard cb(err, result) callback
 */ 
Couchpenter.prototype.warmViews = function(schedule, cb) {
  var self = this;
  if (cb) {
    new cron.CronJob(schedule, function () {
      self._task(['warmViews'], cb);
    }, null, true);
  } else {
    cb = schedule;
    this._task(['warmViews'], cb);
  }
};

/**
 * Execute database tasks in series order.
 *
 * @param {Array} tasks: the tasks to execute
 * @param {Function} cb: standard cb(err, result) callback
 */
Couchpenter.prototype._task = function (tasks, cb) {  
  var setup = this.opts.setup || JSON.parse(bag.cli.lookupFile(this.opts.setupFile)),
    db = new Db(this.url),
    asyncTasks = [],
    self = this;

  // prefix database names if optional prefix is specified
{'fraction_non_alphanumeric': 0.15293152931529316, 'fraction_numerical': 0.002050020500205002, 'mean_word_length': 4.084418968212611, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1731861', 'n_tokens_mistral': 3113, 'n_tokens_neox': 3020, 'n_words': 847}