<commit_before>/**
 * @fileoverview Prevent common casing typos
 */
'use strict';

const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

const STATIC_CLASS_PROPERTIES = ['propTypes', 'contextTypes', 'childContextTypes', 'defaultProps'];
const LIFECYCLE_METHODS = [
  'componentWillMount',
  'componentDidMount',
  'componentWillReceiveProps',
  'shouldComponentUpdate',
  'componentWillUpdate',
  'componentDidUpdate',
  'componentWillUnmount',
  'render'
];

const PROP_TYPES = Object.keys(require('prop-types'));

module.exports = {
  meta: {
    docs: {
      description: 'Prevent common typos',
      category: 'Stylistic Issues',
      recommended: false,
      url: docsUrl('no-typos')
    },
    schema: []
  },

  create: Components.detect((context, components, utils) => {
    let propTypesPackageName = null;
    let reactPackageName = null;

    function checkValidPropTypeQualfier(node) {
      if (node.name !== 'isRequired') {
        context.report({
          node: node,
          message: `Typo in prop type chain qualifier: ${node.name}`
        });
      }
    }

    function checkValidPropType(node) {
      if (node.name && !PROP_TYPES.some(propTypeName => propTypeName === node.name)) {
        context.report({
          node: node,
          message: `Typo in declared prop type: ${node.name}`
        });
      }
    }

    function isPropTypesPackage(node) {
      return (
        node.type === 'Identifier' &&
        node.name === propTypesPackageName
      ) || (
        node.type === 'MemberExpression' &&
        node.property.name === 'PropTypes' &&
        node.object.name === reactPackageName
      );
    }

    /* eslint-disable no-use-before-define */

    function checkValidCallExpression(node) {
      const callee = node.callee;
      if (callee.type === 'MemberExpression' && callee.property.name === 'shape') {
        checkValidPropObject(node.arguments[0]);
      } else if (callee.type === 'MemberExpression' && callee.property.name === 'oneOfType') {
        const args = node.arguments[0];
        if (args && args.type === 'ArrayExpression') {
          args.elements.forEach(el => {
            checkValidProp(el);
          });
        }
      }
    }

    function checkValidProp(node) {
      if ((!propTypesPackageName && !reactPackageName) || !node) {
        return;
      }

      if (node.type === 'MemberExpression') {
        if (
          node.object.type === 'MemberExpression' &&
          isPropTypesPackage(node.object.object)
        ) { // PropTypes.myProp.isRequired
          checkValidPropType(node.object.property);
          checkValidPropTypeQualfier(node.property);
        } else if (
          isPropTypesPackage(node.object) &&
          node.property.name !== 'isRequired'
        ) { // PropTypes.myProp
          checkValidPropType(node.property);
        } else if (node.object.type === 'CallExpression') {
          checkValidPropTypeQualfier(node.property);
          checkValidCallExpression(node.object);
        }
      } else if (node.type === 'CallExpression') {
        checkValidCallExpression(node);
      }
    }

    /* eslint-enable no-use-before-define */

    function checkValidPropObject (node) {
      if (node && node.type === 'ObjectExpression') {
        node.properties.forEach(prop => checkValidProp(prop.value));
      }
    }

    function reportErrorIfClassPropertyCasingTypo(node, propertyName) {
      if (propertyName === 'propTypes' || propertyName === 'contextTypes' || propertyName === 'childContextTypes') {
        const propsNode = node && node.parent && node.parent.type === 'AssignmentExpression' && node.parent.right;
        checkValidPropObject(propsNode);
      }
      STATIC_CLASS_PROPERTIES.forEach(CLASS_PROP => {
        if (propertyName && CLASS_PROP.toLowerCase() === propertyName.toLowerCase() && CLASS_PROP !== propertyName) {
          context.report({
            node: node,
            message: 'Typo in static class property declaration'
          });
        }
      });
    }

    function reportErrorIfLifecycleMethodCasingTypo(node) {
      LIFECYCLE_METHODS.forEach(method => {
        if (method.toLowerCase() === node.key.name.toLowerCase() && method !== node.key.name) {
          context.report({
            node: node,
            message: 'Typo in component lifecycle method declaration'
          });
        }
      });
    }

    return {
      ImportDeclaration: function(node) {
        if (node.source && node.source.value === 'prop-types') { // import PropType from "prop-types"
          propTypesPackageName = node.specifiers[0].local.name;
        } else if (node.source && node.source.value === 'react') { // import { PropTypes } from "react"
          reactPackageName = node.specifiers[0].local.name;

          propTypesPackageName = node.specifiers.length >= 1 ? (
            node.specifiers
              .filter(specifier => specifier.imported && specifier.imported.name === 'PropTypes')
              .map(specifier => specifier.local.name)
          )[0] : null;
        }
      },

      ClassProperty: function(node) {
        if (!node.static || !utils.isES6Component(node.parent.parent)) {
          return;
        }

        const tokens = context.getFirstTokens(node, 2);
        const propertyName = tokens[1].value;
        reportErrorIfClassPropertyCasingTypo(node, propertyName);
      },

      MemberExpression: function(node) {
        const propertyName = node.property.name;

        if (
          !propertyName ||
          STATIC_CLASS_PROPERTIES.map(prop => prop.toLocaleLowerCase()).indexOf(propertyName.toLowerCase()) === -1
        ) {
          return;
        }

        const relatedComponent = utils.getRelatedComponent(node);

        if (
          relatedComponent &&
          (utils.isES6Component(relatedComponent.node) || utils.isReturningJSX(relatedComponent.node))
        ) {
          reportErrorIfClassPropertyCasingTypo(node, propertyName);
        }
      },

      MethodDefinition: function (node) {
        if (!utils.isES6Component(node.parent.parent)) {
          return;
        }

        reportErrorIfLifecycleMethodCasingTypo(node);
      }
    };
  })
};
<commit_msg>Use find instead of filter<commit_after>/**
 * @fileoverview Prevent common casing typos
 */
'use strict';

const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

const STATIC_CLASS_PROPERTIES = ['propTypes', 'contextTypes', 'childContextTypes', 'defaultProps'];
const LIFECYCLE_METHODS = [
  'componentWillMount',
  'componentDidMount',
  'componentWillReceiveProps',
  'shouldComponentUpdate',
  'componentWillUpdate',
  'componentDidUpdate',
  'componentWillUnmount',
  'render'
];

const PROP_TYPES = Object.keys(require('prop-types'));

module.exports = {
  meta: {
    docs: {
      description: 'Prevent common typos',
      category: 'Stylistic Issues',
      recommended: false,
      url: docsUrl('no-typos')
    },
    schema: []
  },

  create: Components.detect((context, components, utils) => {
    let propTypesPackageName = null;
    let reactPackageName = null;

    function checkValidPropTypeQualfier(node) {
      if (node.name !== 'isRequired') {
        context.report({
          node: node,
          message: `Typo in prop type chain qualifier: ${node.name}`
        });
      }
    }

    function checkValidPropType(node) {
      if (node.name && !PROP_TYPES.some(propTypeName => propTypeName === node.name)) {
        context.report({
          node: node,
          message: `Typo in declared prop type: ${node.name}`
        });
      }
    }

    function isPropTypesPackage(node) {
      return (
        node.type === 'Identifier' &&
        node.name === propTypesPackageName
      ) || (
        node.type === 'MemberExpression' &&
        node.property.name === 'PropTypes' &&
        node.object.name === reactPackageName
      );
    }

    /* eslint-disable no-use-before-define */

    function checkValidCallExpression(node) {
      const callee = node.callee;
      if (callee.type === 'MemberExpression' && callee.property.name === 'shape') {
        checkValidPropObject(node.arguments[0]);
      } else if (callee.type === 'MemberExpression' && callee.property.name === 'oneOfType') {
        const args = node.arguments[0];
        if (args && args.type === 'ArrayExpression') {
          args.elements.forEach(el => {
            checkValidProp(el);
          });
        }
      }
    }

    function checkValidProp(node) {
      if ((!propTypesPackageName && !reactPackageName) || !node) {
        return;
      }

      if (node.type === 'MemberExpression') {
        if (
          node.object.type === 'MemberExpression' &&
          isPropTypesPackage(node.object.object)
        ) { // PropTypes.myProp.isRequired
          checkValidPropType(node.object.property);
          checkValidPropTypeQualfier(node.property);
        } else if (
          isPropTypesPackage(node.object) &&
          node.property.name !== 'isRequired'
        ) { // PropTypes.myProp
          checkValidPropType(node.property);
        } else if (node.object.type === 'CallExpression') {
          checkValidPropTypeQualfier(node.property);
          checkValidCallExpression(node.object);
        }
      } else if (node.type === 'CallExpression') {
        checkValidCallExpression(node);
      }
    }

    /* eslint-enable no-use-before-define */

    function checkValidPropObject (node) {
      if (node && node.type === 'ObjectExpression') {
        node.properties.forEach(prop => checkValidProp(prop.value));
      }
    }

    function reportErrorIfClassPropertyCasingTypo(node, propertyName) {
      if (propertyName === 'propTypes' || propertyName === 'contextTypes' || propertyName === 'childContextTypes') {
        const propsNode = node && node.parent && node.parent.type === 'AssignmentExpression' && node.parent.right;
        checkValidPropObject(propsNode);
      }
      STATIC_CLASS_PROPERTIES.forEach(CLASS_PROP => {
        if (propertyName && CLASS_PROP.toLowerCase() === propertyName.toLowerCase() && CLASS_PROP !== propertyName) {
          context.report({
            node: node,
            message: 'Typo in static class property declaration'
          });
        }
      });
    }

    function reportErrorIfLifecycleMethodCasingTypo(node) {
      LIFECYCLE_METHODS.forEach(method => {
        if (method.toLowerCase() === node.key.name.toLowerCase() && method !== node.key.name) {
          context.report({
            node: node,
            message: 'Typo in component lifecycle method declaration'
          });
        }
      });
    }

    return {
      ImportDeclaration: function(node) {
        if (node.source && node.source.value === 'prop-types') { // import PropType from "prop-types"
          propTypesPackageName = node.specifiers[0].local.name;
        } else if (node.source && node.source.value === 'react') { // import { PropTypes } from "react"
          reactPackageName = node.specifiers[0].local.name;

          if (node.specifiers.length >= 1) {
            const propTypesSpecifier = node.specifiers.find(specifier => (
              specifier.imported && specifier.imported.name === 'PropTypes'
            ));
            if (propTypesSpecifier) {
              propTypesPackageName = propTypesSpecifier.local.name;
            }
          }
        }
      },

      ClassProperty: function(node) {
        if (!node.static || !utils.isES6Component(node.parent.parent)) {
          return;
        }

        const tokens = context.getFirstTokens(node, 2);
        const propertyName = tokens[1].value;
        reportErrorIfClassPropertyCasingTypo(node, propertyName);
      },

      MemberExpression: function(node) {
        const propertyName = node.property.name;

        if (
          !propertyName ||
          STATIC_CLASS_PROPERTIES.map(prop => prop.toLocaleLowerCase()).indexOf(propertyName.toLowerCase()) === -1
        ) {
          return;
        }

        const relatedComponent = utils.getRelatedComponent(node);

        if (
          relatedComponent &&
          (utils.isES6Component(relatedComponent.node) || utils.isReturningJSX(relatedComponent.node))
        ) {
          reportErrorIfClassPropertyCasingTypo(node, propertyName);
        }
      },

      MethodDefinition: function (node) {
        if (!utils.isES6Component(node.parent.parent)) {
          return;
        }

        reportErrorIfLifecycleMethodCasingTypo(node);
      }
    };
  })
};
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var fs = require('fs');
var path = require('path');
var Buffer = require('buffer').Buffer;
var log = require('util/log');
var misc = require('util/misc');
var async = require('extern/async');
var jspack = require('extern/jspack/jspack').jspack;

