diff --git a/pom.xml b/pom.xml index 200c4d1..82ccd48 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,12 @@ + + org.assertj + assertj-core + 3.11.1 + test + diff --git a/src/main/java/com/github/difflib/unifieddiff/UnifiedDiff.java b/src/main/java/com/github/difflib/unifieddiff/UnifiedDiff.java index 9fb5184..76bd274 100644 --- a/src/main/java/com/github/difflib/unifieddiff/UnifiedDiff.java +++ b/src/main/java/com/github/difflib/unifieddiff/UnifiedDiff.java @@ -15,30 +15,33 @@ */ package com.github.difflib.unifieddiff; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.logging.Logger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * * @author Tobias Warneke (t.warneke@gmx.net) */ -public final class UnifiedDiff { +public class UnifiedDiff { - private UnifiedDiff(InputStream stream) throws IOException { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream));) { - while (reader.ready()) { - String line = reader.readLine(); - LOG.info(line); - } - } + private String header; + private final List files = new ArrayList<>(); + public String getHeader() { + return header; } - private static final Logger LOG = Logger.getLogger(UnifiedDiff.class.getName()); - public static UnifiedDiff parse(InputStream stream) throws IOException { - return new UnifiedDiff(stream); + public void setHeader(String header) { + this.header = header; } + + void addFile(UnifiedDiffFile file) { + files.add(file); + } + + public List getFiles() { + return Collections.unmodifiableList(files); + } + } diff --git a/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffFile.java b/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffFile.java new file mode 100644 index 0000000..c1faa5a --- /dev/null +++ b/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffFile.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019 java-diff-utils. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.difflib.unifieddiff; + +/** + * + * @author Tobias Warneke (t.warneke@gmx.net) + */ +public class UnifiedDiffFile { + + private String diffCommand; + private String fromFile; + private String toFile; + private String index; + + public String getDiffCommand() { + return diffCommand; + } + + public void setDiffCommand(String diffCommand) { + this.diffCommand = diffCommand; + } + + public String getFromFile() { + return fromFile; + } + + public void setFromFile(String fromFile) { + this.fromFile = fromFile; + } + + public String getToFile() { + return toFile; + } + + public void setToFile(String toFile) { + this.toFile = toFile; + } + + public void setIndex(String index) { + this.index = index; + } + + public String getIndex() { + return index; + } +} diff --git a/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffParser.java b/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffParser.java new file mode 100644 index 0000000..26194f1 --- /dev/null +++ b/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffParser.java @@ -0,0 +1,167 @@ +/* + * Copyright 2019 java-diff-utils. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.difflib.unifieddiff; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.function.BiConsumer; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * @author Tobias Warneke (t.warneke@gmx.net) + */ +public final class UnifiedDiffParser { + + private final UnifiedDiffReader READER; + private final UnifiedDiff data = new UnifiedDiff(); + private final UnifiedDiffLine[] PARSER_RULES = new UnifiedDiffLine[]{ + new UnifiedDiffLine("^\\s+", (m, l) -> LOG.info("normal " + l)), + new UnifiedDiffLine(true, "^diff\\s", UnifiedDiffParser::processDiff), + new UnifiedDiffLine(true, "^index\\s[\\da-zA-Z]+\\.\\.[\\da-zA-Z]+(\\s(\\d+))?$", UnifiedDiffParser::processIndex) + }; + private UnifiedDiffFile actualFile; + + UnifiedDiffParser(Reader reader) { + this.READER = new UnifiedDiffReader(reader); + } + + // schema = [[/^\s+/, normal], [/^diff\s/, start], [/^new file mode \d+$/, new_file], + // [/^deleted file mode \d+$/, deleted_file], [/^index\s[\da-zA-Z]+\.\.[\da-zA-Z]+(\s(\d+))?$/, index], + // [/^---\s/, from_file], [/^\+\+\+\s/, to_file], [/^@@\s+\-(\d+),?(\d+)?\s+\+(\d+),?(\d+)?\s@@/, chunk], + // [/^-/, del], [/^\+/, add], [/^\\ No newline at end of file$/, eof]]; + private UnifiedDiff parse() throws IOException { + boolean header = true; + String headerTxt = ""; + while (READER.ready()) { + String line = READER.readLine(); + if (processLine(header, line) == false) { + if (header) { + headerTxt += line + "\n"; + } else { + break; + } + } else { + header = false; + data.setHeader(headerTxt); + } + } + return data; + } + + static String[] parseFileNames(String line) { + String[] split = line.split(" "); + return new String[]{ + split[2].replaceAll("^a/", ""), + split[3].replaceAll("^b/", "") + }; + } + + private static final Logger LOG = Logger.getLogger(UnifiedDiffParser.class.getName()); + + public static UnifiedDiff parseUnifiedDiff(InputStream stream) throws IOException { + UnifiedDiffParser parser = new UnifiedDiffParser(new BufferedReader(new InputStreamReader(stream))); + return parser.parse(); + } + + private boolean processLine(boolean header, String line) { + for (UnifiedDiffLine rule : PARSER_RULES) { + if (header && rule.isStopsHeaderParsing() || !header) { + if (rule.processLine(line)) { + return true; + } + } + } + return false; + } + + private void initFileIfNecessary() { + if (actualFile == null) { + actualFile = new UnifiedDiffFile(); + } + } + + private void processDiff(MatchResult match, String line) { + initFileIfNecessary(); + LOG.log(Level.INFO, "start {0}", line); + String[] fromTo = parseFileNames(READER.lastLine()); + actualFile.setFromFile(fromTo[0]); + actualFile.setToFile(fromTo[1]); + } + + private void processIndex(MatchResult match, String line) { + initFileIfNecessary(); + LOG.log(Level.INFO, "index {0}", line); + actualFile.setIndex(line.substring(6)); + } + + class UnifiedDiffLine { + + private final Pattern pattern; + private final BiConsumer command; + private final boolean stopsHeaderParsing; + + public UnifiedDiffLine(String pattern, BiConsumer command) { + this(false, pattern, command); + } + + public UnifiedDiffLine(boolean stopsHeaderParsing, String pattern, BiConsumer command) { + this.pattern = Pattern.compile(pattern); + this.command = command; + this.stopsHeaderParsing = stopsHeaderParsing; + } + + public boolean processLine(String line) { + Matcher m = pattern.matcher(line); + if (m.find()) { + command.accept(m.toMatchResult(), line); + return true; + } else { + return false; + } + } + + public boolean isStopsHeaderParsing() { + return stopsHeaderParsing; + } + } +} + +class UnifiedDiffReader extends BufferedReader { + + private String lastLine; + + public UnifiedDiffReader(Reader reader) { + super(reader); + } + + @Override + public String readLine() throws IOException { + lastLine = super.readLine(); + return lastLine(); + } + + String lastLine() { + return lastLine; + } +} diff --git a/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffTest.java b/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffParserTest.java similarity index 62% rename from src/test/java/com/github/difflib/unifieddiff/UnifiedDiffTest.java rename to src/test/java/com/github/difflib/unifieddiff/UnifiedDiffParserTest.java index 380eb8e..9eb6e05 100644 --- a/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffTest.java +++ b/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffParserTest.java @@ -16,6 +16,7 @@ package com.github.difflib.unifieddiff; import java.io.IOException; +import static org.assertj.core.api.Java6Assertions.assertThat; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -26,9 +27,9 @@ import org.junit.Test; * * @author Tobias Warneke (t.warneke@gmx.net) */ -public class UnifiedDiffTest { +public class UnifiedDiffParserTest { - public UnifiedDiffTest() { + public UnifiedDiffParserTest() { } @BeforeClass @@ -49,9 +50,15 @@ public class UnifiedDiffTest { @Test public void testSimpleParse() throws IOException { - UnifiedDiff diff = UnifiedDiff.parse(UnifiedDiffTest.class.getResourceAsStream("jsqlparser_patch_1.diff")); + UnifiedDiff diff = UnifiedDiffParser.parseUnifiedDiff(UnifiedDiffParserTest.class.getResourceAsStream("jsqlparser_patch_1.diff")); System.out.println(diff); } + @Test + public void testParseDiffBlock() { + String[] files = UnifiedDiffParser.parseFileNames("diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java"); + assertThat(files).containsExactly("src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java", "src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java"); + } + }