Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use work queue rather than scheduling work
  • Loading branch information
weswigham committed Aug 13, 2016
commit 80fc6f00fd4be32d0125f0a3077bed355e04a50d
96 changes: 59 additions & 37 deletions Gulpfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import through2 = require("through2");
import merge2 = require("merge2");
import intoStream = require("into-stream");
import * as os from "os";
import Linter = require("tslint");
import fold = require("travis-fold");
const gulp = helpMaker(originalGulp);
const mochaParallel = require("./scripts/mocha-parallel.js");
Expand Down Expand Up @@ -929,26 +928,6 @@ gulp.task("build-rules", "Compiles tslint rules to js", () => {
.pipe(gulp.dest(dest));
});

function getLinterOptions() {
return {
configuration: require("./tslint.json"),
formatter: "prose",
formattersDirectory: undefined,
rulesDirectory: "built/local/tslint"
};
}

function lintFileContents(options, path, contents) {
const ll = new Linter(path, contents, options);
console.log("Linting '" + path + "'.");
return ll.lint();
}

function lintFile(options, path) {
const contents = fs.readFileSync(path, "utf8");
return lintFileContents(options, path, contents);
}

const lintTargets = [
"Gulpfile.ts",
"src/compiler/**/*.ts",
Expand All @@ -960,29 +939,72 @@ const lintTargets = [
"tests/*.ts", "tests/webhost/*.ts" // Note: does *not* descend recursively
];

function sendNextFile(files, child, callback, failures) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would help the first-time reader (me) to write the parameter types

const file = files.pop();
if (file) {
console.log(`Linting '${file.path}'.`);
child.send({ kind: "file", name: file.path });
}
else {
child.send({ kind: "close" });
callback(failures);
}
}

function spawnLintWorker(files, callback) {
const child = cp.fork("./scripts/parallel-lint");
let failures = 0;
child.on("message", function(data) {
switch (data.kind) {
case "result":
if (data.failures > 0) {
failures += data.failures;
console.log(data.output);
}
sendNextFile(files, child, callback, failures);
break;
case "error":
console.error(data.error);
failures++;
sendNextFile(files, child, callback, failures);
break;
}
});
sendNextFile(files, child, callback, failures);
}

gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are: --f[iles]=regex", ["build-rules"], () => {
const fileMatcher = RegExp(cmdLineOptions["files"]);
const lintOptions = getLinterOptions();
let failed = 0;
if (fold.isTravis()) console.log(fold.start("lint"));

const files = [];
return gulp.src(lintTargets)
.pipe(insert.transform((contents, file) => {
if (!fileMatcher.test(file.path)) return contents;
const result = lintFile(lintOptions, file.path);
if (result.failureCount > 0) {
console.log(result.output);
failed += result.failureCount;
.pipe(through2.obj((chunk, enc, cb) => {
files.push(chunk);
cb();
}, (cb) => {
files.sort((filea, fileb) => filea.contents.length - fileb.contents.length).filter(file => fileMatcher.test(file.path));
const workerCount = (process.env.workerCount && +process.env.workerCount) || os.cpus().length;
for (let i = 0; i < workerCount; i++) {
spawnLintWorker(files, finished);
}
return contents; // TODO (weswig): Automatically apply fixes? :3
}))
.on("end", () => {
if (fold.isTravis()) console.log(fold.end("lint"));
if (failed > 0) {
console.error("Linter errors.");
process.exit(1);

let completed = 0;
let failures = 0;
function finished(fails) {
completed++;
failures += fails;
if (completed === workerCount) {
if (fold.isTravis()) console.log(fold.end("lint"));
if (failures > 0) {
throw new Error(`Linter errors: ${failures}`);
}
else {
cb();
}
}
}
});
}));
});


Expand Down
49 changes: 16 additions & 33 deletions Jakefile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1063,44 +1063,38 @@ var lintTargets = compilerSources
.concat(["Gulpfile.ts"])
.concat([nodeServerInFile, perftscPath, "tests/perfsys.ts", webhostPath]);

function min(collection, predicate) {
var minimum;
var selected;
for (var key in collection) {
var value = predicate(collection[key]);
if (typeof minimum === "undefined" || value <= minimum) {
minimum = value;
selected = collection[key];
}
function sendNextFile(files, child, callback, failures) {
var file = files.pop();
if (file) {
console.log("Linting '" + file + "'.");
child.send({kind: "file", name: file});
}
else {
child.send({kind: "close"});
callback(failures);
}
return selected;
}

function spawnLintWorker(bucket, callback) {
function spawnLintWorker(files, callback) {
var child = child_process.fork("./scripts/parallel-lint");
var failures = 0;
child.on("message", function(data) {
switch (data.kind) {
case "start":
console.log("Linting '" + data.name + "'.");
break;
case "result":
if (data.failures > 0) {
failures += data.failures;
console.log(data.output);
}
sendNextFile(files, child, callback, failures);
break;
case "error":
console.error(data.error);
failures++;
break;
case "complete":
child.unref();
callback(failures);
sendNextFile(files, child, callback, failures);
break;
}
});
child.send({kind: "config", data: bucket.elements});
sendNextFile(files, child, callback, failures);
}

desc("Runs tslint on the compiler sources. Optional arguments are: f[iles]=regex");
Expand All @@ -1118,24 +1112,13 @@ task("lint", ["build-rules"], function() {
}

var workerCount = (process.env.workerCount && +process.env.workerCount) || os.cpus().length;
var buckets = new Array(workerCount);
for (var i = 0; i < workerCount; i++) {
buckets[i] = {totalSize: 0, elements: []};
}

var names = Object.keys(done).sort(function(namea, nameb) {
return done[namea] < done[nameb];
return done[namea] - done[nameb];
});
for (var i in names) {
var name = names[i];
var bucket = min(buckets, function(b) { return b.totalSize; });
bucket.totalSize += done[name];
bucket.elements.push(name);
}

console.log(buckets);
for (var i in buckets) {
spawnLintWorker(buckets[i], finished);
for (var i = 0; i < workerCount; i++) {
spawnLintWorker(names, finished);
}

var completed = 0;
Expand Down
29 changes: 12 additions & 17 deletions scripts/parallel-lint.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,26 @@ function lintFileAsync(options, path, cb) {
if (err) {
return cb(err);
}
process.send({kind: "start", name: path});
var result = lintFileContents(options, path, contents);
cb(undefined, result);
});
}

process.on("message", function(data) {
switch (data.kind) {
case "config":
var files = data.data;
var done = 0;
case "file":
var target = data.name;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation is wonky here

var lintOptions = getLinterOptions();
files.forEach(function(target) {
lintFileAsync(lintOptions, target, function(err, result) {
if (err) {
process.send({kind: "error", error: err.toString()});
done++;
return;
}
process.send({kind: "result", failures: result.failureCount, output: result.output});
done++;
if (done === files.length) {
process.send({kind: "complete"});
}
});
lintFileAsync(lintOptions, target, function(err, result) {
if (err) {
process.send({kind: "error", error: err.toString()});
return;
}
process.send({kind: "result", failures: result.failureCount, output: result.output});
});
break;
case "close":
process.exit(0);
break;
}
});