var RUNSV_TEMPLATE = {
  run: "#!/bin/bash\n# Stub run file\nexit 0",
  finish: "#!/bin/bash\n# Stubbed out finish file\nexit 0;",
  down: "# Down file so it doesn't start up automagically",
  log: {
    "run": "#!/bin/bash\necho 'start'",
    "finish": "#!/bin/bash\necho 'finish'"
  }
};

/**
 * RunitService represents a runit service control directory (as passed to
 * runsv).  These are lazily constructed, so its possible that a RunitService's
 * doesn't corresponding directory doesn't actually exist, and you won't know
 * until you attempt to read the details, etc.
 *
 * @param {String} basedir  The directory in which the service resides
 * @param {String} name     The name of the service, corresponds to the name of
 *                            the service's control directory.
 */
function RunitService(basedir, name) {
  this.availpath = path.join(basedir, 'available', name);
  this.enablepath = path.join(basedir, 'enabled', name);
  this.name = name;
}

/**
 * Retrieves the details of a service. Potential errors and the details object
 * are passed to a required callback
 *
 * @param {Function} callback A required callback taking (err, details).
 */
RunitService.prototype.get_details = function(cb) {
  var self = this;
  var details = {};
  var down_path = path.join(this.availpath, "down");
  path.exists(down_path, function(exists) {
    details.name = self.name;
    details.normally = exists? "down": "up";
    self.is_enabled(function(enabled) {
      details.enabled = enabled;
      if (enabled) {
        self.get_status(function(err, sstatus) {
          // If we were unable to retrieve the status, set the status to false
          // TODO: discuss this
          details.status = err? false: sstatus;
          return cb(null, details);
        });
      }
      else {
        return cb(null, details);
      }
    });
  });
};

/**
 * Checks whether a service is enabled by looking for it in the avaiable
 * directory.
 *
 * @param {Function} callback A callback that takes a possible error and a
 *                            boolean for whether the service is enabled.
 */
RunitService.prototype.is_enabled = function(cb) {
  path.exists(this.enablepath, cb);
};

/**
 * Get status information about a service
 *
 * @param {Function} callback A callback that takes a possible error and
 *                            a status object.
 */
RunitService.prototype.get_status = function(callback) {
  var sstatus = {};
  var sstatus_path = path.join(this.availpath, "supervise", "status");
  fs.open(sstatus_path, "r", 0644, function(err, fd) {
    if (err) {
      return callback(err, sstatus);
    }
    /**
     * The 'status' file binary format is:
     *   Start time is stored as:
     *     Seconds in a uint64_t in indices 0 - 7
     *     Nanoseconds in an unsigned long in indices 8 - 11
     *   PID packed in indices 12 - 15
     *   Paused is 0|1 at index 16
     *   Want is u|d at index 17
     *   TERM is 0|1 at index 18
     *   State is (0|1|2) = (down|run|finish) at index 19
     */
    var buf = new Buffer(20);
    fs.read(fd, buf, 0, buf.length, null, function(err, bytesRead) {
      if (err) {
        return callback(err, sstatus);
      }
      var time = jspack.Unpack('>L', buf, 4)[0];
      var pid = jspack.Unpack('<L', buf, 12)[0];
      var paused = buf[16];
      var want = buf[17];
      var term = buf[18];
      var state = buf[19];
      sstatus.time = jspack.Unpack('>L>L', buf, 0)[1];
      sstatus.pid = (pid !== 0)? pid: -1;
      sstatus.paused = paused? true: false;
      sstatus.want = {
        'u': "up",
        'd': "down"
      }[want];
      sstatus.term = term? true:false;
      sstatus.state = {
        0: "down",
        1: "run",
        2: "finish"
      }[state];
      return callback(err, sstatus);
    });
  });
};

/**
 * Pipe characters into the runsv control pipe to control the service. For a
 * list of available control characters and their corresponding signals, see
 * the runsv man page.
 *
 * @param {String} cchar The control character to write to the pipe.
 * @param {Function} cb A callback called with a possible error
 */
RunitService.prototype.control = function(cchar, cb) {
  this.is_enabled(function(err, enabled) {
    if (!enabled) {
      return cb(new Error("Service disabled"));
    }
    var cpath = path.join(this.availpath, 'supervise', 'control');
    fs.open(cpath, 'a', function(err, fd) {
      if (err) {
        return cb(new Error('Control file not yet created'));
      }
      fs.write(fd, cchar, 'ascii', function(err, writen) {
        return cb(err);
      });
    });
  });
};

/**
 * Restart the service. The callback fires when the control characters have
 * been written, without regard to what actually happens to the service. This
 * sends a TERM followed by a CONT, then has runsv start the service and set it
 * to up.
 *
 * @param {Function} cb A callback called with a possible error
 */
RunitService.prototype.restart = function(cb) {
  this.control('tcu', cb);
};

/**
 * Start the service and set it to "up".
 *
 * @param {Function} cb A callback called with a possible error
 */
RunitService.prototype.start = function(cb) {
  this.control('u', cb);
};

/**
 * Stop the service and set it to "down".
 *
 * @param {Function} cb A callback called with a possible error
 */
RunitService.prototype.stop = function(cb) {
  this.control('d', cb);
};

/**
 * Enable a service by symlinking to it from the enabled directory
 *
 * @param {Function} cb A callback with a possible error
 */
RunitService.prototype.enable = function(cb) {
  var self = this;
  self.is_enabled(function(enabled) {
    if (!enabled) {
      var target;
      if (self.availpath[0] === '/') {
        target = self.availpath;
      }
      else {
        target = path.join(process.cwd(), self.availpath);
      }
      fs.symlink(target, self.enablepath, cb);
    }
    return cb();
  });
};

/**
 * Disable a service by removing the symlink to it from the enabled directory
 *
 * @param {Function} cb A callback with a possible error
 */
RunitService.prototype.disable = function(cb) {
  var self = this;
  self.is_enabled(function(enabled) {
    if (enabled) {
      fs.unlink(self.enablepath, cb);
    }
    return cb();
  });
};

/**
 * RunitServiceDirectory represents a runit services directory as passed to
 * 'runsvdir'. This is lazily constructed, so the success of this constructor
 * does not necessarily indicate that the directory exists or contains any
 * services.
 *
 * @param {String} dir  The path to the services directory
 */
function RunitServiceDirectory(dir) {
  this.dir = dir;
  this.availdir = path.join(dir, 'available');
  this.enabldir = path.join(dir, 'enabled');
}

/**
 * Retrieve a service within the service directory by name. This takes a
 * required callback which will receive a possible error and the RunitService
 * object (which may not represent a valid service, see {@link RunitService}).
 *
 * @param {Function} cb A callback taking an error and a {@link RunitService}
 */
RunitServiceDirectory.prototype.get_service = function(name, callback) {
  var self = this;
  fs.stat(path.join(self.availdir, name), function(err, stats) {
    if (err) {
      return callback(err);
    }
    return callback(null, new RunitService(self.dir, name));
  });
};

/**
 * Retrieve a list of objects containing details for all valid services in the
 * service directory.
 *
 * @param {Function} cb A callback taking an error a list of retrieved details
 */
RunitServiceDirectory.prototype.list_services_details = function(cb) {
  var self = this;
  var services = [];

  fs.readdir(self.availdir, function(err, files) {
    // If the services directory can't be read, just return error now
    if (err) {
      return cb(err);
    }

    async.forEach(files, function(file, callback) {
      self.get_service(file, function(err, service) {
        if (err) {
          return callback(err);
        }
        service.get_details(function(err, details) {
          if (!err) {
            services.push(details);
          }
          return callback(err);
        });
      });
    },
    function(err) {
      cb(err, services);
    });
  });
};

/**
 * Create a RunitService layout with the given name. This is incomplete.
 *
 * @param {Function} cb A callback taking a possible error.
 */
RunitServiceDirectory.prototype.create_service_layout = function(name, cb) {
  var self = this;
  var svcpath = path.join(self.availdir, name);
  fs.stat(svcpath, function(err, stats) {
    if (!err) {
      cb(new Error("Service name already in use"));
    }
    else {
      misc.template_to_tree(svcpath, RUNSV_TEMPLATE, cb);
    }
  });
};

exports.RunitServiceDirectory = RunitServiceDirectory;
<commit_msg>More runit bug fixes<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var fs = require('fs');
var path = require('path');
var Buffer = require('buffer').Buffer;
var log = require('util/log');
var misc = require('util/misc');
var async = require('extern/async');
var jspack = require('extern/jspack/jspack').jspack;

var RUNSV_TEMPLATE = {
  run: "#!/bin/bash\n# Stub run file\nexit 0",
  finish: "#!/bin/bash\n# Stubbed out finish file\nexit 0;",
  down: "# Down file so it doesn't start up automagically",
  log: {
    "run": "#!/bin/bash\necho 'start'",
    "finish": "#!/bin/bash\necho 'finish'"
  }
};

/**
 * RunitService represents a runit service control directory (as passed to
 * runsv).  These are lazily constructed, so its possible that a RunitService's
 * doesn't corresponding directory doesn't actually exist, and you won't know
 * until you attempt to read the details, etc.
 *
 * @param {String} basedir  The directory in which the service resides
 * @param {String} name     The name of the service, corresponds to the name of
 *                            the service's control directory.
 */
function RunitService(basedir, name) {
  this.availpath = path.join(basedir, 'available', name);
  this.enablepath = path.join(basedir, 'enabled', name);
  this.name = name;
}

/**
 * Retrieves the details of a service. Potential errors and the details object
 * are passed to a required callback
 *
 * @param {Function} callback A required callback taking (err, details).
 */
