build(brocolli): move filename filtering into DiffingPluginWrapper

Closes #1719
This commit is contained in:
Caitlin Potter 2015-05-06 19:24:10 -04:00
parent 6bba289a3c
commit aaf3edd131
5 changed files with 149 additions and 43 deletions

View File

@ -30,6 +30,8 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
private tsServiceHost: ts.LanguageServiceHost; private tsServiceHost: ts.LanguageServiceHost;
private tsService: ts.LanguageService; private tsService: ts.LanguageService;
static includeExtensions = ['.ts'];
static excludeExtensions = ['.d.ts'];
constructor(public inputPath: string, public cachePath: string, public options) { constructor(public inputPath: string, public cachePath: string, public options) {
this.tsOpts = Object.create(options); this.tsOpts = Object.create(options);
@ -46,8 +48,7 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
let pathsToEmit = []; let pathsToEmit = [];
let pathsWithErrors = []; let pathsWithErrors = [];
treeDiff.changedPaths.filter((changedPath) => treeDiff.changedPaths
changedPath.match(/\.ts/) && !changedPath.match(/\.d\.ts/))
.forEach((tsFilePath) => { .forEach((tsFilePath) => {
if (!this.fileRegistry[tsFilePath]) { if (!this.fileRegistry[tsFilePath]) {
this.fileRegistry[tsFilePath] = {version: 0}; this.fileRegistry[tsFilePath] = {version: 0};
@ -59,8 +60,7 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
pathsToEmit.push(tsFilePath); pathsToEmit.push(tsFilePath);
}); });
treeDiff.removedPaths.filter((changedPath) => treeDiff.removedPaths
changedPath.match(/\.ts/) && !changedPath.match(/\.d\.ts/))
.forEach((tsFilePath) => { .forEach((tsFilePath) => {
console.log('removing outputs for', tsFilePath); console.log('removing outputs for', tsFilePath);

View File

@ -49,7 +49,6 @@ class DiffingPluginWrapper implements BroccoliTree {
cachePath = null; cachePath = null;
outputPath = null; outputPath = null;
constructor(private pluginClass, private wrappedPluginArguments) { constructor(private pluginClass, private wrappedPluginArguments) {
if (Array.isArray(wrappedPluginArguments[0])) { if (Array.isArray(wrappedPluginArguments[0])) {
this.inputTrees = wrappedPluginArguments[0]; this.inputTrees = wrappedPluginArguments[0];
@ -92,8 +91,10 @@ class DiffingPluginWrapper implements BroccoliTree {
private init() { private init() {
if (!this.initialized) { if (!this.initialized) {
let includeExtensions = this.pluginClass.includeExtensions || [];
let excludeExtensions = this.pluginClass.excludeExtensions || [];
this.initialized = true; this.initialized = true;
this.treeDiffer = new TreeDiffer(this.inputPath); this.treeDiffer = new TreeDiffer(this.inputPath, includeExtensions, excludeExtensions);
this.wrappedPlugin = this.wrappedPlugin =
new this.pluginClass(this.inputPath, this.cachePath, this.wrappedPluginArguments[1]); new this.pluginClass(this.inputPath, this.cachePath, this.wrappedPluginArguments[1]);
} }

View File

@ -13,43 +13,37 @@ let xtend = require('xtend');
class DiffingTraceurCompiler implements DiffingBroccoliPlugin { class DiffingTraceurCompiler implements DiffingBroccoliPlugin {
constructor(public inputPath: string, public cachePath: string, public options) {} constructor(public inputPath: string, public cachePath: string, public options) {}
static includeExtensions = ['.js', '.es6', '.cjs'];
rebuild(treeDiff: DiffResult) { rebuild(treeDiff: DiffResult) {
treeDiff.changedPaths.forEach((changedFilePath) => { treeDiff.changedPaths.forEach((changedFilePath) => {
var extension = path.extname(changedFilePath).toLowerCase(); var traceurOpts = xtend({filename: changedFilePath}, this.options.traceurOptions);
if (extension === '.js' || extension === '.es6' || extension === '.cjs') {
var traceurOpts = xtend({filename: changedFilePath}, this.options.traceurOptions);
var fsOpts = {encoding: 'utf-8'}; var fsOpts = {encoding: 'utf-8'};
var absoluteInputFilePath = path.join(this.inputPath, changedFilePath); var absoluteInputFilePath = path.join(this.inputPath, changedFilePath);
var sourcecode = fs.readFileSync(absoluteInputFilePath, fsOpts); var sourcecode = fs.readFileSync(absoluteInputFilePath, fsOpts);
var result = traceur.compile(traceurOpts, changedFilePath, sourcecode); var result = traceur.compile(traceurOpts, changedFilePath, sourcecode);
// TODO: we should fix the sourceMappingURL written by Traceur instead of overriding // TODO: we should fix the sourceMappingURL written by Traceur instead of overriding
// (but we might switch to typescript first) // (but we might switch to typescript first)
var mapFilepath = var mapFilepath = changedFilePath.replace(/\.\w+$/, '') + this.options.destSourceMapExtension;
changedFilePath.replace(/\.\w+$/, '') + this.options.destSourceMapExtension; result.js = result.js + '\n//# sourceMappingURL=./' + path.basename(mapFilepath);
result.js = result.js + '\n//# sourceMappingURL=./' + path.basename(mapFilepath);
var destFilepath = changedFilePath.replace(/\.\w+$/, this.options.destExtension); var destFilepath = changedFilePath.replace(/\.\w+$/, this.options.destExtension);
var destFile = path.join(this.cachePath, destFilepath); var destFile = path.join(this.cachePath, destFilepath);
fse.mkdirsSync(path.dirname(destFile)); fse.mkdirsSync(path.dirname(destFile));
fs.writeFileSync(destFile, result.js, fsOpts); fs.writeFileSync(destFile, result.js, fsOpts);
var destMap = path.join(this.cachePath, mapFilepath); var destMap = path.join(this.cachePath, mapFilepath);
result.sourceMap.file = destFilepath; result.sourceMap.file = destFilepath;
fs.writeFileSync(destMap, JSON.stringify(result.sourceMap), fsOpts); fs.writeFileSync(destMap, JSON.stringify(result.sourceMap), fsOpts);
}
}); });
treeDiff.removedPaths.forEach((removedFilePath) => { treeDiff.removedPaths.forEach((removedFilePath) => {
var extension = path.extname(removedFilePath).toLowerCase(); var destFilepath = removedFilePath.replace(/\.\w+$/, this.options.destExtension);
if (extension === '.js' || extension === '.es6' || extension === '.cjs') { var absoluteOuputFilePath = path.join(this.cachePath, destFilepath);
var destFilepath = removedFilePath.replace(/\.\w+$/, this.options.destExtension); fs.unlinkSync(absoluteOuputFilePath);
var absoluteOuputFilePath = path.join(this.cachePath, destFilepath);
fs.unlinkSync(absoluteOuputFilePath);
}
}); });
} }
} }

View File

@ -102,6 +102,95 @@ describe('TreeDiffer', () => {
diffResult = differ.diffTree(); diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.txt']); expect(diffResult.changedPaths).toEqual(['file-1.txt']);
}); });
it('should ignore files with extensions not listed in includeExtensions', () => {
let testDir = {
'dir1': {
'file-1.js': mockfs.file({content: 'file-1.js content', mtime: new Date(1000)}),
'file-2.md': mockfs.file({content: 'file-2.md content', mtime: new Date(1000)}),
'file-3.coffee': mockfs.file({content: 'file-3.coffee content', mtime: new Date(1000)}),
'subdir-1': {
'file-1.1.cc': mockfs.file({content: 'file-1.1.cc content', mtime: new Date(1000)})
}
}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1', ['.js', '.coffee']);
let diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.js', 'file-3.coffee']);
// change two files
testDir['dir1']['file-1.js'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-3.coffee'] =
mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['subdir-1']['file-1.1.cc'] =
mockfs.file({content: 'file-1.1.cc content', mtime: new Date(9999)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.js', 'file-3.coffee']);
expect(diffResult.removedPaths).toEqual([]);
// change one file
testDir['dir1']['file-1.js'] = mockfs.file({content: 'super new', mtime: new Date(1000)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.js']);
});
it('should ignore files with extensions listed in excludeExtensions', () => {
let testDir = {
'dir1': {
'file-1.ts': mockfs.file({content: 'file-1.ts content', mtime: new Date(1000)}),
'file-1.cs': mockfs.file({content: 'file-1.cs content', mtime: new Date(1000)}),
'file-1.d.cs': mockfs.file({content: 'file-1.d.cs content', mtime: new Date(1000)}),
'file-2.md': mockfs.file({content: 'file-2.md content', mtime: new Date(1000)}),
'file-3.ts': mockfs.file({content: 'file-3.ts content', mtime: new Date(1000)}),
'file-4.d.ts': mockfs.file({content: 'file-4.d.ts content', mtime: new Date(1000)}),
'subdir-1': {
'file-1.1.cc': mockfs.file({content: 'file-1.1.cc content', mtime: new Date(1000)})
}
}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1', ['.ts', '.cs'], ['.d.ts', '.d.cs']);
let diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.cs', 'file-1.ts', 'file-3.ts']);
// change two files
testDir['dir1']['file-1.ts'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-1.cs'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-1.d.cs'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-3.ts'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-4.d.ts'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['subdir-1']['file-1.1.cc'] =
mockfs.file({content: 'file-1.1.cc content', mtime: new Date(9999)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.cs', 'file-1.ts', 'file-3.ts']);
expect(diffResult.removedPaths).toEqual([]);
// change one file
testDir['dir1']['file-4.d.ts'] = mockfs.file({content: 'super new', mtime: new Date(1000)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual([]);
});
}); });
describe('diff of new files', () => { describe('diff of new files', () => {

View File

@ -8,8 +8,24 @@ export class TreeDiffer {
private fingerprints: {[key: string]: string} = Object.create(null); private fingerprints: {[key: string]: string} = Object.create(null);
private nextFingerprints: {[key: string]: string} = Object.create(null); private nextFingerprints: {[key: string]: string} = Object.create(null);
private rootDirName: string; private rootDirName: string;
private include: RegExp = null;
private exclude: RegExp = null;
constructor(private rootPath: string) { this.rootDirName = path.basename(rootPath); } constructor(private rootPath: string, includeExtensions?: string[],
excludeExtensions?: string[]) {
this.rootDirName = path.basename(rootPath);
let buildRegexp = (arr) => new RegExp(`(${arr.reduce(combine, "")})$`, "i");
this.include = (includeExtensions || []).length ? buildRegexp(includeExtensions) : null;
this.exclude = (excludeExtensions || []).length ? buildRegexp(excludeExtensions) : null;
function combine(prev, curr) {
if (curr.charAt(0) !== ".") throw new TypeError("Extension must begin with '.'");
curr = '(' + curr + ')';
return prev ? (prev + '|' + curr) : curr;
}
}
public diffTree(): DiffResult { public diffTree(): DiffResult {
@ -30,9 +46,12 @@ export class TreeDiffer {
result.directoriesChecked++; result.directoriesChecked++;
this.dirtyCheckPath(absolutePath, result); this.dirtyCheckPath(absolutePath, result);
} else { } else {
result.filesChecked++; if (!(this.include && !absolutePath.match(this.include)) &&
if (this.isFileDirty(absolutePath, pathStat)) { !(this.exclude && absolutePath.match(this.exclude))) {
result.changedPaths.push(path.relative(this.rootPath, absolutePath)); result.filesChecked++;
if (this.isFileDirty(absolutePath, pathStat)) {
result.changedPaths.push(path.relative(this.rootPath, absolutePath));
}
} }
} }
}); });
@ -62,9 +81,12 @@ export class TreeDiffer {
private detectDeletionsAndUpdateFingerprints(result: DiffResult) { private detectDeletionsAndUpdateFingerprints(result: DiffResult) {
for (let absolutePath in this.fingerprints) { for (let absolutePath in this.fingerprints) {
if (this.fingerprints[absolutePath] !== null) { if (!(this.include && !absolutePath.match(this.include)) &&
let relativePath = path.relative(this.rootPath, absolutePath); !(this.exclude && absolutePath.match(this.exclude))) {
result.removedPaths.push(relativePath); if (this.fingerprints[absolutePath] !== null) {
let relativePath = path.relative(this.rootPath, absolutePath);
result.removedPaths.push(relativePath);
}
} }
} }
@ -93,8 +115,7 @@ class DirtyCheckingDiffResult {
constructor(public name: string) {} constructor(public name: string) {}
toString() { toString() {
return `${pad(this.name, 40)}, ` + return `${pad(this.name, 40)}, duration: ${pad(this.endTime - this.startTime, 5)}ms, ` +
`duration: ${pad(this.endTime - this.startTime, 5)}ms, ` +
`${pad(this.changedPaths.length + this.removedPaths.length, 5)} changes detected ` + `${pad(this.changedPaths.length + this.removedPaths.length, 5)} changes detected ` +
`(files: ${pad(this.filesChecked, 5)}, directories: ${pad(this.directoriesChecked, 4)})`; `(files: ${pad(this.filesChecked, 5)}, directories: ${pad(this.directoriesChecked, 4)})`;
} }
@ -102,8 +123,9 @@ class DirtyCheckingDiffResult {
log(verbose) { log(verbose) {
let prefixedPaths = let prefixedPaths =
this.changedPaths.map((p) => `* ${p}`).concat(this.removedPaths.map((p) => `- ${p}`)); this.changedPaths.map((p) => `* ${p}`).concat(this.removedPaths.map((p) => `- ${p}`));
console.log(`Tree diff: ${this}` + console.log(`Tree diff: ${this}` + ((verbose && prefixedPaths.length) ?
((verbose && prefixedPaths.length) ? ` [\n ${prefixedPaths.join('\n ')}\n]` : '')); ` [\n ${prefixedPaths.join('\n ')}\n]` :
''));
} }
} }