build(broccoli): allow rebuild() to return DiffResult

Plugins may opt to return a DiffResult themselves, and avoid the
need to calculate a diff

Closes #2514
This commit is contained in:
Caitlin Potter 2015-06-12 13:12:10 -04:00
parent ed9d9d5096
commit d575915d7a
2 changed files with 57 additions and 26 deletions

View File

@ -28,7 +28,7 @@ export function wrapDiffingPlugin(pluginClass): DiffingPluginWrapperFactory {
export interface DiffingBroccoliPlugin { export interface DiffingBroccoliPlugin {
rebuild(diff: (DiffResult | DiffResult[])): (Promise<any>| void); rebuild(diff: (DiffResult | DiffResult[])): (Promise<DiffResult | void>| DiffResult | void);
cleanup ? () : void; cleanup ? () : void;
} }
@ -52,6 +52,8 @@ class DiffingPluginWrapper implements BroccoliTree {
cachePath = null; cachePath = null;
outputPath = null; outputPath = null;
private diffResult: DiffResult = null;
constructor(private pluginClass, private wrappedPluginArguments) { constructor(private pluginClass, private wrappedPluginArguments) {
if (Array.isArray(wrappedPluginArguments[0])) { if (Array.isArray(wrappedPluginArguments[0])) {
this.inputTrees = this.stabilizeTrees(wrappedPluginArguments[0]); this.inputTrees = this.stabilizeTrees(wrappedPluginArguments[0]);
@ -62,33 +64,59 @@ class DiffingPluginWrapper implements BroccoliTree {
this.description = this.pluginClass.name; this.description = this.pluginClass.name;
} }
private calculateDiff(firstRun: boolean): (DiffResult | DiffResult[]) { private getDiffResult(): (DiffResult | DiffResult[]) {
// TODO(caitp): optionally log trees based on environment variable or let returnOrCalculateDiffResult = (tree, index) => {
// command line option. It may be worth logging for trees where elapsed // returnOrCalculateDiffResult will do one of two things:
// time exceeds some threshold, like 10ms. //
if (this.treeDiffer) { // If `this.diffResult` is null, calculate a DiffResult using TreeDiffer
return this.treeDiffer.diffTree(); // for the input tree.
} else if (this.treeDiffers) { //
return this.treeDiffers.map((treeDiffer) => treeDiffer.diffTree()); // Otherwise, `this.diffResult` was produced from the output of the
// inputTree's rebuild() method, and can be used without being checked.
// Set `this.diffResult` to null and return the previously stored value.
if (!tree.diffResult) {
let differ = index === false ? this.treeDiffer : this.treeDiffers[index];
return differ.diffTree();
}
let diffResult = tree.diffResult;
tree.diffResult = null;
return diffResult;
};
if (this.inputTrees) {
return this.inputTrees.map(returnOrCalculateDiffResult);
} else if (this.inputTree) {
return returnOrCalculateDiffResult(this.inputTree, false);
} else { } else {
throw new Error("Missing TreeDiffer"); throw new Error("Missing TreeDiffer");
} }
} }
private maybeStoreDiffResult(value: (DiffResult | void)) {
this.diffResult = value ? <DiffResult>(value) : null;
}
rebuild() { rebuild() {
try { try {
let firstRun = !this.initialized; let firstRun = !this.initialized;
this.init(); this.init();
let diffResult = this.calculateDiff(firstRun); let diffResult = this.getDiffResult();
var rebuildPromise = this.wrappedPlugin.rebuild(diffResult); let result = this.wrappedPlugin.rebuild(diffResult);
if (rebuildPromise) { if (result) {
return (<Promise<any>>rebuildPromise).then(this.relinkOutputAndCachePaths.bind(this)); let resultPromise = <Promise<DiffResult | void>>(result);
if (resultPromise.then) {
// rebuild() -> Promise<>
return resultPromise.then((result: (DiffResult | void)) => {
this.maybeStoreDiffResult(result);
this.relinkOutputAndCachePaths();
});
}
} }
this.maybeStoreDiffResult(<(DiffResult | void)>(result));
this.relinkOutputAndCachePaths(); this.relinkOutputAndCachePaths();
} catch (e) { } catch (e) {
e.message = `[${this.description}]: ${e.message}`; e.message = `[${this.description}]: ${e.message}`;

View File

@ -121,25 +121,28 @@ export class TreeDiffer {
} }
export interface DiffResult { export class DiffResult {
addedPaths: string[];
changedPaths: string[];
removedPaths: string[];
log(verbose: boolean): void;
toString(): string;
}
class DirtyCheckingDiffResult {
public filesChecked: number = 0;
public directoriesChecked: number = 0;
public addedPaths: string[] = []; public addedPaths: string[] = [];
public changedPaths: string[] = []; public changedPaths: string[] = [];
public removedPaths: string[] = []; public removedPaths: string[] = [];
constructor(public label: string = '') {}
log(verbose: boolean): void {}
toString(): string {
// TODO(@caitp): more meaningful logging
return '';
}
}
class DirtyCheckingDiffResult extends DiffResult {
public filesChecked: number = 0;
public directoriesChecked: number = 0;
public startTime: number = Date.now(); public startTime: number = Date.now();
public endTime: number = null; public endTime: number = null;
constructor(public label: string, public directoryName: string) {} constructor(label: string, public directoryName: string) { super(label); }
toString() { toString() {
return `${pad(this.label, 30)}, ${pad(this.endTime - this.startTime, 5)}ms, ` + return `${pad(this.label, 30)}, ${pad(this.endTime - this.startTime, 5)}ms, ` +