RunitService.prototype.get_details = function(cb) {
  var self = this;
  var details = {};
  var down_path = path.join(this.availpath, "down");
  path.exists(down_path, function(exists) {
    details.name = self.name;
    details.normally = exists? "down": "up";
    self.is_enabled(function(enabled) {
      details.enabled = enabled;
      if (enabled) {
        self.get_status(function(err, sstatus) {
          // If we were unable to retrieve the status, set the status to false
          // TODO: discuss this
          details.status = err? false: sstatus;
          return cb(null, details);
        });
      }
      else {
        return cb(null, details);
      }
    });
  });
};

/**
 * Checks whether a service is enabled by looking for it in the avaiable
 * directory.
 *
 * @param {Function} callback A callback that takes a boolean
 */
RunitService.prototype.is_enabled = function(cb) {
  path.exists(this.enablepath, cb);
};

/**
 * Get status information about a service
 *
 * @param {Function} callback A callback that takes a possible error and
 *                            a status object.
 */
RunitService.prototype.get_status = function(callback) {
  var sstatus = {};
  var sstatus_path = path.join(this.availpath, "supervise", "status");
  fs.open(sstatus_path, "r", 0644, function(err, fd) {
    if (err) {
      return callback(err, sstatus);
    }
    /**
     * The 'status' file binary format is:
     *   Start time is stored as:
     *     Seconds in a uint64_t in indices 0 - 7
     *     Nanoseconds in an unsigned long in indices 8 - 11
     *   PID packed in indices 12 - 15
     *   Paused is 0|1 at index 16
     *   Want is u|d at index 17
     *   TERM is 0|1 at index 18
     *   State is (0|1|2) = (down|run|finish) at index 19
     */
    var buf = new Buffer(20);
    fs.read(fd, buf, 0, buf.length, null, function(err, bytesRead) {
      if (err) {
        return callback(err, sstatus);
      }
      var time = jspack.Unpack('>L', buf, 4)[0];
      var pid = jspack.Unpack('<L', buf, 12)[0];
      var paused = buf[16];
      var want = buf[17];
      var term = buf[18];
      var state = buf[19];
      sstatus.time = jspack.Unpack('>L>L', buf, 0)[1];
      sstatus.pid = (pid !== 0)? pid: -1;
      sstatus.paused = paused? true: false;
      sstatus.want = {
        'u': "up",
        'd': "down"
      }[want];
      sstatus.term = term? true:false;
      sstatus.state = {
        0: "down",
        1: "run",
        2: "finish"
      }[state];
      return callback(err, sstatus);
    });
  });
};

/**
 * Pipe characters into the runsv control pipe to control the service. For a
 * list of available control characters and their corresponding signals, see
 * the runsv man page.
 *
 * @param {String} cchar The control character to write to the pipe.
 * @param {Function} cb A callback called with a possible error
 */
RunitService.prototype.control = function(cchar, cb) {
  var self = this;
  this.is_enabled(function(enabled) {
    if (!enabled) {
      return cb(new Error("Service disabled"));
    }
    var cpath = path.join(self.availpath, 'supervise', 'control');
    // Node's syntax is a little annoying on this, we have to specify a mode
    // in order to provide a callback
    fs.open(cpath, process.O_WRONLY, 0700, function(err, fd) {
      if (err) {
        //return cb(new Error('Control file not yet created'));
        return cb(err);
      }
      var buf = new Buffer(cchar, 'ascii');
      fs.write(fd, buf, 0, buf.length, null, function(err, writen) {
        return cb(err);
      });
    });
  });
};

/**
 * Restart the service. The callback fires when the control characters have
 * been written, without regard to what actually happens to the service. This
 * sends a TERM followed by a CONT, then has runsv start the service and set it
 * to up.
 *
 * @param {Function} cb A callback called with a possible error
 */
RunitService.prototype.restart = function(cb) {
  this.control('tcu', cb);
};

/**
 * Start the service and set it to "up".
 *
 * @param {Function} cb A callback called with a possible error
 */
RunitService.prototype.start = function(cb) {
  this.control('u', cb);
};

/**
 * Stop the service and set it to "down".
 *
 * @param {Function} cb A callback called with a possible error
 */
RunitService.prototype.stop = function(cb) {
  this.control('d', cb);
};

/**
 * Enable a service by symlinking to it from the enabled directory
 *
 * @param {Function} cb A callback with a possible error
 */
RunitService.prototype.enable = function(cb) {
  var self = this;
  self.is_enabled(function(enabled) {
    if (!enabled) {
      var target;
      if (self.availpath[0] === '/') {
        target = self.availpath;
      }
      else {
        target = path.join(process.cwd(), self.availpath);
      }
      fs.symlink(target, self.enablepath, cb);
    }
    return cb();
  });
};

/**
 * Disable a service by removing the symlink to it from the enabled directory
 *
 * @param {Function} cb A callback with a possible error
 */
RunitService.prototype.disable = function(cb) {
  var self = this;
  self.is_enabled(function(enabled) {
    if (enabled) {
      fs.unlink(self.enablepath, cb);
    }
    return cb();
  });
};

/**
 * RunitServiceDirectory represents a runit services directory as passed to
 * 'runsvdir'. This is lazily constructed, so the success of this constructor
 * does not necessarily indicate that the directory exists or contains any
 * services.
 *
 * @param {String} dir  The path to the services directory
 */
function RunitServiceDirectory(dir) {
  this.dir = dir;
  this.availdir = path.join(dir, 'available');
  this.enabldir = path.join(dir, 'enabled');
}

/**
 * Retrieve a service within the service directory by name. This takes a
 * required callback which will receive a possible error and the RunitService
 * object (which may not represent a valid service, see {@link RunitService}).
 *
 * @param {Function} cb A callback taking an error and a {@link RunitService}
 */
RunitServiceDirectory.prototype.get_service = function(name, callback) {
  var self = this;
  fs.stat(path.join(self.availdir, name), function(err, stats) {
    if (err) {
      return callback(err);
    }
    return callback(null, new RunitService(self.dir, name));
  });
};

/**
 * Retrieve a list of objects containing details for all valid services in the
 * service directory.
 *
 * @param {Function} cb A callback taking an error a list of retrieved details
 */
RunitServiceDirectory.prototype.list_services_details = function(cb) {
  var self = this;
  var services = [];

  fs.readdir(self.availdir, function(err, files) {
    // If the services directory can't be read, just return error now
    if (err) {
      return cb(err);
    }

    async.forEach(files, function(file, callback) {
      self.get_service(file, function(err, service) {
        if (err) {
          return callback(err);
        }
        service.get_details(function(err, details) {
          if (!err) {
            services.push(details);
          }
          return callback(err);
        });
      });
    },
    function(err) {
      cb(err, services);
    });
  });
};

/**
 * Create a RunitService layout with the given name. This is incomplete.
 *
 * @param {Function} cb A callback taking a possible error.
 */
RunitServiceDirectory.prototype.create_service_layout = function(name, cb) {
  var self = this;
  var svcpath = path.join(self.availdir, name);
  fs.stat(svcpath, function(err, stats) {
    if (!err) {
      cb(new Error("Service name already in use"));
    }
    else {
      misc.template_to_tree(svcpath, RUNSV_TEMPLATE, cb);
    }
  });
};

exports.RunitServiceDirectory = RunitServiceDirectory;
<|endoftext|>


<commit_before>/**
 * @fileoverview This file contains the module that is required to enable specialised timers that have better control
 * on a global level.
 *
 * @todo - the architecture of this sucks even if this "works".
 *       - the way to compute firing of start and end events suck
 *       - basically this needs a redo with more "engineering" put into it
 */
var /**
     *
     * @constant {String}
     */
    FUNCTION = 'function',

    /**
     * The set of timer function names. We use this array to define common behaviour of all setters and clearer timer
     * functions
     * @constant {Array.<String>}
     */
    timerFunctionNames = ['Timeout', 'Interval', 'Immediate', 'Event'],

    /**
     * This object defines a set of timer function names that are trigerred a number of times instead of a single time.
     * Such timers, when placed in generic rules, needs special attention.
     * @constant {Array.<Boolean>}
     */
    multiFireTimerFunctions = {
        'Interval': true
    },

    /**
     * This object defines a set of function timer names that do not fire based on any pre-set duration or interval.
     * Such timers, when placed in generic rules, needs special attention.
     * @constant {Array.<Boolean>}
     */
    staticTimerFunctions = {
        'Event': true
    },

    /**
     * A local copy of Slice function of Array
     * @constant {Function}
     */
    arrayProtoSlice = Array.prototype.slice,

    /**
     * This object holds the current global timers
     * @extends Timers
     */
    defaultTimers = timerFunctionNames.reduce(function (timers, name) {
        // get hold of default timer functions as available in global scope
        var fnset = (new Function('return (typeof set' + name + // eslint-disable-line no-new-func
                ' === "function" ? set' + name + ' : undefined);'))(),
            fnclr = (new Function('return (typeof clear' + name + // eslint-disable-line no-new-func
                ' === "function" ? clear' + name + ' : undefined);'))();

        if (typeof fnset === FUNCTION) {
            timers[('set' + name)] = fnset;
        }

        if (typeof fnclr === FUNCTION) {
            timers[('clear' + name)] = fnclr;
        }

        return timers;
    }, {}),

    Timerz; // main exports constructor

/**
 * @constructor
 *
 * @param {Object} [delegations]
 * @param {Function} [onError]
 * @param {Function} [onAnyTimerStart]
 * @param {Function} [onAllTimerEnd]
 */
