appnexus/sicksync

View on GitHub
src/util.js

Summary

Maintainability
A
0 mins
Test Coverage
import _ from 'lodash';
import fs from 'fs-extra';
import { exec, spawn } from 'child_process';
import anymatch from 'anymatch';
import chalk from 'chalk';
import path from 'path';
import untildify from 'untildify';
import gitignore from 'parse-gitignore';
import constants from '../conf/constants';
import text from '../conf/text';

// Returns the path to the sicksync dir
export function getSicksyncDir() {
  return untildify(constants.SICKSYNC_DIR);
}

// Return the path to the update json
export function getUpdatePath() {
  return getSicksyncDir() + '/' + constants.UPDATE_FILE;
}

// Returns the path the the config file
export function getConfigPath() {
  return getSicksyncDir() + '/' + constants.CONFIG_FILE;
}

// Returns the config object if it exists, if not an empty object. Loads/saves from cache where possible
// TODO: `existsSync` is going to be deprecated soon...
export function getConfig() {
  const configPath = getConfigPath();
  let config = {};

  if (fs.existsSync(configPath)) {
    config = require(configPath);
  }

  // Return a cloned copy of config to avoid indirect changes
  return _.cloneDeep(config);
}

// Randomly generate a unique ID
export function getId() {
  return Math.random().toString(36).substr(2, 9) + Date.now();
}

// Write out the config file with a provided <obj>
export function writeConfig(configFile) {
  const configPath = getConfigPath();

  fs.outputFileSync(configPath, JSON.stringify(configFile, null, 4));
  console.info(text.CONFIG_SAVED);
}

// Given a file path, check to see if it's in the excludes array
export function isExcluded(filepath, excludes) {
  return anymatch(excludes, filepath);
}

// Log messages with Hostname prepended
export function generateLog(projectName, hostname) {
  const args = _.slice(arguments);

  // If only one argument it's the hostname
  if (args.length === 1) {
    projectName = null;
    hostname = args[0];
  }

  return function log() {
    const args = [
      projectName ? chalk.blue('[' + projectName + ']') : '',
      hostname ? chalk.green('[' + hostname + ']') : '',
    ].concat([].slice.call(arguments));

    console.info.apply(console, args);
  };
}

//
// Rebounce
//
// Takes a desired function, a fallback function, the number of times
// called, and a cool down. Returns a `rebounced` function.
//
// The basic idea is that we want to limit calls to function to a
// certain # of times in a given time-frame. If it breaks over that,
// then we fallback to another function, and halt previous desired calls
export function rebounce(primaryFn, secondaryFn, fallOverAmount, coolDown) {
  const timeOutIds = [];
  let timesCalled = 0;
  let fallbackCalled = false;

  return function rebounced() {
    const args = arguments;
    timesCalled++;

    timeOutIds.push(setTimeout(function() {
      timesCalled = 0;
      primaryFn.apply(null, args);
    }, coolDown));

    if (timesCalled >= fallOverAmount) {
      timeOutIds.forEach(clearTimeout);

      /* istanbul ignore else */
      if (!fallbackCalled) {
        timesCalled = 0;
        fallbackCalled = true;
        secondaryFn.apply(null, arguments);
        setTimeout(function() {
          fallbackCalled = false;
        }, coolDown);
      }
    }
  };
}

export function ensureTrailingSlash(path) {
  return (path.substring(path.length - 1) === '/') ? path : path + '/';
}

export function open(parameter) {
  return exec('open ' + parameter);
}

export function toBoolean(param) {
  const lowerParam = param.toLowerCase();

  if (lowerParam.indexOf('y') > -1) {
    return true;
  }

  if (lowerParam.indexOf('n') > -1) {
    return false;
  }

  if (lowerParam === 'true' || lowerParam === 'false') {
    return JSON.parse(lowerParam);
  }

  return false;
}

export function setupPrompter(prompt) {
  prompt.message = '';
  prompt.delimiter = '';
  prompt.start();

  return prompt;
}

export function shellIntoRemote(remote) {
  return spawn('ssh', [
    '-tt',
    remote,
  ]);
}

export function printLogo() {
  console.info(chalk.blue(fs.readFileSync(path.resolve(__dirname, '../conf/logo.txt')).toString()));
}

export function uniqInstance(tokenPath, Constructor) {
  const instances = {};

  return function(args) {
    const token = _.get(args, tokenPath, null);

    if (_.get(instances, token, null)) {
      return instances[token];
    }

    if (!_.isNull(token)) {
      instances[token] = new Constructor(args);
      return instances[token];
    }

    return new Constructor(args);
  };
}

export function getProjectFromCwd(config) {
  return _.chain(config.projects)
    .filter((project) => {
      return _.isEqual(
        ensureTrailingSlash(untildify(project.sourceLocation)),
        ensureTrailingSlash(process.cwd())
      );
    })
    .value();
}

export function getProjectsFromConfig(config, projects) {
  let foundProjects = [];

  if (_.isEmpty(projects)) {
    const cwdProject = getProjectFromCwd(config);

    if (cwdProject) {
      foundProjects = cwdProject;
    }
  }

  _.each(projects, (project) => {
    const projectConf = _.find(config.projects, { project });

    if (!_.isEmpty(projectConf)) {
      foundProjects.push(projectConf);
    }
  });

  return foundProjects;
}

export function processExcludes({ excludes = [], excludesFile = [] } = {}) {
  return _.concat(excludes, _.chain(excludesFile)
      .map(untildify)
      .map(gitignore)
      .flatten()
      .value()
    );
}