Socket
Socket
Sign inDemoInstall

wsrun

Package Overview
Dependencies
Maintainers
1
Versions
48
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

wsrun - npm Package Compare versions

Comparing version 1.1.1 to 1.2.0

55

build/index.js
#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Promise = require("bluebird");
const fs = require("fs");

@@ -10,3 +9,2 @@ const yargs_1 = require("yargs");

const workspace_1 = require("./workspace");
const topomap_1 = require("./topomap");
const bin = yargs_1.argv.bin || 'yarn';

@@ -28,2 +26,3 @@ let mode;

const addPrefix = yargs_1.argv.prefix === undefined ? true : false;
const doneCriteria = yargs_1.argv.doneCriteria;
const cmd = yargs_1.argv._[0];

@@ -40,43 +39,13 @@ const pkgName = yargs_1.argv._[1];

const pkgJsons = _.map(pkgs, pkg => pkg.json);
function genCmd(bi) {
return { pkgName: bi.name, cmd: `cd ${pkgPaths[bi.name]} && ${bin} ${cmd}` };
}
// choose which packages to run the command on
let sortedInstrs;
if (pkgName) {
if (recursive) {
sortedInstrs = topomap_1.subsetBuildOrder(pkgJsons, [pkgName]);
}
else {
sortedInstrs = [{ name: pkgName, order: 1, cycle: false }];
}
}
else {
sortedInstrs = topomap_1.buildOrder(pkgJsons);
}
sortedInstrs = _.sortBy(sortedInstrs, 'order');
let runner;
if (mode === 'stages' || mode === 'serial') {
const runMode = mode === 'stages' ? 'parallel' : 'serial';
// generate stages
const stages = [];
let i = 1;
while (true) {
const stage = sortedInstrs.filter(pkg => pkg.order === i);
if (!stage.length)
break;
stages.push(stage);
i++;
}
// run in batches
runner = Promise.mapSeries(stages, stg => {
console.log(`-- Packages in stage: ${stg.map(p => p.name).join(', ')} --`);
const cmds = stg.map(genCmd);
return new parallelshell_1.RunAll(cmds, runMode, { fastExit, collectLogs, addPrefix }).finishedAll;
});
}
else {
const cmds = sortedInstrs.map(genCmd);
runner = new parallelshell_1.RunAll(cmds, 'parallel', { fastExit, collectLogs, addPrefix }).finishedAll;
}
let runner = new parallelshell_1.RunGraph(pkgJsons, {
bin,
fastExit,
collectLogs,
addPrefix,
mode: mode,
recursive,
doneCriteria
}, pkgPaths);
let runlist = yargs_1.argv._.slice(1);
runner.run(cmd, runlist.length > 0 ? runlist : undefined);
//# sourceMappingURL=index.js.map

@@ -6,41 +6,55 @@ /// <reference types="node" />