Timerz = function Timerz (delegations, onError, onAnyTimerStart, onAllTimerEnd) {
    var /**
         * Holds the present timers, either delegated or defaults
         * @extends Timers
         */
        timers = delegations || defaultTimers,
        dummyContext = {},

        total = 0, // accumulator to keep track of total timers
        pending = 0, // counters to keep track of running timers
        sealed = false, // flag that stops all new timer additions
        wentAsync = false,
        computeTimerEvents;

    // do special handling to enable emulation of immediate timers in hosts that lacks them
    if (typeof timers.setImmediate !== FUNCTION) {
        timers.setImmediate = function (callback) {
            return timers.setTimeout(callback, 0);
        };
        timers.clearImmediate = function (id) {
            return timers.clearTimeout(id);
        };
    }

    // write special handlers for event based timers if the delegations don't contain one
    (typeof timers.setEvent !== FUNCTION) && (function () {
        var events = {},
            total = 0;

        timers.setEvent = function (callback) {
            var id = ++total;
            events[id] = callback;
            return id;
        };

        timers.clearEvent = function (id) {
            var cb = events[id];
            delete events[id];
            (typeof cb === FUNCTION) && cb.apply(dummyContext, arrayProtoSlice.call(arguments, 1));
        };

        timers.clearAllEvents = function () {
            Object.keys(events).forEach(function (prop) {
                delete events[prop];
            });
        };
    }());

    // create a function that decides whether to fire appropriate callbacks
    computeTimerEvents = function (increment, clearing) {
        increment && (pending += increment);

        if (pending === 0 && computeTimerEvents.started) {
            !clearing && (typeof onAllTimerEnd === FUNCTION) && onAllTimerEnd();
            computeTimerEvents.started = false;
            return;
        }

        if (pending > 0 && !computeTimerEvents.started) {
            !clearing && (typeof onAnyTimerStart === FUNCTION) && onAnyTimerStart();
            computeTimerEvents.started = true;
        }
    };

    // iterate through the timer variants and create common setter and clearer function behaviours for each of them.
    timerFunctionNames.forEach(function (name) {
        // create an accumulator for all timer references
        var running = {};

        // create the setter function for the timer
        this[('set' + name)] = function (callback) {
            // it is pointless to proceed with setter if there is no callback to execute
            if (sealed || typeof callback !== FUNCTION) {
                return;
            }

            var id = ++total, // get hold of the next timer id
                args = arrayProtoSlice.call(arguments);

            args[0] = function () {
                wentAsync = true; // mark that we did go async once. this will ensure we do not pass erroneous events

                // call the actual callback with a dummy context
                try { callback.apply(dummyContext, staticTimerFunctions[name] ? arguments : null); }
                catch (e) { onError && onError(e); }

                // interval timers can only be cleared using clearXYZ function and hence we need not do anything
                // except call the timer
                if (staticTimerFunctions[name] || multiFireTimerFunctions[name]) {
                    // do not modify counter during interval type events
                    computeTimerEvents();
                }
                // when this is fired, the timer dies, so we decrement tracking counters and delete
                // irq references
                else {
                    computeTimerEvents(-1);
                    delete running[id];
                }
            };

            // for static timers
            staticTimerFunctions[name] && (wentAsync = true);

            // call the underlying timer function and keep a track of its irq
            running[id] = timers[('set' + name)].apply(this, args);
            args = null; // precaution

            // increment the counter and return the tracking ID to be used to pass on to clearXYZ function
            computeTimerEvents(1);
            return id;
        };

        // create the clear function of the timer
        this[('clear' + name)] = function (id) {
            var underLyingId = running[id],
                args;

            // it is pointless and erroenous to proceed in case it seems that it is no longer running
            if (sealed || !underLyingId) {
                return;
            }

            // prepare args to be forwarded to clear function
            args = arrayProtoSlice.call(arguments);
            args[0] = underLyingId;
            delete running[id];

            // fire the underlying clearing function

            try { timers['clear' + name].apply(dummyContext, args); }
            catch (e) { onError(e); }

            // decrement counters and call the clearing timer function
            computeTimerEvents(-1, !wentAsync);

            args = underLyingId = null; // just a precaution
        };

        // create a sugar function to clear all running timers of this category
        // @todo: decide how to handle clearing for underlying delegated timers, if they are instances of Timerz itself.
        if (typeof timers[('clearAll' + name + 's')] === FUNCTION) {
            // if native timers have a function to clear all timers, then use it
            this[('clearAll' + name + 's')] = function () {
                timers[('clearAll' + name + 's')]();
                Object.keys(running).forEach(function () {
                    computeTimerEvents(-1, true);
                });
            };
        }
        else {
            this[('clearAll' + name + 's')] = function () {
                Object.keys(running).forEach(function (id) {
                    computeTimerEvents(-1, true);
                    // run clear functions except for static timers
                    timers['clear' + name](running[id]);
                });
            };
        }

    }.bind(this));

    /**
     * @memberof Timerz.prototype
     * @returns {Number}
     */
    this.queueLength = function () {
        return pending;
    };

    /**
     * @memberof Timerz.prototype
     */
    this.clearAll = function () {
        // call all internal timer clearAll function variants
        timerFunctionNames.forEach(function (name) {
            this[('clearAll' + name + 's')]();
        }.bind(this));
    };

    /**
     * @memberof Timerz.prototype
     */
    this.seal = function () {
        sealed = true;
    };

    this.error = function (err) {
        return onError.call(dummyContext, err);
    };

    this.terminate = function () {
        this.seal();
        this.clearAll();
        return onAllTimerEnd.apply(dummyContext, arguments);
    };
};

module.exports = Timerz;
<commit_msg>Wrap timers function in a anonymous function<commit_after>/**
 * @fileoverview This file contains the module that is required to enable specialised timers that have better control
 * on a global level.
 *
 * @todo - the architecture of this sucks even if this "works".
 *       - the way to compute firing of start and end events suck
 *       - basically this needs a redo with more "engineering" put into it
 */
var /**
     *
     * @constant {String}
     */
    FUNCTION = 'function',

    /**
     * The set of timer function names. We use this array to define common behaviour of all setters and clearer timer
     * functions
     * @constant {Array.<String>}
     */
    timerFunctionNames = ['Timeout', 'Interval', 'Immediate', 'Event'],

    /**
     * This object defines a set of timer function names that are trigerred a number of times instead of a single time.
     * Such timers, when placed in generic rules, needs special attention.
     * @constant {Array.<Boolean>}
     */
    multiFireTimerFunctions = {
        'Interval': true
    },

    /**
     * This object defines a set of function timer names that do not fire based on any pre-set duration or interval.
     * Such timers, when placed in generic rules, needs special attention.
     * @constant {Array.<Boolean>}
     */
    staticTimerFunctions = {
        'Event': true
    },

    /**
     * A local copy of Slice function of Array
     * @constant {Function}
     */
    arrayProtoSlice = Array.prototype.slice,

    /**
     * This object holds the current global timers
     * @extends Timers
     */
    defaultTimers = timerFunctionNames.reduce(function (timers, name) {
        // get hold of default timer functions as available in global scope
        var fnset = (new Function(`return typeof set${name} === 'function' ?` + // eslint-disable-line no-new-func
                `function (fn, ms) { return set${name}(fn, ms); } : undefined;`))(),
            fnclr = (new Function(`return typeof clear${name} === 'function' ?` + // eslint-disable-line no-new-func
                `function (id) { return clear${name}(id); } : undefined;`))();

        if (typeof fnset === FUNCTION) {
            timers[('set' + name)] = fnset;
        }

        if (typeof fnclr === FUNCTION) {
            timers[('clear' + name)] = fnclr;
        }

        return timers;
    }, {}),

    Timerz; // main exports constructor

/**
 * @constructor
 *
 * @param {Object} [delegations]
 * @param {Function} [onError]
 * @param {Function} [onAnyTimerStart]
 * @param {Function} [onAllTimerEnd]
 */
Timerz = function Timerz (delegations, onError, onAnyTimerStart, onAllTimerEnd) {
    var /**
         * Holds the present timers, either delegated or defaults
         * @extends Timers
         */
        timers = delegations || defaultTimers,
        dummyContext = {},

        total = 0, // accumulator to keep track of total timers
        pending = 0, // counters to keep track of running timers
        sealed = false, // flag that stops all new timer additions
        wentAsync = false,
        computeTimerEvents;

    // do special handling to enable emulation of immediate timers in hosts that lacks them
    if (typeof timers.setImmediate !== FUNCTION) {
        timers.setImmediate = function (callback) {
            return timers.setTimeout(callback, 0);
        };
        timers.clearImmediate = function (id) {
            return timers.clearTimeout(id);
        };
    }

    // write special handlers for event based timers if the delegations don't contain one
    (typeof timers.setEvent !== FUNCTION) && (function () {
        var events = {},
            total = 0;

        timers.setEvent = function (callback) {
            var id = ++total;
            events[id] = callback;
            return id;
        };

        timers.clearEvent = function (id) {
            var cb = events[id];
            delete events[id];
            (typeof cb === FUNCTION) && cb.apply(dummyContext, arrayProtoSlice.call(arguments, 1));
        };

        timers.clearAllEvents = function () {
            Object.keys(events).forEach(function (prop) {
                delete events[prop];
            });
        };
    }());

    // create a function that decides whether to fire appropriate callbacks
    computeTimerEvents = function (increment, clearing) {
        increment && (pending += increment);

        if (pending === 0 && computeTimerEvents.started) {
            !clearing && (typeof onAllTimerEnd === FUNCTION) && onAllTimerEnd();
            computeTimerEvents.started = false;
            return;
        }

        if (pending > 0 && !computeTimerEvents.started) {
            !clearing && (typeof onAnyTimerStart === FUNCTION) && onAnyTimerStart();
            computeTimerEvents.started = true;
        }
    };

    // iterate through the timer variants and create common setter and clearer function behaviours for each of them.
    timerFunctionNames.forEach(function (name) {
        // create an accumulator for all timer references
        var running = {};

        // create the setter function for the timer
        this[('set' + name)] = function (callback) {
            // it is pointless to proceed with setter if there is no callback to execute
            if (sealed || typeof callback !== FUNCTION) {
                return;
            }

            var id = ++total, // get hold of the next timer id
                args = arrayProtoSlice.call(arguments);

            args[0] = function () {
                wentAsync = true; // mark that we did go async once. this will ensure we do not pass erroneous events

                // call the actual callback with a dummy context
                try { callback.apply(dummyContext, staticTimerFunctions[name] ? arguments : null); }
                catch (e) { onError && onError(e); }

                // interval timers can only be cleared using clearXYZ function and hence we need not do anything
                // except call the timer
                if (staticTimerFunctions[name] || multiFireTimerFunctions[name]) {
                    // do not modify counter during interval type events
                    computeTimerEvents();
                }
                // when this is fired, the timer dies, so we decrement tracking counters and delete
                // irq references
                else {
                    computeTimerEvents(-1);
                    delete running[id];
                }
            };

            // for static timers
            staticTimerFunctions[name] && (wentAsync = true);

            // call the underlying timer function and keep a track of its irq
            running[id] = timers[('set' + name)].apply(this, args);
            args = null; // precaution

            // increment the counter and return the tracking ID to be used to pass on to clearXYZ function
            computeTimerEvents(1);
            return id;
        };

        // create the clear function of the timer
        this[('clear' + name)] = function (id) {
            var underLyingId = running[id],
                args;

            // it is pointless and erroenous to proceed in case it seems that it is no longer running
            if (sealed || !underLyingId) {
                return;
            }

            // prepare args to be forwarded to clear function
            args = arrayProtoSlice.call(arguments);
            args[0] = underLyingId;
            delete running[id];

            // fire the underlying clearing function

            try { timers['clear' + name].apply(dummyContext, args); }
            catch (e) { onError(e); }

            // decrement counters and call the clearing timer function
            computeTimerEvents(-1, !wentAsync);

            args = underLyingId = null; // just a precaution
        };

        // create a sugar function to clear all running timers of this category
        // @todo: decide how to handle clearing for underlying delegated timers, if they are instances of Timerz itself.
        if (typeof timers[('clearAll' + name + 's')] === FUNCTION) {
            // if native timers have a function to clear all timers, then use it
            this[('clearAll' + name + 's')] = function () {
                timers[('clearAll' + name + 's')]();
                Object.keys(running).forEach(function () {
                    computeTimerEvents(-1, true);
                });
            };
        }
        else {
            this[('clearAll' + name + 's')] = function () {
                Object.keys(running).forEach(function (id) {
                    computeTimerEvents(-1, true);
                    // run clear functions except for static timers
                    timers['clear' + name](running[id]);
                });
            };
        }

    }.bind(this));

    /**
     * @memberof Timerz.prototype
     * @returns {Number}
     */
    this.queueLength = function () {
        return pending;
    };

    /**
     * @memberof Timerz.prototype
     */
    this.clearAll = function () {
        // call all internal timer clearAll function variants
        timerFunctionNames.forEach(function (name) {
            this[('clearAll' + name + 's')]();
        }.bind(this));
    };

    /**
     * @memberof Timerz.prototype
     */
    this.seal = function () {
        sealed = true;
    };

    this.error = function (err) {
        return onError.call(dummyContext, err);
    };

    this.terminate = function () {
        this.seal();
        this.clearAll();
        return onAllTimerEnd.apply(dummyContext, arguments);
    };
};

