UNPKG

msync

Version:

Easily manage building and syncing multiple node-modules in a flexibly defined workspace.

132 lines (131 loc) 4.73 kB
import { debounceTime, filter } from 'rxjs/operators'; import { exec, constants, copy, dependsOn, elapsed, file, filter as filterUtil, fs, listr, loadSettings, log, moment, updatePackageRef, util, } from '../common'; import * as listCommand from './ls.cmd'; export const name = 'sync'; export const alias = ['s', 'sl']; export const description = `Syncs each module's dependency tree within the workspace.`; export const args = { '-i': 'Include ignored modules.', '-w': 'Sync on changes to files.', '-v': 'Update version reference in package.json files.', }; export async function cmd(args) { const options = (args && args.options) || {}; const watch = options.w || false; const includeIgnored = options.i || false; const updateVersions = options.v || false; const config = { includeIgnored, updateVersions }; if (watch) { await syncWatch(config); } else { await sync(config); } } export async function sync(options = {}) { const { includeIgnored = false } = options; const write = (msg) => util.write(msg, options.silent); const settings = await loadSettings(); if (!settings) { write(log.yellow(constants.CONFIG_NOT_FOUND_ERROR)); return; } const modules = settings.modules .filter(pkg => filterUtil.localDeps(pkg).length > 0) .filter(pkg => filterUtil.includeIgnored(pkg, includeIgnored)); await syncModules(modules, options); return { settings: settings, modules, }; } export async function syncModules(modules, options = {}) { const startedAt = new Date(); const { includeIgnored = false, updateVersions = false, silent = false } = options; const write = (msg) => util.write(msg, options.silent); const sync = async (sources, target) => { for (const source of sources) { if (source.package) { await copy.module(source.package, target); await copy.logUpdate(target); await chmod(target); if (updateVersions) { await updatePackageRef(target, source.package.name, source.package.version, { save: true, }); } } } }; const tasks = modules.map(target => { const sources = filterUtil .localDeps(target) .filter(dep => filterUtil.includeIgnored(dep.package, includeIgnored)); const sourceNames = sources.map(dep => ` ${log.cyan(dep.name)}`); const title = `${log.magenta(target.name)} ${log.cyan(sourceNames.length > 0 ? '⬅' : '')}${sourceNames}`; return { title, task: () => sync(sources, target), }; }); try { if (silent) { for (const item of tasks) { await item.task(); } } else { const taskList = listr(tasks, { concurrent: false }); await taskList.run(); write(log.gray(` ${elapsed(startedAt)}, ${moment().format('h:mm:ssa')}`)); write(''); } } catch (error) { write(log.yellow(`\nFailed while syncing module '${error.message}'.`)); } return modules; } export async function chmod(module) { const dir = fs.join(module.dir, 'node_modules/.bin'); if (!(await fs.pathExistsSync(dir))) { return []; } const cmd = exec.command(`chmod 777`); const files = (await fs.readdir(dir)).map(name => fs.join(dir, name)); const wait = files.map(path => { return cmd .clone() .add(path) .run({ silent: true }); }); await Promise.all(wait); return files; } export async function syncWatch(options = {}) { const { includeIgnored = false, silent = false } = options; const write = (msg) => util.write(msg, options.silent); write(log.magenta('\nSync watching:')); const result = await listCommand.ls({ dependencies: 'local', includeIgnored, }); if (!result) { return; } const { modules, settings } = result; modules.forEach(pkg => watch(pkg, modules, settings.watchPattern, includeIgnored, silent)); } function watch(pkg, modules, watchPattern, includeIgnored, silent) { const sync = () => { const dependants = dependsOn(pkg, modules); if (dependants.length > 0) { util.write(log.green(`${pkg.name} changed: `), silent); syncModules(dependants, { includeIgnored }); } }; file .watch(fs.join(pkg.dir, watchPattern)) .pipe(filter(path => !path.includes('node_modules/')), debounceTime(1000)) .subscribe(() => sync()); }