*/
import * as Promise from "bluebird";
import { ChildProcess } from "child_process";
import * as Promise from 'bluebird';
import { ChildProcess } from 'child_process';
export interface CmdOptions {
rejectOnNonZeroExit?: boolean;
collectLogs?: boolean;
addPrefix?: boolean;
doneCriteria?: string;
path?: string;
}
export declare class CmdProcess {
cmd: string;
private cmd;
private pkgName;
private opts;
cp: ChildProcess;
finished: Promise<CmdProcess>;
pkgName: string;
opts: {
rejectOnNonZeroExit?: boolean;
collectLogs?: boolean;
addPrefix?: boolean;
};
constructor(cmd: string, pkgName: string, opts?: {
rejectOnNonZeroExit?: boolean;
collectLogs?: boolean;
addPrefix?: boolean;
});
private _closed;
private _finished;
private _exitCode;
readonly finished: Promise<void>;
readonly closed: Promise<number>;
readonly exitCode: Promise<number>;
doneCriteria?: RegExp;
constructor(cmd: string, pkgName: string, opts?: CmdOptions);
start(): void;
private autoPrefix(line);
private _start(cmd);
}
export declare class RunAll {
import { PkgJson, Dict } from './workspace';
export interface GraphOptions {
bin: string;
fastExit: boolean;
collectLogs: boolean;
addPrefix: boolean;
mode: 'parallel' | 'serial' | 'stages';
recursive: boolean;
doneCriteria: string | undefined;
}
export declare class RunGraph {
pkgJsons: PkgJson[];
opts: GraphOptions;
pkgPaths: Dict<string>;
private procmap;
children: CmdProcess[];
finishedAll: Promise<CmdProcess[]>;
opts: {
fastExit: boolean;
collectLogs: boolean;
addPrefix: boolean;
};
constructor(pkgCmds: {
pkgName: string;
cmd: string;
}[], mode: "parallel" | "serial", opts: {
fastExit: boolean;
collectLogs: boolean;
addPrefix: boolean;
});
/**
* kills all the children
*/
closeAll(): void;
private jsonMap;
private runList;
private throat;
constructor(pkgJsons: PkgJson[], opts: GraphOptions, pkgPaths: Dict<string>);
private closeAll;
private lookupOrRun(cmd, pkg);
private allDeps(pkg);
private makeCmd(cmd, pkg);
private runOne(cmd, pkg);
run(cmd: string, pkgs?: string[]): Promise<undefined>;
}

@@ -9,44 +9,72 @@ "use strict";

const split = require("split");
let wait, verbose;
wait = true;
verbose = true;
let mkThroat = require('throat')(Promise);
let passThrough = f => f();
function prefixLine(pkgName, line, prefixLength = 15) {
const pkgNameShort = pkgName.slice(0, prefixLength - 1);
const spaces = " ".repeat(Math.max(1, prefixLength - pkgName.length));
const spaces = ' '.repeat(Math.max(1, prefixLength - pkgName.length));
return `${pkgNameShort}${spaces} | ${line}`;
}
function defer() {
let d;
let promise = new Promise((resolve, reject) => {
d = { resolve, reject };
});
d.promise = promise;
return d;
}
class CmdProcess {
constructor(cmd, pkgName, opts = {}) {
this.cmd = cmd;
this.pkgName = pkgName;
this.opts = opts;
this._start(cmd);
this.finished = new Promise((resolve, reject) => {
this.cp.on("close", (code) => {
if (code > 0) {
const msg = "`" + this.cmd + "` failed with exit code " + code;
console.error(msg);
if (this.opts.rejectOnNonZeroExit) {
reject(new Error(msg));
}
else {
resolve(this);
}
}
else {
resolve(this);
}
});
this.pkgName = pkgName;
this.opts = opts;
this._finished = defer();
this._exitCode = defer();
this._closed = defer();
if (this.opts.doneCriteria)
this.doneCriteria = new RegExp(this.opts.doneCriteria);
}
get finished() {
return this._finished.promise;
}
get closed() {
return this._closed.promise;
}
get exitCode() {
return this._exitCode.promise;
}
start() {
this._start(this.cmd);
this.cp.once('close', code => {
this._closed.resolve(code);
this._exitCode.resolve(code);
});
this.cp.once('exit', code => this._exitCode.resolve(code));
this.exitCode.then(code => {
if (code > 0) {
const msg = '`' + this.cmd + '` failed with exit code ' + code;
console.error(msg);
if (this.opts.rejectOnNonZeroExit)
return this._finished.reject(new Error(msg));
}
this._finished.resolve();
});
}
autoPrefix(line) {
return this.opts.addPrefix ? prefixLine(this.pkgName, line) : line;
}
_start(cmd) {
let sh;
let shFlag;
let args;
// cross platform compatibility
if (process.platform === "win32") {
sh = "cmd";
shFlag = "/c";
if (process.platform === 'win32') {
sh = 'cmd';
args = ['/c', cmd];
}
else {
sh = "bash";
shFlag = "-c";
;
[sh, ...args] = cmd.split(' ');
//sh = 'bash'
//shFlag = '-c'
}

@@ -56,77 +84,105 @@ const stdOutBuffer = [];

this.cmd = cmd;
this.cp = child_process_1.spawn(sh, [shFlag, cmd], {
cwd: (process.versions.node < "8.0.0"
? process.cwd
: process.cwd()),
env: process.env,
stdio: ["pipe"]
console.log('>>>', this.pkgName, '$', cmd);
this.cp = child_process_1.spawn(sh, args, {
cwd: this.opts.path ||
(process.versions.node < '8.0.0' ? process.cwd : process.cwd()),
env: Object.assign(process.env, { FORCE_COLOR: process.stdout.isTTY }),
stdio: this.opts.collectLogs || this.opts.addPrefix || this.opts.doneCriteria ? 'pipe' : 'inherit'
});
if (this.opts.collectLogs) {
this.cp.stdout.pipe(split()).on("data", (line) => {
stdOutBuffer.push(line);
if (this.cp.stdout)
this.cp.stdout.pipe(split()).on('data', (line) => {
if (this.opts.collectLogs)
stdOutBuffer.push(line);
else
console.log(this.autoPrefix(line));
if (this.doneCriteria && this.doneCriteria.test(line))
this._finished.resolve();
});
this.cp.stderr.pipe(split()).on("data", (line) => {
stdErrBuffer.push(line);
if (this.cp.stderr)
this.cp.stderr.pipe(split()).on('data', (line) => {
if (this.opts.collectLogs)
stdErrBuffer.push(line);
else
console.error(this.autoPrefix(line));
if (this.doneCriteria && this.doneCriteria.test(line))
this._finished.resolve();
});
this.cp.on("close", () => {
console.log(stdOutBuffer
.map(line => this.opts.addPrefix ? prefixLine(this.pkgName, line) : line)
.join("\n"));
console.error(stdErrBuffer
.map(line => this.opts.addPrefix ? prefixLine(this.pkgName, line) : line)
.join("\n"));
if (this.opts.collectLogs)
this.closed.then(() => {
console.log(stdOutBuffer.map(line => this.autoPrefix(line)).join('\n'));
console.error(stdErrBuffer.map(line => this.autoPrefix(line)).join('\n'));
});
}
else {
this.cp.stdout.pipe(split()).on("data", (line) => {
console.log(this.opts.addPrefix ? prefixLine(this.pkgName, line) : line);
});
this.cp.stderr.pipe(split()).on("data", (line) => {
console.error(this.opts.addPrefix ? prefixLine(this.pkgName, line) : line);
});
}
}
}
exports.CmdProcess = CmdProcess;
class RunAll {
constructor(pkgCmds, mode, opts) {
this.children = [];
const lodash_1 = require("lodash");
class RunGraph {
constructor(pkgJsons, opts, pkgPaths) {
this.pkgJsons = pkgJsons;
this.opts = opts;
if (mode === "parallel") {
this.finishedAll = Promise.map(pkgCmds, pkgCmd => {
const child = new CmdProcess(pkgCmd.cmd, pkgCmd.pkgName, {
rejectOnNonZeroExit: this.opts.fastExit,
collectLogs: this.opts.collectLogs,
addPrefix: this.opts.addPrefix
});
child.cp.on("close", code => code > 0 && this.closeAll.bind(this));
this.children.push(child);
return child.finished;
this.pkgPaths = pkgPaths;
this.procmap = new Map();
this.jsonMap = new Map();
this.runList = new Set();
this.throat = passThrough;
this.closeAll = () => {
console.log('Stopping', this.children.length, 'active children');
this.children.forEach(ch => {
ch.cp.removeAllListeners('close');
ch.cp.removeAllListeners('exit');
ch.cp.kill('SIGINT');
});
};
pkgJsons.forEach(j => this.jsonMap.set(j.name, j));
this.children = [];
if (this.opts.mode === 'serial')
this.throat = mkThroat(1);
if (this.opts.mode === 'stages')
this.throat = mkThroat(16); // max 16 proc
process.on('SIGINT', this.closeAll); // close all children on ctrl+c
}
lookupOrRun(cmd, pkg) {
let proc = this.procmap.get(pkg);
if (proc == null) {
proc = Promise.resolve().then(() => this.runOne(cmd, pkg));
this.procmap.set(pkg, proc);
}
else {
this.finishedAll = Promise.mapSeries(pkgCmds, pkgCmd => {
const child = new CmdProcess(pkgCmd.cmd, pkgCmd.pkgName, {
rejectOnNonZeroExit: this.opts.fastExit,
collectLogs: this.opts.collectLogs,
addPrefix: this.opts.addPrefix
});
child.cp.on("close", code => code > 0 && this.closeAll.bind(this));
this.children = [child];
return proc;
}
allDeps(pkg) {
let findMyDeps = lodash_1.uniq(Object.keys(pkg.dependencies || {}).concat(Object.keys(pkg.devDependencies || {}))).filter(d => this.jsonMap.has(d) && (this.opts.recursive || this.runList.has(d)));
return findMyDeps;
}
makeCmd(cmd, pkg) {
return `${this.opts.bin} ${cmd}`;
}
runOne(cmd, pkg) {
let p = this.jsonMap.get(pkg);
if (p == null)
throw new Error('Unknown package: ' + pkg);
let myDeps = Promise.all(this.allDeps(p).map(d => this.lookupOrRun(cmd, d)));
return myDeps.then(() => {
let cmdLine = this.makeCmd(cmd, pkg);
const child = new CmdProcess(cmdLine, pkg, {
rejectOnNonZeroExit: this.opts.fastExit,
collectLogs: this.opts.collectLogs,
addPrefix: this.opts.addPrefix,
doneCriteria: this.opts.doneCriteria,
path: this.pkgPaths[pkg]
});
child.exitCode.then(code => code > 0 && this.closeAll.bind(this));
this.children.push(child);
let finished = this.throat(() => {
child.start();
return child.finished;
});
}
process.on("SIGINT", this.closeAll.bind(this)); // close all children on ctrl+c
}
/**
* kills all the children
*/
closeAll() {
this.children.forEach(ch => {
ch.cp.removeAllListeners("close");
ch.cp.kill("SIGINT");
return this.opts.mode != 'parallel' ? finished : Promise.resolve();
});
}
run(cmd, pkgs = this.pkgJsons.map(p => p.name)) {
this.runList = new Set(pkgs);
return Promise.all(pkgs.map(pkg => this.lookupOrRun(cmd, pkg))).thenReturn(void 0);
}
}
exports.RunAll = RunAll;
exports.RunGraph = RunGraph;
//# sourceMappingURL=parallelshell.js.map
{
"name": "wsrun",
"version": "1.1.1",
"version": "1.2.0",
"description": "executes commands on packages in parallel, but is aware of the dependencies between them",

@@ -24,3 +24,5 @@ "main": "./build/index.js",

},
"files": ["build/"],
"files": [
"build/"
],
"devDependencies": {

@@ -32,4 +34,4 @@ "@types/bluebird": "^3.5.18",

"@types/node": "^8.0.53",
"@types/split": "^0.3.28",
"@types/yargs": "^8.0.2",
"@types/split": "^0.3.28",
"jest": "^21.2.1",

@@ -50,4 +52,5 @@ "ts-jest": "^21.2.3",

"split": "^1.0.1",
"throat": "^4.1.0",
"yargs": "^10.0.3"
}
}
# Workspace command runner
Usage:
Run commands in a yarn workspace, like a boss.
### Usage:
```

@@ -22,5 +24,6 @@ wsrun cmd [<package>] [options]

--bin=yarn which program should we pass the cmd to
--done-criteria=regex consider the process "done" when output line matches regex
```
Examples:
### Examples:

@@ -35,10 +38,7 @@ `yarn wsrun watch` will run `yarn watch` on every individual package, in parallel.

`yarn wsrun clean` will remove the build folders in every package.
`yarn wsrun watch planc -r --stages --done-criteria='Compilation complete'` will watch planc deps,
in order, continuing when command outputs "Compilation complete"
`yarn wsrun clean` will remove "build" folders in every package.
`yarn wsrun test` will test every package.
Todo:
* Support for collecting stdouts
* Support for stdout line prefixes
* Reorganize files

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc