From c1fcf6dd9cfaa7ed7e0d3ada466b58308e9fae95 Mon Sep 17 00:00:00 2001 From: Jinheng Zhu Date: Wed, 26 Apr 2017 11:22:39 +0800 Subject: [PATCH] Add support for output of `svn diff --git` --- README.md | 4 ++ src/diff-parser.js | 110 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b4b368e..68cd5df 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ diff2html generates pretty HTML diffs from git or unified diff output. * Easy code selection +* Support `svn diff --git` output + ## Online Example > Go to [diff2html](https://diff2html.xyz/) @@ -100,6 +102,8 @@ The HTML output accepts a Javascript object with configuration. Possible options - `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is `2500` - `templates`: object with previously compiled templates to replace parts of the html - `rawTemplates`: object with raw not compiled templates to replace parts of the html + - `ignoreSvnPropertyChange`: If you use `svn diff --git`, and add or delete a binary file, you will get two file change records in output. Set `ignoreSvnPropertyChange = true` will help you ignore the second record. + > For more information regarding the possible templates look into [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates) ## Diff2HtmlUI Helper diff --git a/src/diff-parser.js b/src/diff-parser.js index 4f3fdf6..1b67feb 100644 --- a/src/diff-parser.js +++ b/src/diff-parser.js @@ -5,7 +5,7 @@ * */ -(function() { +(function () { var utils = require('./utils.js').Utils; var LINE_TYPE = { @@ -22,7 +22,7 @@ DiffParser.prototype.LINE_TYPE = LINE_TYPE; - DiffParser.prototype.generateDiffJson = function(diffInput, configuration) { + DiffParser.prototype.generateDiffJson = function (diffInput, configuration) { var config = configuration || {}; var files = []; @@ -198,8 +198,8 @@ /* Diff */ var oldMode = /^old mode (\d{6})/; var newMode = /^new mode (\d{6})/; - var deletedFileMode = /^deleted file mode (\d{6})/; - var newFileMode = /^new file mode (\d{6})/; + var deletedFileMode = /^deleted file mode (\d{5,6})/; + var newFileMode = /^new file mode (\d{5,6})/; var copyFrom = /^copy from "?(.+)"?/; var copyTo = /^copy to "?(.+)"?/; @@ -220,7 +220,45 @@ var combinedNewFile = /^new file mode (\d{6})/; var combinedDeletedFile = /^deleted file mode (\d{6}),(\d{6})/; - diffLines.forEach(function(line, lineIndex) { + var svnNullFileMode = /^(.+)(\s+)(\(nonexistent\))$/; + var svnWithVersionFileMode = /^(.+)(\s+)(\(revision\s+\d+\))$/; + + /* if we use command `svn diff --git`. we wiil get header like that: + * + * ``` + * diff --git a/color_doc.docx b/color_doc.docx + * --- a/color_doc.docx (nonexistent) + * +++ b/color_doc.docx (revision 10) + * ``` + * + * `(nonexistent)` means that file do not exist. + * `(revision 10)` shows the current version of file. When the string exit, this file is in reposity. + */ + function checkSvnFileMode(fileName, isOld) { + var result = null; + if (isOld) { + if (result = svnNullFileMode.exec(fileName)) { + currentFile.oldName = result[1]; + // currentFile.isNew = true; + } else if (result = svnWithVersionFileMode.exec(fileName)) { + currentFile.oldName = result[1]; + } else { + currentFile.oldName = fileName; + } + } else { + if (result = svnNullFileMode.exec(fileName)) { + currentFile.newName = result[1]; + // currentFile.isDeleted = true; + } else if (result = svnWithVersionFileMode.exec(fileName)) { + currentFile.newName = result[1]; + } else { + currentFile.newName = fileName; + } + + } + } + + diffLines.forEach(function (line, lineIndex) { // Unmerged paths, and possibly other non-diffable files // https://github.com/scottgonzalez/pretty-diff/issues/11 // Also, remove some useless lines @@ -280,7 +318,9 @@ */ if (currentFile && !currentFile.oldName && utils.startsWith(line, '--- ') && (values = getSrcFilename(line, config))) { - currentFile.oldName = values; + + checkSvnFileMode(values, true); + // currentFile.oldName = values; currentFile.language = getExtension(currentFile.oldName, currentFile.language); return; } @@ -291,7 +331,8 @@ */ if (currentFile && !currentFile.newName && utils.startsWith(line, '+++ ') && (values = getDstFilename(line, config))) { - currentFile.newName = values; + checkSvnFileMode(values, false); + // currentFile.newName = values; currentFile.language = getExtension(currentFile.newName, currentFile.language); return; } @@ -386,9 +427,57 @@ saveBlock(); saveFile(); + if (configuration.ignoreSvnPropertyChange) + files = dropSvnPropertyChangeFiles(files); return files; }; + /** + * If you use `svn diff --git`, and add or delete a binary file, you will get two file change records in output, like that: + * + * ``` + * =================================================================== + * diff --git a/text.png b/text.png + * deleted file mode 10644 + * GIT binary patch + * ... + * =================================================================== + * diff --git a/text.png b/text.png + * --- a/text.png (revision 15) + * +++ b/text.png (nonexistent) + * + * Property changes on: text.png + * ... + * ``` + * First record for "delete/new" a file. + * Second record for svn property change. + * + * You proberly do not want to see the second record. So will provide an `ignoreSvnPropertyChange` option to do that for you. + */ + function dropSvnPropertyChangeFiles(files) { + const GIT_BINNARY_HEADER = 'GIT binary patch'; + const PROPERTY_CHANGE_HEADER = 'Property changes on:'; + let ret = new Array(); + for (var i = 0; i < files.length - 1; i++) { + let file = files[i]; + let nextFile = files[i + 1]; + + ret.push(file); + if (file.blocks.length > 0 + && utils.startsWith(file.blocks[0].header, GIT_BINNARY_HEADER) + && nextFile.blocks.length > 0 + && utils.startsWith(nextFile.blocks[0].header, PROPERTY_CHANGE_HEADER) + && file.name === nextFile.name + && (file.isDeleted === true || file.isNew === true) + ) { + i += 1; + } + } + + return ret; + } + + function getExtension(filename, language) { var nameSplit = filename.split('.'); if (nameSplit.length > 1) { @@ -398,6 +487,7 @@ return language; } + function getSrcFilename(line, cfg) { return _getFilename('---', line, cfg.srcPrefix); } @@ -423,7 +513,7 @@ var values = FilenameRegExp.exec(line); if (values && values[1]) { filename = values[1]; - var matchingPrefixes = prefixes.filter(function(p) { + var matchingPrefixes = prefixes.filter(function (p) { return filename.indexOf(p) === 0; }); @@ -442,4 +532,6 @@ } module.exports.DiffParser = new DiffParser(); -})(); +}) +(); +