environmenter

Sometimes your project involves many tools and discrete pieces to run. Environmenter attempts to help this issue by facilitating the starting up of these pieces and allowing you to define rules about what to do when certain things occur.

npm install environmenter
37 downloads in the last month

environmenter - A tool to help manage your environment

Sometimes your project involves many tools and discrete pieces to run. Environmenter attempts to help this issue by facilitating the starting up of these pieces and allowing you to define rules about what to do when certain things occur.

The example json is more or less what I'm using in my project. There are 4 commands that are ran underneath environmenter: coffeescript, compass, redis, and my node app itself. When coffee recompiles a file, I check to see if it's a frontend file, backend file, or both. If it's frontend, I send a kill signal to the node process which causes it to ask all its socket.io-connected clients to reload the page. If it's backend, I restart the node process. If both, I do both.

Usage

The environmenter module is a function, and you should pass it the configuration as either a simple javascript object or as a filename that should be read as JSON. So, either of the following methods are acceptable:

require('environmenter')('/path/to/config.json');
var fs = require('fs');
fs.readFile('/path/to/config.json', function(err, jsonString) {
  // Handle err, of course...
  require('environmenter')(JSON.parse(jsonString));
});

In either case, the tool will immediately kick off the defined commands.

Config Format

The config file is an object at the outer-most level with keys being the process labels used to refer to them throughout the config. The vals are their respective rules as objects. These per-process rule objects have the following options:

  • command (required) - An array consisting of the executable, followed by any arguments. Note that "CWD" will be replaced with the current working directory.
  • logOut (required) - The label to prefix lines that come from the standard output of this process.
  • logErr (required) - The label to prefix lines that come from the standard error output of this process.
  • spawnOptions - An object to be passed as the options to the spawn command. Note that "CWD" within the values of this object will be replaced with the current working directory.
  • initialSettleDelay - Milliseconds to wait before the first line of output before deeming the process "started". Default is 800.
  • settleDelay - After the first line of output, this is the milliseconds to wait without any output before deeming the process "started". Default is 600.
  • waitForOutput - A boolean. If true, initialSettleDelay will be ignored, and environmenter will instead wait for the first line and deem the process started when settleDelay ms elapses between lines of output.
  • hide - An array of strings that, if matched, will not be echoed in the output. Node that the perform chain logic will still watch lines matched here.
  • deps - An array of process labels that need to be started up before this one can start.
  • perform - An array of objects to tell environmenter how to behave based on what comes out of this process. Both stdout and stderr are watched for this purpose. Each object is evaluated in order, and if it matches, evaluation continues through the chain unless stop is set to true.
    • on (required) - This is a regular expression (without delimeters) that will be checked against the output. If it matches, things that are expressed in this rule will happen.
    • kill - An object where the keys are process labels and the vals are signal names that will be sent to their respective processes. It is assumed that the signal used here will not actually end the process.
    • restart - An array of process labels that will be killed via the SIGTERM kill signal and restarted.
    • stop - If this is set to true, evaluation of the rules under this perform chain will stop.

Example Config

{
  "coffee": {
    "command": ["coffee", "-wo", "__CWD__/app", "__CWD__/src"],
    "logOut":  "cof",
    "logErr":  "cof-ERR",
    "perform": [
      {
        "on":      "starting on line|Parse error",
        "stop":    true
      }, {
        "on":      "/public/",
        "kill":    {"node": "SIGUSR2"},
        "stop":    true
      }, {
        "on":      "/shared.coffee",
        "kill":    {"node": "SIGUSR2"},
        "restart": ["node"],
        "stop":    true
      }, {
        "on":      "",
        "restart": ["node"]
      }
    ]
  },
  "compass": {
    "command":      ["compass", "watch"],
    "spawnOptions": {"cwd": "__CWD__/public"},
    "logOut":       "cps",
    "logErr":       "cps-ERR",
    "perform":      [
      {
        "on":   "overwrite|identical",
        "kill": {"node": "SIGUSR2"}
      }
    ]
  },
  "redis": {
    "command": ["redis-server"],
    "logOut":  "red",
    "logErr":  "red-ERR",
    "hide":    [
      "connected.+bytes in use",
      "keys.+volatile.+slots"
    ]
  },
  "node": {
    "command": ["node", "__CWD__/app/app.js"],
    "logOut":  "app",
    "logErr":  "app-ERR",
    "deps":    ["coffee", "compass", "redis"]
  }
}
npm loves you