UNPKG

fecs-git-hooks

Version:
214 lines (157 loc) 5.42 kB
/** * @file utils * @author cxtom <cxtom2010@gmail.com> */ var Path = require('path'); var Fs = require('fs'); /* eslint-disable no-console */ var internals = {}; // Expands source and target to absolute paths, then calls internals.copy exports.copy = function (source, target, options) { if (typeof target === 'object') { options = target; target = undefined; } options = options || {}; var root = Path.dirname(internals.findParent(module).filename); var projectRoot = exports.findGitRoot(root); var sourcePath = Path.resolve(root, source); var targetPath = Path.resolve(projectRoot, target || source); if (targetPath.indexOf(projectRoot) !== 0) { throw new Error('Destination must be within project root'); } return internals.copy(sourcePath, targetPath, options); }; // Install the git hook as specified by `hook`. // For example, Validate.installHook('pre-commit'); exports.installHooks = function (hooks, root) { hooks = Array.isArray(hooks) ? hooks : [hooks]; var gitRoot = exports.findGitRoot(root); var hookRoot = Path.join(gitRoot, '.git', 'hooks'); var source = Path.resolve(__dirname, '..', 'hooks', 'pre-commit'); if (!exports.isDir(hookRoot)) { internals.mkdir(hookRoot); } for (var i = 0, il = hooks.length; i < il; ++i) { var hook = hooks[i]; var dest = Path.join(hookRoot, hook); if (Fs.existsSync(dest)) { Fs.renameSync(dest, dest + '.backup'); } Fs.writeFileSync(dest, Fs.readFileSync(source), {mode: 511}); } }; exports.unInstallHooks = function (hooks, root) { hooks = Array.isArray(hooks) ? hooks : [hooks]; var gitRoot = exports.findGitRoot(root); var hookRoot = Path.join(gitRoot, '.git', 'hooks'); if (!exports.isDir(hookRoot)) { return; } for (var i = 0, il = hooks.length; i < il; ++i) { var hook = hooks[i]; var dest = Path.join(hookRoot, hook); if (Fs.existsSync(dest)) { Fs.unlinkSync(dest); if (Fs.existsSync(dest + '.backup')) { Fs.renameSync(dest + '.backup', dest); } } } }; // Given a starting directory, find the root of a git repository. // In this case, the root is defined as the first directory that contains // a directory named ".git" // // Returns a string if found, otherwise undefined exports.findGitRoot = function (start) { start = start || Path.dirname(internals.findParent(module).filename); var root; if (exports.isDir(Path.join(start, '.git'))) { root = start; } /* $lab:coverage:off$ */ // Coverage disabled here due to false positive on else if, since we have to trap the throwWarn method else if (Path.dirname(start) !== start) { root = exports.findGitRoot(Path.dirname(start)); } else { return internals.throwWarn('Unable to find a .git directory for this project'); } /* $lab:coverage:on$ */ return root; }; /* $lab:coverage:off$ */ // Coverage disabled for this method because we use a child process to test it due to the process.exit() call internals.throwWarn = function (warning) { console.error('WARNING: ' + warning + ', installation aborted.'); process.exit(0); }; /* $lab:coverage:on$ */ // Find the topmost parent of the given module. internals.findParent = function (mod) { return mod.parent ? internals.findParent(mod.parent) : mod; }; // Similar to mkdir -p, recursively creates directories until `path` exists internals.mkdir = function (path) { var mode = ~process.umask() & parseInt('777', 8); if (exports.isDir(path)) { return; } try { Fs.mkdirSync(path, mode); } catch (err) { if (err.code !== 'ENOENT') { throw err; } internals.mkdir(Path.dirname(path)); internals.mkdir(path); } }; // Determine if source is a directory or a file and call the appropriate method internals.copy = function (source, target, options) { if (exports.isDir(source)) { internals.copyDirectory(source, target, options); } else { return internals.copyFile(source, target, options); } }; // Copy a single file internals.copyFile = function (source, target, options) { internals.mkdir(Path.dirname(target)); var mode = ~process.umask() & parseInt('666', 8); if (Fs.existsSync(target) && !options.overwrite) { return new Error(target + ' already exists'); } var sourceContent = ''; try { sourceContent = Fs.readFileSync(source); } catch (e) { /* no source to copy */ } Fs.writeFileSync(target, sourceContent, {flag: 'w', mode: mode}); }; // Recursively copy a directory internals.copyDirectory = function (source, target, options) { internals.mkdir(target); var sources = Fs.readdirSync(source); for (var i = 0, l = sources.length; i < l; ++i) { var sourcePath = Path.join(source, sources[i]); var targetPath = Path.join(target, sources[i]); internals.copy(sourcePath, targetPath, options); } }; // Given a path, determine if the path is a directory exports.isDir = function (path) { try { var stat = Fs.statSync(path); return stat.isDirectory(); } catch (e) { return false; } };