src/util.js
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()
);
}