UNPKG

nlu

Version:

Use this package to link your projects together for local development.

222 lines (221 loc) 9.11 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); const util = require("util"); const cp = require("child_process"); const chalk_1 = require("chalk"); const async = require("async"); const logging_1 = require("./logging"); exports.runNPMLink = (map, opts, cb) => { const keys = Object.keys(map); if (keys.length < 1) { return process.nextTick(cb, new Error('NLU could not find any dependencies on the filesystem;' + ' perhaps broaden your search using searchRoots.')); } if (opts.dry_run) { logging_1.default.warning('given the --treeify option passed at the command line, npm-link-up will only print out the dependency tree and exit.'); logging_1.default.veryGood('the following is a complete list of recursively related dependencies:\n'); logging_1.default.veryGood(util.inspect(Object.keys(map))); return process.nextTick(cb); } if (opts.verbosity > 2) { logging_1.default.good('Dependency map:'); } Object.keys(map).forEach(function (k) { if (opts.verbosity > 2) { logging_1.default.info('Info for project:', chalk_1.default.bold(k)); console.log(chalk_1.default.green.bold(util.inspect(map[k]))); console.log(); } }); const isAllLinked = function () { return Object.keys(map).every(function (k) { return map[k].isLinked; }); }; const getCountOfUnlinkedDeps = function (dep) { return dep.deps.filter(function (d) { if (!map[d]) { logging_1.default.warning(`there is no dependency named ${d} in the map.`); return false; } return !map[d].isLinked; }) .length; }; const findNextDep = function () { let dep; let count = null; for (let name in map) { if (map.hasOwnProperty(name)) { let d = map[name]; if (!d.isLinked) { if (!count) { dep = d; count = dep.deps.length; } else if (getCountOfUnlinkedDeps(d) < count) { dep = d; count = dep.deps.length; } } } } if (!dep) { logging_1.default.error('Internal implementation error => no dep found,\nbut there should be at least one yet-to-be-linked dep.'); return process.exit(1); } return dep; }; const getNPMLinkList = (deps) => { return deps.filter(function (d) { if (!map[d]) { logging_1.default.warning('Map for key => "' + d + '" is not defined.'); return false; } return map[d] && map[d].isLinked; }) .map(function (d) { const path = map[d].path; const bin = map[d].bin; return ` mkdir -p node_modules && rm -rf "node_modules/${d}" && mkdir -p "node_modules/${d}" && rm -rf "node_modules/${d}" ` + ` && ln -s "${path}" "node_modules/${d}" ` + ` ${getBinMap(bin, path, d)}`; }); }; const getBinMap = function (bin, path, name) { if (!bin) { return ''; } if (typeof bin === 'string') { return ` && mkdir -p "node_modules/.bin" && ln -s "${path}/${bin}" "node_modules/.bin/${name}" `; } const keys = Object.keys(bin); if (keys.length < 1) { return ''; } return ` && ` + keys.map(function (k) { return ` mkdir -p node_modules/.bin && ln -sf "${path}/${bin[k]}" "node_modules/.bin/${k}" `; }) .join(' && '); }; const getCommandListOfLinked = function (name) { const path = map[name] && map[name].path; const bin = map[name] && map[name].bin; if (!path) { logging_1.default.error(`missing path for dependency with name "${name}"`); return process.exit(1); } return Object.keys(map).filter(function (k) { return map[k].isLinked && map[k].deps.includes(name); }) .map(function (k) { const p = `${map[k].path}`; return ` cd ${p} && mkdir -p node_modules && rm -rf "node_modules/${name}" && mkdir -p "node_modules/${name}" ` + ` && rm -rf "node_modules/${name}" && ln -s "${path}" "node_modules/${name}" ` + ` ${getBinMap(bin, path, name)} `; }); }; const getInstallCommand = function (dep) { if (!opts.no_install && (dep.runInstall || opts.install_all || (dep.isMainProject && opts.install_main))) { const installProd = opts.production ? ' --production ' : ''; return ` && rm -rf node_modules && npm install --cache-min 999999 --loglevel=warn ${installProd}`; } }; const getLinkToItselfCommand = function (dep) { if (!opts.no_link && (opts.self_link_all || dep.linkToItself === true)) { return ` && mkdir -p node_modules && rm -rf "node_modules/${dep.name}" && mkdir -p "node_modules/${dep.name}" ` + ` && rm -rf "node_modules/${dep.name}" ` + ` && ln -s "${dep.path}" "node_modules/${dep.name}" `; } }; const getGlobalLinkCommand = function (dep) { if (!opts.no_link && (opts.link_all || (dep.isMainProject && opts.link_main))) { const installProd = opts.production ? ' --production ' : ''; return ` && mkdir -p node_modules/.bin && npm link --cache-min 999999 -f ${installProd}`; } }; async.until(isAllLinked, function (cb) { if (opts.verbosity > 2) { logging_1.default.info(`Searching for next dep to run.`); } const dep = findNextDep(); if (opts.verbosity > 1) { logging_1.default.good(`Processing dep with name => '${chalk_1.default.bold(dep.name)}'.`); } const deps = getNPMLinkList(dep.deps); const links = deps.length > 0 ? '&& ' + deps.join(' && ') : ''; const script = [ `cd ${dep.path}`, getInstallCommand(dep), getGlobalLinkCommand(dep), links, getLinkToItselfCommand(dep) ] .filter(Boolean) .join(' '); if (opts.verbosity > 1) { logging_1.default.info(`First-pass script is => "${chalk_1.default.blueBright.bold(script)}"`); } const k = cp.spawn('bash', [], { env: Object.assign({}, process.env, { NPM_LINK_UP: 'yes' }) }); k.stdin.end(script); k.stdout.setEncoding('utf8'); k.stderr.setEncoding('utf8'); k.stderr.pipe(process.stderr); if (opts.verbosity > 2) { k.stdout.pipe(process.stdout); } let stderr = ''; k.stderr.on('data', function (d) { stderr += d; }); k.once('error', cb); k.once('exit', function (code) { if (code > 0 && /ERR/i.test(stderr)) { logging_1.default.error(`Dep with name "${dep.name}" is done, but with an error.`); return cb({ code, dep, error: stderr }); } dep.isLinked = map[dep.name].isLinked = true; const linkPreviouslyUnlinked = function (cb) { const cmds = getCommandListOfLinked(dep.name); if (!cmds.length) { return process.nextTick(cb); } const cmd = cmds.join(' && '); if (opts.verbosity > 1) { logging_1.default.info(`Running this command for "${chalk_1.default.bold(dep.name)}" => '${chalk_1.default.blueBright(cmd)}'.`); } const k = cp.spawn('bash', [], { env: Object.assign({}, process.env, { NPM_LINK_UP: 'yes' }) }); k.stdin.write(cmd); k.stdout.setEncoding('utf8'); k.stderr.setEncoding('utf8'); k.stderr.pipe(process.stderr, { end: false }); if (opts.verbosity > 2) { k.stdout.pipe(process.stdout, { end: false }); } k.stdin.end(); k.once('exit', cb); }; linkPreviouslyUnlinked(function (err) { if (err) { logging_1.default.error(`Dep with name "${dep.name}" is done, but with an error => `, err.message || err); } else { if (opts.verbosity > 1) { logging_1.default.veryGood(`Dep with name '${chalk_1.default.bold(dep.name)}' is done.`); } } cb(err, { code: code, dep: dep, error: stderr }); }); }); }, cb); };