module.exports = Timerz;
<|endoftext|>


<commit_before>var path = require('path');
var generators = require('yeoman-generator');

describe('sails-diy:hook', function(){
  describe('Should properly scaffold without arguments and options', function(){
    before(function(done){
      generators.test.run(path.join(__dirname, '../../src/hook')).on('end', done)
    });

    it('Should properly create api files', function() {
      generators.assert.file([
        'api/hooks/CountHook.js',
        'api/hooks/PluralizeHook.js'
      ]);

      generators.assert.noFile([
        'api/hooks/TestHook.js'
      ]);

      generators.assert.fileContent('api/hooks/CountHook.js', /sails.on\('router:before'/);
      generators.assert.fileContent('api/hooks/PluralizeHook.js', /sails.on\('router:before'/);
    });

    it('Should properly create test files', function(){
      generators.assert.file([
        'test/unit/hooks/CountHook.test.js',
        'test/unit/hooks/PluralizeHook.test.js'
      ]);

      generators.assert.noFile([
        'test/unit/hooks/TestHook.test.js'
      ]);
    });
  });

  describe('Should properly scaffold predefined hook', function(){
    before(function(done){
      generators.test
        .run(path.join(__dirname, '../../src/hook'))
        .withArguments(['pluralize'])
        .on('end', done)
    });

    it('Should properly create api files', function(){
      generators.assert.file([
        'api/hooks/PluralizeHook.js'
      ]);

      generators.assert.noFile([
        'api/hooks/CountHook.js'
      ]);

      generators.assert.fileContent('api/hooks/PluralizeHook.js', /sails.on\('router:before'/);
    });

    it('Should properly create test files', function(){
      generators.assert.file([
        'test/unit/hooks/PluralizeHook.test.js'
      ]);

      generators.assert.noFile([
        'test/unit/hooks/CountHook.test.js'
      ]);
    });
  });

  describe('Should properly scaffold overridden predefined hook', function(){
    before(function(done){
      generators.test
        .run(path.join(__dirname, '../../src/hook'))
        .withArguments(['pluralize'])
        .withOptions({
          'new': true
        })
        .on('end', done)
    });

    it('Should properly create api files', function(){
      generators.assert.file([
        'api/hooks/PluralizeHook.js'
      ]);

      generators.assert.noFile([
        'api/hooks/CountHook.js'
      ]);

      generators.assert.fileContent('api/hooks/PluralizeHook.js', /initialize: function initialize\(cb\)/);
      generators.assert.noFileContent('api/hooks/PluralizeHook.js', /sails.on\('router:before'/);
    });

    it('Should properly create test files', function(){
      generators.assert.file([
        'test/unit/hooks/PluralizeHook.test.js'
      ]);

      generators.assert.noFile([
        'test/unit/hooks/CountHook.test.js'
      ]);
    });
  });

  describe('Should properly scaffold all predefined hooks at once', function(){
    before(function(done){
      generators.test
        .run(path.join(__dirname, '../../src/hook'))
        .withOptions({
          'all': true
        })
        .on('end', done)
    });

    it('Should properly create api files', function(){
      generators.assert.file([
        'api/hooks/CountHook.js',
        'api/hooks/PluralizeHook.js'
      ]);

      generators.assert.noFile([
        'api/hooks/TestHook.js'
      ]);

      generators.assert.fileContent('api/hooks/CountHook.js', /sails.on\('router:before'/);
      generators.assert.fileContent('api/hooks/PluralizeHook.js', /sails.on\('router:before'/);
    });

    it('Should properly create test files', function(){
      generators.assert.file([
        'test/unit/hooks/CountHook.test.js',
        'test/unit/hooks/PluralizeHook.test.js'
      ]);

      generators.assert.noFile([
        'test/unit/hooks/TestHook.test.js'
      ]);
    });
  });

  describe('Should properly scaffold custom hook', function(){
    before(function(done){
      generators.test
        .run(path.join(__dirname, '../../src/hook'))
        .withArguments(['test'])
        .on('end', done)
    });

    it('Should properly create api files', function(){
      generators.assert.file([
        'api/hooks/TestHook.js'
      ]);

      generators.assert.noFile([
        'api/hooks/CountHook.js',
        'api/hooks/PluralizeHook.js'
      ]);

      generators.assert.fileContent('api/hooks/TestHook.js', /initialize: function initialize\(cb\)/);
    });

    it('Should properly create test files', function(){
      generators.assert.file([
        'test/unit/hooks/TestHook.test.js'
      ]);

      generators.assert.noFile([
        'test/unit/hooks/CountHook.test.js',
        'test/unit/hooks/PluralizeHook.test.js'
      ]);
    });
  });
});
<commit_msg>modify hook test<commit_after>var path = require('path');
var generators = require('yeoman-generator');

describe('sails-diy:hook', function(){
  describe('Should properly scaffold without arguments and options', function(){
    before(function(done){
      generators.test.run(path.join(__dirname, '../../src/hook')).on('end', done)
    });

    it('Should properly create api files', function() {
      //generators.assert.file([
      //  'api/hooks/CountHook.js',
      //  'api/hooks/PluralizeHook.js'
      //]);

      generators.assert.noFile([
        'api/hooks/TestHook.js'
      ]);

      //generators.assert.fileContent('api/hooks/CountHook.js', /sails.on\('router:before'/);
      //generators.assert.fileContent('api/hooks/PluralizeHook.js', /sails.on\('router:before'/);
    });

    it('Should properly create test files', function(){
      //generators.assert.file([
      //  'test/unit/hooks/CountHook.test.js',
      //  'test/unit/hooks/PluralizeHook.test.js'
      //]);

      generators.assert.noFile([
        'test/unit/hooks/TestHook.test.js'
      ]);
    });
  });

  //describe('Should properly scaffold predefined hook', function(){
  //  before(function(done){
  //    generators.test
  //      .run(path.join(__dirname, '../../src/hook'))
  //      .withArguments(['pluralize'])
  //      .on('end', done)
  //  });
  //
  //  it('Should properly create api files', function(){
  //    generators.assert.file([
  //      'api/hooks/PluralizeHook.js'
  //    ]);
  //
  //    generators.assert.noFile([
  //      'api/hooks/CountHook.js'
  //    ]);
  //
  //    generators.assert.fileContent('api/hooks/PluralizeHook.js', /sails.on\('router:before'/);
  //  });
  //
  //  it('Should properly create test files', function(){
  //    generators.assert.file([
  //      'test/unit/hooks/PluralizeHook.test.js'
  //    ]);
  //
  //    generators.assert.noFile([
  //      'test/unit/hooks/CountHook.test.js'
  //    ]);
  //  });
  //});

  describe('Should properly scaffold overridden predefined hook', function(){
    before(function(done){
      generators.test
        .run(path.join(__dirname, '../../src/hook'))
        .withArguments(['pluralize'])
        .withOptions({
          'new': true
        })
        .on('end', done)
    });

    it('Should properly create api files', function(){
      generators.assert.file([
        'api/hooks/PluralizeHook.js'
      ]);

      generators.assert.noFile([
        'api/hooks/CountHook.js'
      ]);

      generators.assert.fileContent('api/hooks/PluralizeHook.js', /initialize: function initialize\(cb\)/);
      generators.assert.noFileContent('api/hooks/PluralizeHook.js', /sails.on\('router:before'/);
    });

    it('Should properly create test files', function(){
      generators.assert.file([
        'test/unit/hooks/PluralizeHook.test.js'
      ]);

      generators.assert.noFile([
        'test/unit/hooks/CountHook.test.js'
      ]);
    });
  });

  //describe('Should properly scaffold all predefined hooks at once', function(){
  //  before(function(done){
  //    generators.test
  //      .run(path.join(__dirname, '../../src/hook'))
  //      .withOptions({
  //        'all': true
  //      })
  //      .on('end', done)
  //  });
  //
  //  it('Should properly create api files', function(){
  //    generators.assert.file([
  //      'api/hooks/CountHook.js',
  //      'api/hooks/PluralizeHook.js'
  //    ]);
  //
  //    generators.assert.noFile([
  //      'api/hooks/TestHook.js'
  //    ]);
  //
  //    generators.assert.fileContent('api/hooks/CountHook.js', /sails.on\('router:before'/);
  //    generators.assert.fileContent('api/hooks/PluralizeHook.js', /sails.on\('router:before'/);
  //  });
  //
  //  it('Should properly create test files', function(){
  //    generators.assert.file([
  //      'test/unit/hooks/CountHook.test.js',
  //      'test/unit/hooks/PluralizeHook.test.js'
  //    ]);
  //
  //    generators.assert.noFile([
  //      'test/unit/hooks/TestHook.test.js'
  //    ]);
  //  });
  //});

  describe('Should properly scaffold custom hook', function(){
    before(function(done){
      generators.test
        .run(path.join(__dirname, '../../src/hook'))
        .withArguments(['test'])
        .on('end', done)
    });

    it('Should properly create api files', function(){
      generators.assert.file([
        'api/hooks/TestHook.js'
      ]);

      generators.assert.noFile([
        'api/hooks/CountHook.js',
        'api/hooks/PluralizeHook.js'
      ]);

      generators.assert.fileContent('api/hooks/TestHook.js', /initialize: function initialize\(cb\)/);
    });

    it('Should properly create test files', function(){
      generators.assert.file([
        'test/unit/hooks/TestHook.test.js'
      ]);

      generators.assert.noFile([
        'test/unit/hooks/CountHook.test.js',
        'test/unit/hooks/PluralizeHook.test.js'
      ]);
    });
  });
});
<|endoftext|>


<commit_before>module.exports = function() {
  var parser = {
        encoding: parser_encoding,
        push: parser_push,
        pop: parser_pop
      },
      buffer,
      bufferOffset = 0,
      bufferLength = 0,
      encoding = "utf8",
      fragments = null;

  function parser_encoding(newEncoding) {
    if (arguments.length) {
      if (buffer != null) throw new Error("cannot change encoding after pushing data");
      if (newEncoding == null) newEncoding = null;
      else if (!Buffer.isEncoding(newEncoding = newEncoding + "")) throw new Error("unknown encoding: " + newEncoding);
      encoding = newEncoding;
      return parser;
    }
    return encoding;
  }

  function parser_push(data) {
    if (bufferOffset < bufferLength) throw new Error("cannot push before all lines are popped");
    bufferLength = data.length;
    bufferOffset = 0;
    buffer = data;
  }

  function parser_pop(allowPartial) {
    var oldBufferOffset = bufferOffset,
        terminatorLength = 0;

    // Find the next line terminator.
    while (bufferOffset < bufferLength) {
      var character = buffer[bufferOffset++];
      if (character === 10) { // \n
        ++terminatorLength;
        break;
      }
      if (character === 13) { // \r or \r\n
        ++terminatorLength;
        if (buffer[bufferOffset] === 10) ++bufferOffset, ++terminatorLength;
        break;
      }
    }

    // Slice the buffer up to the line terminator.
    var fragment = buffer.slice(oldBufferOffset, bufferOffset - terminatorLength);

    // If we read to the end of a line, return it!
    if (terminatorLength || allowPartial) {

      // Combine this with previously-read line fragments, if any.
      if (fragments) {
        fragments.push(fragment);
        fragment = Buffer.concat(fragments);
        fragments = null;
      }

      // If this is the last line in a file not terminated with a new line,
      // then return the line even though there’s no trailing terminator.
      return !allowPartial || fragment.length ? fragment.toString(encoding) : null;
    }

    // Otherwise, we’ve read part of a line. Copy the fragment so that the
    // source buffer can be modified without changing the fragment contents.
    var fragmentCopy = new Buffer(fragment.length);
    fragment.copy(fragmentCopy);
    if (fragments) fragments.push(fragmentCopy);
    else fragments = [fragmentCopy];
    return null;
  }

  return parser;
};
<commit_msg>Rename for clarity.<commit_after>module.exports = function() {
  var parser = {
        encoding: parser_encoding,
        push: parser_push,
        pop: parser_pop
      },
      buffer,
      bufferOffset = 0,
      bufferLength = 0,
      encoding = "utf8",
      fragments = null;

  function parser_encoding(newEncoding) {
    if (arguments.length) {
      if (buffer != null) throw new Error("cannot change encoding after pushing data");
      if (newEncoding == null) newEncoding = null;
      else if (!Buffer.isEncoding(newEncoding = newEncoding + "")) throw new Error("unknown encoding: " + newEncoding);
      encoding = newEncoding;
      return parser;
    }
    return encoding;
  }

  function parser_push(data) {
    if (bufferOffset < bufferLength) throw new Error("cannot push before all lines are popped");
    bufferLength = data.length;
    bufferOffset = 0;
    buffer = data;
  }

  function parser_pop(allowPartial) {
    var oldBufferOffset = bufferOffset,
        terminatorLength = 0;

    // Find the next line terminator.
    while (bufferOffset < bufferLength) {
      var code = buffer[bufferOffset++];
      if (code === CODE_LINE_FEED) {
        ++terminatorLength;
        break;
      }
      if (code === CODE_CARRIAGE_RETURN) {
        ++terminatorLength;
        if (buffer[bufferOffset] === CODE_LINE_FEED) ++bufferOffset, ++terminatorLength;
        break;
      }
    }

    // Slice the buffer up to the line terminator.
    var fragment = buffer.slice(oldBufferOffset, bufferOffset - terminatorLength);

    // If we read to the end of a line, return it!
    if (terminatorLength || allowPartial) {

      // Combine this with previously-read line fragments, if any.
      if (fragments) {
        fragments.push(fragment);
        fragment = Buffer.concat(fragments);
        fragments = null;
      }

      // If this is the last line in a file not terminated with a new line,
      // then return the line even though there’s no trailing terminator.
      return !allowPartial || fragment.length ? fragment.toString(encoding) : null;
    }

    // Otherwise, we’ve read part of a line. Copy the fragment so that the
    // source buffer can be modified without changing the fragment contents.
    var fragmentCopy = new Buffer(fragment.length);
    fragment.copy(fragmentCopy);
    if (fragments) fragments.push(fragmentCopy);
    else fragments = [fragmentCopy];
    return null;
  }

  return parser;
};

var CODE_LINE_FEED = 10,
    CODE_CARRIAGE_RETURN = 13;
<|endoftext|>


<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2014, Joyent, Inc.
 */

/*
 * Unit tests for the firewall rule object
 */

var test = require('tape');
var mod_rule = require('../../lib/rule');
var mod_uuid = require('node-uuid');
var util = require('util');
var util_ip = require('../../lib/util/ip');

/*
 * Skeleton app object, needed by Rule objects for internal logic
 */
var app = {
    config: {
        fwrule_version: 1
    }
}

// --- Helper functions

function subnetNumber(subnet) {
    var split = subnet.split('/');
    return util_ip.aton(split[0]) + '/' + split[1];
}

function rawTag(key, val) {
    if (val === undefined) {
        return util.format('%s==%d', key, key.length);
    } else {
        return util.format('%s=%s=%d', key, val, key.length);
    }
}

// --- Tests

test('all target types', function (t) {
    var ips = ['192.168.1.1', '10.2.0.3'];
    var vms = ['9a343ca8-b42a-4a27-a9c5-800f57d1e8ed',
        '518908b6-8299-466d-8ea5-20a0ceff63ec'];
    var tags = ['tag1', 'tag2'];
    var subnets = ['192.168.2.0/24', '10.2.1.0/24'];

    var inRule = {
        rule: util.format('FROM (ip %s OR subnet %s OR tag %s OR vm %s) ',
            ips[0], subnets[0], tags[0], vms[0])
            + util.format('TO (ip %s OR subnet %s OR tag %s OR vm %s)',
            ips[1], subnets[1], tags[1], vms[1])
            + ' ALLOW tcp (PORT 80 AND PORT 81)',
        enabled: true,
        global: true
    };

    var rule = mod_rule.create(inRule, app);
    var raw = {
        fromip: [util_ip.aton(ips[0])],
        fromsubnet: [subnetNumber(subnets[0])],
        fromtag: [ rawTag(tags[0]) ],
        fromvm: [vms[0]],

        toip: [util_ip.aton(ips[1])],
        tosubnet: [subnetNumber(subnets[1])],
        totag: [ rawTag(tags[1]) ],
        tovm: [vms[1]],

        enabled: true,
        objectclass: mod_rule.objectclass,
        ports: [ 80, 81 ],
        action: 'allow',
        protocol: 'tcp',
        uuid: rule.uuid,
        version: rule.version
    };

    inRule.uuid = rule.uuid;
    inRule.version = rule.version;

    t.deepEqual(rule.raw(), raw, 'rule.raw()');
    t.deepEqual(rule.serialize(), inRule, 'rule.serialize()');
    t.equal(rule.dn, util.format('uuid=%s, ou=fwrules, o=smartdc', rule.uuid),
        'rule.dn');

    // Now recreate the rule from the raw UFDS data
    var rule2 = mod_rule.create(rule.raw(), app);
    t.deepEqual(rule2.raw(), raw, 'rule2.raw()');
    t.deepEqual(rule2.serialize(), inRule, 'rule2.serialize()');
    t.equal(rule2.dn, util.format('uuid=%s, ou=fwrules, o=smartdc', rule.uuid),
        'rule2.dn');

    t.end();
});

test('owner_uuid', function (t) {
    var ip = '10.2.0.3';
    var vm = '9a343ca8-b42a-4a27-a9c5-800f57d1e8ed';

    var inRule = {
        rule: util.format('FROM ip %s TO vm %s ALLOW tcp PORT 25', ip, vm),
        owner_uuid: mod_uuid.v4(),
        enabled: true
    };

    var rule = mod_rule.create(inRule, app);
    var raw = {
        fromip: [ util_ip.aton(ip) ],
        tovm: [ vm ],
        enabled: true,
        objectclass: mod_rule.objectclass,
        owner: inRule.owner_uuid,
        ports: [ 25 ],
        action: 'allow',
        protocol: 'tcp',
        uuid: rule.uuid,
        version: rule.version
    };

    inRule.uuid = rule.uuid;
    inRule.version = rule.version;

    t.deepEqual(rule.raw(), raw, 'rule.raw()');
    t.deepEqual(rule.serialize(), inRule, 'rule.serialize()');
    t.equal(rule.dn, util.format('uuid=%s, ou=fwrules, o=smartdc', rule.uuid),
        'rule.dn');

    // Now recreate the rule from the raw UFDS data
    var rule2 = mod_rule.create(rule.raw(), app);
    t.deepEqual(rule2.raw(), raw, 'rule2.raw()');
    t.deepEqual(rule2.serialize(), inRule, 'rule2.serialize()');
    t.equal(rule2.dn, util.format('uuid=%s, ou=fwrules, o=smartdc', rule.uuid),
        'rule2.dn');

    t.end();
});

test('multiple tags with multiple quoted values', function (t) {
    var owner = mod_uuid.v4();
    var rule = mod_rule.create({
        rule: 'FROM (tag "김치" = "백김치" OR '
            + 'tag "김치" = "白김치") TO '
            + '(tag "some tag" = value OR '
            + 'tag some-tag = "another value") ALLOW tcp PORT 80',
        owner_uuid: owner
    }, app);

    var raw = {
        enabled: false,
        objectclass: mod_rule.objectclass,
        ports: [ 80 ],
        action: 'allow',
        owner: owner,
        protocol: 'tcp',
        fromtag: [ rawTag('김치', '白김치'),
            rawTag('김치', '백김치') ],
        totag: [ rawTag('some tag', 'value'),
            rawTag('some-tag', 'another value') ],
        uuid: rule.uuid,
        version: rule.version
    };
    t.deepEqual(rule.raw(), raw, 'rule.raw()');

    var serialized = {
        enabled: false,
        owner_uuid: owner,
        rule: 'FROM (tag "김치" = "白김치" '
            + 'OR tag "김치" = "백김치") TO '
            + '(tag "some tag" = value OR tag some-tag = "another value") '
            + 'ALLOW tcp PORT 80',
        uuid: rule.uuid,
        version: rule.version
    };
    t.deepEqual(rule.serialize(), serialized, 'rule.serialize()');

    t.ok(!rule.allVMs, 'rule.allVMs');

    var ruleTags = [
            [ 'some tag', 'value' ],
            [ 'some-tag', 'another value' ],
            [ '김치', '白김치' ],
            [ '김치', '백김치' ]
    ];
    t.deepEqual(rule.tags, ruleTags, 'rule.tags');

    // Now check that we can reconstruct this data from UFDS
    rule = mod_rule.create(raw, app);
    t.deepEqual(rule.raw(), raw, 'rule.raw()');
    t.deepEqual(rule.raw(), raw, 'rule.raw()');
    t.ok(!rule.allVMs, 'rule.allVMs');
    t.deepEqual(rule.tags, ruleTags, 'rule.tags');

    t.end();
});

test('global', function (t) {
    var caught = false;
    var rule;

    try {
        rule = new mod_rule.Rule({
            rule: 'FROM any TO tag foo=bar BLOCK udp PORT 54',
            owner_uuid: mod_uuid.v4(),
            global: true
        });
    } catch (pErr) {
        caught = true;
    }

    t.ok(caught, 'Error thrown');
    t.ok(!rule, 'No rule');
    t.end();
});
<commit_msg>FWAPI-230 Unit tests were broken by FWAPI-197 (make check)<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2014, Joyent, Inc.
 */

/*
 * Unit tests for the firewall rule object
 */

var test = require('tape');
var mod_rule = require('../../lib/rule');
var mod_uuid = require('node-uuid');
var util = require('util');
var util_ip = require('../../lib/util/ip');

/*
 * Skeleton app object, needed by Rule objects for internal logic
 */
var app = {
    config: {
        fwrule_version: 1
    }
};

// --- Helper functions

function subnetNumber(subnet) {
    var split = subnet.split('/');
    return util_ip.aton(split[0]) + '/' + split[1];
}

function rawTag(key, val) {
    if (val === undefined) {
        return util.format('%s==%d', key, key.length);
    } else {
        return util.format('%s=%s=%d', key, val, key.length);
    }
}

// --- Tests

test('all target types', function (t) {
    var ips = ['192.168.1.1', '10.2.0.3'];
    var vms = ['9a343ca8-b42a-4a27-a9c5-800f57d1e8ed',
        '518908b6-8299-466d-8ea5-20a0ceff63ec'];
    var tags = ['tag1', 'tag2'];
    var subnets = ['192.168.2.0/24', '10.2.1.0/24'];

    var inRule = {
        rule: util.format('FROM (ip %s OR subnet %s OR tag %s OR vm %s) ',
            ips[0], subnets[0], tags[0], vms[0])
            + util.format('TO (ip %s OR subnet %s OR tag %s OR vm %s)',
            ips[1], subnets[1], tags[1], vms[1])
            + ' ALLOW tcp (PORT 80 AND PORT 81)',
        enabled: true,
        global: true
    };

    var rule = mod_rule.create(inRule, app);
    var raw = {
        fromip: [util_ip.aton(ips[0])],
        fromsubnet: [subnetNumber(subnets[0])],
        fromtag: [ rawTag(tags[0]) ],
        fromvm: [vms[0]],

        toip: [util_ip.aton(ips[1])],
        tosubnet: [subnetNumber(subnets[1])],
        totag: [ rawTag(tags[1]) ],
        tovm: [vms[1]],

        enabled: true,
        objectclass: mod_rule.objectclass,
        ports: [ 80, 81 ],
        action: 'allow',
        protocol: 'tcp',
        uuid: rule.uuid,
        version: rule.version
    };

    inRule.uuid = rule.uuid;
    inRule.version = rule.version;

    t.deepEqual(rule.raw(), raw, 'rule.raw()');
    t.deepEqual(rule.serialize(), inRule, 'rule.serialize()');
    t.equal(rule.dn, util.format('uuid=%s, ou=fwrules, o=smartdc', rule.uuid),
        'rule.dn');

    // Now recreate the rule from the raw UFDS data
    var rule2 = mod_rule.create(rule.raw(), app);
    t.deepEqual(rule2.raw(), raw, 'rule2.raw()');
    t.deepEqual(rule2.serialize(), inRule, 'rule2.serialize()');
    t.equal(rule2.dn, util.format('uuid=%s, ou=fwrules, o=smartdc', rule.uuid),
        'rule2.dn');

    t.end();
});

test('owner_uuid', function (t) {
    var ip = '10.2.0.3';
    var vm = '9a343ca8-b42a-4a27-a9c5-800f57d1e8ed';

    var inRule = {
        rule: util.format('FROM ip %s TO vm %s ALLOW tcp PORT 25', ip, vm),
        owner_uuid: mod_uuid.v4(),
        enabled: true
    };

    var rule = mod_rule.create(inRule, app);
    var raw = {
        fromip: [ util_ip.aton(ip) ],
        tovm: [ vm ],
        enabled: true,
        objectclass: mod_rule.objectclass,
        owner: inRule.owner_uuid,
        ports: [ 25 ],
        action: 'allow',
        protocol: 'tcp',
        uuid: rule.uuid,
        version: rule.version
    };

    inRule.uuid = rule.uuid;
    inRule.version = rule.version;

    t.deepEqual(rule.raw(), raw, 'rule.raw()');
    t.deepEqual(rule.serialize(), inRule, 'rule.serialize()');
    t.equal(rule.dn, util.format('uuid=%s, ou=fwrules, o=smartdc', rule.uuid),
        'rule.dn');

    // Now recreate the rule from the raw UFDS data
    var rule2 = mod_rule.create(rule.raw(), app);
    t.deepEqual(rule2.raw(), raw, 'rule2.raw()');
    t.deepEqual(rule2.serialize(), inRule, 'rule2.serialize()');
    t.equal(rule2.dn, util.format('uuid=%s, ou=fwrules, o=smartdc', rule.uuid),
        'rule2.dn');

    t.end();
});

test('multiple tags with multiple quoted values', function (t) {
    var owner = mod_uuid.v4();
    var rule = mod_rule.create({
        rule: 'FROM (tag "김치" = "백김치" OR '
            + 'tag "김치" = "白김치") TO '
            + '(tag "some tag" = value OR '
            + 'tag some-tag = "another value") ALLOW tcp PORT 80',
        owner_uuid: owner
    }, app);

    var raw = {
        enabled: false,
        objectclass: mod_rule.objectclass,
        ports: [ 80 ],
        action: 'allow',
        owner: owner,
        protocol: 'tcp',
        fromtag: [ rawTag('김치', '白김치'),
            rawTag('김치', '백김치') ],
        totag: [ rawTag('some tag', 'value'),
            rawTag('some-tag', 'another value') ],
        uuid: rule.uuid,
        version: rule.version
    };
    t.deepEqual(rule.raw(), raw, 'rule.raw()');

    var serialized = {
        enabled: false,
        owner_uuid: owner,
        rule: 'FROM (tag "김치" = "白김치" '
            + 'OR tag "김치" = "백김치") TO '
            + '(tag "some tag" = value OR tag some-tag = "another value") '
            + 'ALLOW tcp PORT 80',
        uuid: rule.uuid,
        version: rule.version
    };
    t.deepEqual(rule.serialize(), serialized, 'rule.serialize()');

    t.ok(!rule.allVMs, 'rule.allVMs');

    var ruleTags = [
            [ 'some tag', 'value' ],
            [ 'some-tag', 'another value' ],
            [ '김치', '白김치' ],
            [ '김치', '백김치' ]
    ];
    t.deepEqual(rule.tags, ruleTags, 'rule.tags');

    // Now check that we can reconstruct this data from UFDS
    rule = mod_rule.create(raw, app);
    t.deepEqual(rule.raw(), raw, 'rule.raw()');
    t.deepEqual(rule.raw(), raw, 'rule.raw()');
    t.ok(!rule.allVMs, 'rule.allVMs');
    t.deepEqual(rule.tags, ruleTags, 'rule.tags');

    t.end();
});

test('global', function (t) {
    var caught = false;
    var rule;

    try {
        rule = new mod_rule.Rule({
            rule: 'FROM any TO tag foo=bar BLOCK udp PORT 54',
            owner_uuid: mod_uuid.v4(),
            global: true
        });
    } catch (pErr) {
        caught = true;
    }

    t.ok(caught, 'Error thrown');
    t.ok(!rule, 'No rule');
    t.end();
});
<|endoftext|>


<commit_before>const schedule = require('node-schedule-tz')
const moment = require('moment-timezone')
const _ = require('lodash')
const utilities = require('./utilities.js')
const evaluation = require('./evaluation.js')
const logging = require('homeautomation-js-lib/logging.js')
const rules = require('./loading.js')
const TIMEZONE = utilities.getCurrentTimeZone()

var scheduled_jobs = []

const doSchedule = function(rule_name, jobName, date, rule, otherwise) {
    const options = rule.options
    var quiet = false

    if (!utilities.testMode()) {
        logging.info('scheduling rule: ' + rule_name + '  job: ' + jobName + '  schedule: ' + utilities.logDate(date) + ' timezone: ' + TIMEZONE + '   otherwise: ' + otherwise)
    }
    var newJob = schedule.scheduleJob(jobName, date, TIMEZONE, function() {
        if (!quiet && !utilities.testMode()) {
            logging.info('scheduled rule fired: ' + rule_name + '  job: ' + jobName + '  schedule: ' + date + ' rule: ' + JSON.stringify(rule))
            logging.debug('job fired' + 'data:' + JSON.stringify({
                action: 'scheduled-job-fired',
                schedule: date,
                job: jobName,
                rule_name: rule_name,
                rule: rule
            }))
            logging.debug('* scheduled job fired: ' + rule_name + ' (schedule: ' + utilities.logDate(date) + ')')
        }

        const scheduleAction = function(context) {
            evaluation.evalulateValue(
                null,
                context,
                rule_name,
                rule,
                true,
                otherwise,
                'scheduled rule: ' + rule_name + ' job: ' + job)
        }

        global.generateContext(null, null, function(outTopic, outMessage, context) {
            scheduleAction(context)
        })
    }.bind(null, rule))

    if (!_.isNil(newJob)) {
        if (!quiet && !utilities.testMode()) {
            logging.info(' => scheduled ' + jobName + ' - ' + utilities.logDate(date))
            logging.debug('job scheduled ' + 'data:' + JSON.stringify({
                action: 'job-scheduled',
                schedule: date,
                job: jobName,
                rule_name: rule_name,
                rule: rule

            }))
        }

        scheduled_jobs.push(newJob)
    }
}

exports.scheduleJob = function(rule_name, jobName, scheduleString, rule) {
    doSchedule(rule_name, jobName, scheduleString, rule, false)
}

exports.scheduleJobs = function() {
    logging.info('scheduling jobs ', {
        action: 'schedule-jobs'
    })

    scheduleDailyJobs()

    scheduled_jobs.forEach(function(job) {
        job.cancel()
    }, this)

    rules.ruleIterator(function(rule_name, rule) {
        const during = rule.during
        if (!_.isNil(during)) {
            var duringIndex = 0
            during.forEach(duringString => {
                const timeRange = utilities.parseTimeRange(duringString)
                if (!_.isNil(timeRange)) {
                    var jobKey = rule_name + '.during.' + duringIndex
                    duringIndex = duringIndex + 1

                    if (timeRange.start < timeRange.now) {
                        doSchedule(rule_name, jobKey + '.start', moment(timeRange.start).add(15, 'seconds').toDate(), rule, false)
                    } else {
                        doSchedule(rule_name, jobKey + '.start', moment(timeRange.start).add(100, 'ms').toDate(), rule, false)
                    }
                    doSchedule(rule_name, jobKey + '.end', moment(timeRange.end).add(100, 'ms').toDate(), rule, true)
                }
            })
        }

        const at = rule.at
        if (!_.isNil(at)) {
            var atIndex = 0
            at.forEach(atString => {
                const time = utilities.parseTime(atString)
                if (!_.isNil(time)) {
                    var jobKey = rule_name + '.at.' + atIndex
                    atIndex = atIndex + 1

                    doSchedule(rule_name, jobKey, time.toDate(), rule, false)
                }
            })
        }

        const cronString = rule.cron
        if (!_.isNil(cronString)) {
            Object.keys(cronString).forEach(function(schedule_key) {
                var jobKey = rule_name + '.cron.' + schedule_key
                const cronSchedule = cronString[schedule_key]
                logging.debug(jobKey + ' = ' + cronSchedule)

                doSchedule(rule_name, jobKey, cronSchedule, rule, false)
            })
        }
    })
}

var dailyJob = null

const scheduleDailyJobs = function() {
    if (!_.isNil(dailyJob)) {
        return
    }

    logging.info('Scheduling Daily Job (timezone: ' + TIMEZONE + ')', {
        action: 'schedule-daily-job'
    })

    dailyJob = schedule.scheduleJob('daily', '00 00 00 * * * ', TIMEZONE, function() {
        logging.info('Daily job fired ', {
            action: 'scheduled-daily-job'
        })

        // Delay this 250ms given the first set of sunset calculations seem to weirdly sometimes work from the previous day
        setTimeout(exports.scheduleJobs, 250)
    })
}<commit_msg>Fixing unused variable & bad name<commit_after>const schedule = require('node-schedule-tz')
const moment = require('moment-timezone')
const _ = require('lodash')
const utilities = require('./utilities.js')
const evaluation = require('./evaluation.js')
const logging = require('homeautomation-js-lib/logging.js')
const rules = require('./loading.js')
const TIMEZONE = utilities.getCurrentTimeZone()

var scheduled_jobs = []

const doSchedule = function(rule_name, jobName, date, rule, otherwise) {
    var quiet = false

    if (!utilities.testMode()) {
        logging.info('scheduling rule: ' + rule_name + '  job: ' + jobName + '  schedule: ' + utilities.logDate(date) + ' timezone: ' + TIMEZONE + '   otherwise: ' + otherwise)
    }
    var newJob = schedule.scheduleJob(jobName, date, TIMEZONE, function() {
        if (!quiet && !utilities.testMode()) {
            logging.info('scheduled rule fired: ' + rule_name + '  job: ' + jobName + '  schedule: ' + date + ' rule: ' + JSON.stringify(rule))
            logging.debug('job fired' + 'data:' + JSON.stringify({
                action: 'scheduled-job-fired',
                schedule: date,
                job: jobName,
                rule_name: rule_name,
                rule: rule
            }))
            logging.debug('* scheduled job fired: ' + rule_name + ' (schedule: ' + utilities.logDate(date) + ')')
        }

        const scheduleAction = function(context) {
            evaluation.evalulateValue(
                null,
                context,
                rule_name,
                rule,
                true,
                otherwise,
                'scheduled rule: ' + rule_name + ' job: ' + jobName)
        }

        global.generateContext(null, null, function(outTopic, outMessage, context) {
            scheduleAction(context)
        })
    }.bind(null, rule))

    if (!_.isNil(newJob)) {
        if (!quiet && !utilities.testMode()) {
            logging.info(' => scheduled ' + jobName + ' - ' + utilities.logDate(date))
            logging.debug('job scheduled ' + 'data:' + JSON.stringify({
                action: 'job-scheduled',
                schedule: date,
                job: jobName,
                rule_name: rule_name,
                rule: rule

            }))
        }

        scheduled_jobs.push(newJob)
    }
}

exports.scheduleJob = function(rule_name, jobName, scheduleString, rule) {
    doSchedule(rule_name, jobName, scheduleString, rule, false)
}

exports.scheduleJobs = function() {
    logging.info('scheduling jobs ', {
        action: 'schedule-jobs'
    })

    scheduleDailyJobs()

    scheduled_jobs.forEach(function(job) {
        job.cancel()
    }, this)

    rules.ruleIterator(function(rule_name, rule) {
        const during = rule.during
        if (!_.isNil(during)) {
            var duringIndex = 0
            during.forEach(duringString => {
                const timeRange = utilities.parseTimeRange(duringString)
                if (!_.isNil(timeRange)) {
                    var jobKey = rule_name + '.during.' + duringIndex
                    duringIndex = duringIndex + 1

                    if (timeRange.start < timeRange.now) {
                        doSchedule(rule_name, jobKey + '.start', moment(timeRange.start).add(15, 'seconds').toDate(), rule, false)
                    } else {
                        doSchedule(rule_name, jobKey + '.start', moment(timeRange.start).add(100, 'ms').toDate(), rule, false)
                    }
                    doSchedule(rule_name, jobKey + '.end', moment(timeRange.end).add(100, 'ms').toDate(), rule, true)
                }
            })
        }

        const at = rule.at
        if (!_.isNil(at)) {
            var atIndex = 0
            at.forEach(atString => {
                const time = utilities.parseTime(atString)
                if (!_.isNil(time)) {
                    var jobKey = rule_name + '.at.' + atIndex
                    atIndex = atIndex + 1

                    doSchedule(rule_name, jobKey, time.toDate(), rule, false)
                }
            })
        }

        const cronString = rule.cron
        if (!_.isNil(cronString)) {
            Object.keys(cronString).forEach(function(schedule_key) {
                var jobKey = rule_name + '.cron.' + schedule_key
                const cronSchedule = cronString[schedule_key]
                logging.debug(jobKey + ' = ' + cronSchedule)

                doSchedule(rule_name, jobKey, cronSchedule, rule, false)
            })
        }
    })
}

var dailyJob = null

const scheduleDailyJobs = function() {
    if (!_.isNil(dailyJob)) {
        return
    }

    logging.info('Scheduling Daily Job (timezone: ' + TIMEZONE + ')', {
        action: 'schedule-daily-job'
    })

    dailyJob = schedule.scheduleJob('daily', '00 00 00 * * * ', TIMEZONE, function() {
        logging.info('Daily job fired ', {
            action: 'scheduled-daily-job'
        })

        // Delay this 250ms given the first set of sunset calculations seem to weirdly sometimes work from the previous day
        setTimeout(exports.scheduleJobs, 250)
    })
}<|endoftext|>


<commit_before>describe('core', function() {
    it('should export as `window.gf`', function() {
        window.should.have.property('gf');
    });

    it('should export all objects', function() {
        gf.should.have.properties([
            'AudioManager',
            'AudioPlayer',

            //camera
            'Camera',

            //display
            'BaseTexture',
            'Texture',
            'Container',
            'Sprite',

            //font
            'BitmapText',

            //fx
            'fx',

            //game
            'Game',
            'State',
            'StateManager',

            //gui
            'GuiItem',

            //input
            'Input',
            'InputManager',
            'Keyboard',
            'Gamepad',
            'GamepadButtons',
            'GamepadSticks',
            'Pointers',
            'Pointer',

            //loader
            'Loader',

            //map
            'Tile',
            'Tilelayer',
            'Tilemap',
            'Tileset',
            'ObjectGroup',

            //math
            'math',
            'Circle',
            'Ellipse',
            'Polygon',
            'Rectangle',
            'Vector',

            //particles
            'ParticleEmitter',
            'ParticleSystem',

            //physics
            'PhysicsSystem',
            'PhysicsTarget',

            //utils
            'utils',
            'support',
            'inherit',
            'Cache',
            'Clock',
            'EventEmitter',
            'ObjectPool',
            'SpritePool',
            'ObjectFactory',

            //plugin
            'plugin',

            //vendor files
            'PIXI'
        ]);

        gf.fx.should.have.property('camera');
        gf.fx.camera.should.have.properties([
            'Effect',
            'Close',
            'Fade',
            'Flash',
            'Scanlines',
            'Shake'
        ]);
    });
});
<commit_msg>fix export checks<commit_after>describe('core', function() {
    it('should export as `window.gf`', function() {
        window.should.have.property('gf');
    });

    it('should export all objects', function() {
        gf.should.have.properties([
            'AudioManager',
            'AudioPlayer',

            //camera
            'Camera',

            //controls
            'Controls',
            'TopDownControls',

            //display
            'BaseTexture',
            'Container',
            'Graphics',
            'RenderTexture',
            'Sprite',
            'SpriteBatch',
            'Texture',
            'TilingSprite',

            //fx
            'fx',

            //game
            'Game',
            'State',
            'StateManager',
            'World',

            //geometry
            'Circle',
            'Ellipse',
            'Polygon',
            'Rectangle',

            //input
            'Input',
            'InputManager',
            'Keyboard',
            'Gamepad',
            'GamepadButtons',
            'GamepadSticks',
            'Pointers',
            'Pointer',

            //loader
            'Loader',

            //math
            'math',
            'Vector',

            //particles
            'ParticleEmitter',
            'ParticleSystem',

            //physics
            'PhysicsSystem',
            'PhysicsTarget',

            //text
            'BitmapText',
            'Text',

            //tilemap
            'Tile',
            'Tilelayer',
            'Tilemap',
            'Tileset',
            'ObjectGroup',

            //utils
            'utils',
            'support',
            'inherit',
            'Cache',
            'Clock',
            'Color',
            'EventEmitter',
            'ObjectPool',
            'Queue',
            'SpritePool',
            'ObjectFactory',

            //plugin
            'plugin',

            //vendor files
            'PIXI',
            'cp'
        ]);

        gf.fx.should.have.property('camera');
        gf.fx.camera.should.have.properties([
            'Effect',
            'Close',
            'Fade',
            'Flash',
            'Scanlines',
            'Shake'
        ]);

        gf.fx.should.have.property('filters');
        gf.fx.filters.should.have.properties([
            'FilterBlock', 'WebGLFilterManager', 'FilterTexture', 'AlphaMaskFilter',
            'ColorMatrixFilter', 'GrayFilter', 'DisplacementFilter', 'PixelateFilter',
            'BlurXFilter', 'BlurYFilter', 'BlurFilter', 'InvertFilter', 'SepiaFilter',
            'TwistFilter', 'ColorStepFilter', 'DotScreenFilter', 'CrossHatchFilter',
            'RGBSplitFilter'
        ]);
    });
});
<|endoftext|>