From 4885a0cb804dcaa369ad01dba99aa083da41cd46 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Mon, 21 Oct 2019 16:25:57 +0200 Subject: [PATCH 1/5] Filter git diff stream to decode file names --- .../scm/repository/spi/GitDiffCommand.java | 69 ++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java index 1ac64c1b5e..e568320ad5 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java @@ -33,10 +33,13 @@ package sonia.scm.repository.spi; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.util.QuotedString; import sonia.scm.repository.Repository; import sonia.scm.repository.api.DiffCommandBuilder; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStream; /** * @@ -56,7 +59,7 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand { Differ.Diff diff = Differ.diff(repository, request); return output -> { - try (DiffFormatter formatter = new DiffFormatter(output)) { + try (DiffFormatter formatter = new DiffFormatter(new DequoteOutputStream(output))) { formatter.setRepository(repository); for (DiffEntry e : diff.getEntries()) { @@ -70,4 +73,68 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand { }; } + private static class DequoteOutputStream extends OutputStream { + + private final OutputStream target; + + private boolean afterNL = false; + private int minusCount = 0; + private int plusCount = 0; + private ByteArrayOutputStream buffer; + + private DequoteOutputStream(OutputStream target) { + this.target = target; + } + + @Override + public void write(int i) throws IOException { + if (i == (int) '+' && afterNL) { + plusCount = 1; + afterNL = false; + target.write(i); + } else if (i == (int) '+' && plusCount > 0) { + ++plusCount; + afterNL = false; + target.write(i); + } else if (i == (int) '-' && afterNL) { + minusCount = 1; + afterNL = false; + target.write(i); + } else if (i == (int) '-' && minusCount > 0) { + ++minusCount; + afterNL = false; + target.write(i); + } else if (i == (int) ' ' && plusCount == 3) { + buffer = new ByteArrayOutputStream(); + afterNL = false; + plusCount = 0; + target.write(i); + } else if (i == (int) ' ' && minusCount == 3) { + minusCount = 0; + afterNL = false; + buffer = new ByteArrayOutputStream(); + target.write(i); + } else if (buffer != null) { + if (i == (int) '\n') { + afterNL = true; + byte[] bytes = buffer.toByteArray(); + String dequote = QuotedString.GIT_PATH.dequote(bytes, 0, bytes.length); + target.write(dequote.getBytes()); + target.write(i); + buffer = null; + } else { + buffer.write(i); + afterNL = false; + } + } else if (i == (int) '\n') { + afterNL = true; + target.write(i); + } else { + target.write(i); + afterNL = false; + minusCount = 0; + plusCount = 0; + } + } + } } From 7209702643704396bdbbd1672dbcb90609dca528 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Mon, 21 Oct 2019 16:30:57 +0200 Subject: [PATCH 2/5] Rearrange ifs --- .../scm/repository/spi/GitDiffCommand.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java index e568320ad5..0fbe45d3cd 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java @@ -114,8 +114,8 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand { afterNL = false; buffer = new ByteArrayOutputStream(); target.write(i); - } else if (buffer != null) { - if (i == (int) '\n') { + } else if (i == (int) '\n') { + if (buffer != null) { afterNL = true; byte[] bytes = buffer.toByteArray(); String dequote = QuotedString.GIT_PATH.dequote(bytes, 0, bytes.length); @@ -123,17 +123,19 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand { target.write(i); buffer = null; } else { + afterNL = true; + target.write(i); + } + } else { + if (buffer != null) { buffer.write(i); afterNL = false; + } else { + target.write(i); + afterNL = false; + minusCount = 0; + plusCount = 0; } - } else if (i == (int) '\n') { - afterNL = true; - target.write(i); - } else { - target.write(i); - afterNL = false; - minusCount = 0; - plusCount = 0; } } } From cbee87fa0c17880f7234092499edc2be709ff5f2 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Mon, 18 Nov 2019 11:41:09 +0100 Subject: [PATCH 3/5] Buffer output and do not create new temp array streams --- .../scm/repository/spi/GitDiffCommand.java | 53 +++++++++++-------- ...itDiffCommand_DequoteOutputStreamTest.java | 35 ++++++++++++ 2 files changed, 65 insertions(+), 23 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitDiffCommand_DequoteOutputStreamTest.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java index 0fbe45d3cd..c165ee550e 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java @@ -37,10 +37,13 @@ import org.eclipse.jgit.util.QuotedString; import sonia.scm.repository.Repository; import sonia.scm.repository.api.DiffCommandBuilder; +import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * * @author Sebastian Sdorra @@ -73,17 +76,19 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand { }; } - private static class DequoteOutputStream extends OutputStream { + static class DequoteOutputStream extends OutputStream { private final OutputStream target; private boolean afterNL = false; + private boolean writeToBuffer = false; private int minusCount = 0; private int plusCount = 0; - private ByteArrayOutputStream buffer; - private DequoteOutputStream(OutputStream target) { - this.target = target; + private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + DequoteOutputStream(OutputStream target) { + this.target = new BufferedOutputStream(target); } @Override @@ -105,38 +110,40 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand { afterNL = false; target.write(i); } else if (i == (int) ' ' && plusCount == 3) { - buffer = new ByteArrayOutputStream(); + writeToBuffer = true; + buffer.reset(); afterNL = false; plusCount = 0; target.write(i); } else if (i == (int) ' ' && minusCount == 3) { minusCount = 0; afterNL = false; - buffer = new ByteArrayOutputStream(); + writeToBuffer = true; + buffer.reset(); target.write(i); } else if (i == (int) '\n') { - if (buffer != null) { - afterNL = true; + afterNL = true; + if (writeToBuffer) { byte[] bytes = buffer.toByteArray(); String dequote = QuotedString.GIT_PATH.dequote(bytes, 0, bytes.length); - target.write(dequote.getBytes()); - target.write(i); - buffer = null; - } else { - afterNL = true; - target.write(i); + target.write(dequote.getBytes(UTF_8)); + writeToBuffer = false; } + target.write(i); + } else if (writeToBuffer) { + buffer.write(i); + afterNL = false; } else { - if (buffer != null) { - buffer.write(i); - afterNL = false; - } else { - target.write(i); - afterNL = false; - minusCount = 0; - plusCount = 0; - } + target.write(i); + afterNL = false; + minusCount = 0; + plusCount = 0; } } + + @Override + public void flush() throws IOException { + target.flush(); + } } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitDiffCommand_DequoteOutputStreamTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitDiffCommand_DequoteOutputStreamTest.java new file mode 100644 index 0000000000..790bb34b4e --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitDiffCommand_DequoteOutputStreamTest.java @@ -0,0 +1,35 @@ +package sonia.scm.repository.spi; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class GitDiffCommand_DequoteOutputStreamTest { + + @Test + void shouldDequoteText() throws IOException { + String s = "diff --git \"a/\\303\\272\\303\\274\\303\\276\\303\\253\\303\\251\\303\\245\\303\\253\\303\\245\\303\\251 \\303\\245g\\303\\260f\\303\\237\" \"b/\\303\\272\\303\\274\\303\\276\\303\\253\\303\\251\\303\\245\\303\\253\\303\\245\\303\\251 \\303\\245g\\303\\260f\\303\\237\"\n" + + "new file mode 100644\n" + + "index 0000000..8cb0607\n" + + "--- /dev/null\n" + + "+++ \"b/\\303\\272\\303\\274\\303\\276\\303\\253\\303\\251\\303\\245\\303\\253\\303\\245\\303\\251 \\303\\245g\\303\\260f\\303\\237\"\n" + + "@@ -0,0 +1 @@\n" + + "+rthms"; + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + GitDiffCommand.DequoteOutputStream stream = new GitDiffCommand.DequoteOutputStream(buffer); + byte[] bytes = s.getBytes(); + stream.write(bytes, 0, bytes.length); + stream.flush(); + + Assertions.assertThat(buffer.toString()).isEqualTo("diff --git \"a/\\303\\272\\303\\274\\303\\276\\303\\253\\303\\251\\303\\245\\303\\253\\303\\245\\303\\251 \\303\\245g\\303\\260f\\303\\237\" \"b/\\303\\272\\303\\274\\303\\276\\303\\253\\303\\251\\303\\245\\303\\253\\303\\245\\303\\251 \\303\\245g\\303\\260f\\303\\237\"\n" + + "new file mode 100644\n" + + "index 0000000..8cb0607\n" + + "--- /dev/null\n" + + "+++ b/úüþëéåëåé ågðfß\n" + + "@@ -0,0 +1 @@\n" + + "+rthms"); + } +} From f960bbd0b9110534c8ce50bef210f528ac304e06 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Mon, 18 Nov 2019 12:51:16 +0100 Subject: [PATCH 4/5] Replace quotes in git command line, too --- .../scm/repository/spi/GitDiffCommand.java | 130 ++++++++++++------ ...itDiffCommand_DequoteOutputStreamTest.java | 4 +- 2 files changed, 87 insertions(+), 47 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java index c165ee550e..d6203f2a1b 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitDiffCommand.java @@ -45,7 +45,6 @@ import java.io.OutputStream; import static java.nio.charset.StandardCharsets.UTF_8; /** - * * @author Sebastian Sdorra */ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand { @@ -57,7 +56,7 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand { @Override public DiffCommandBuilder.OutputStreamConsumer getDiffResult(DiffCommandRequest request) throws IOException { @SuppressWarnings("squid:S2095") // repository will be closed with the RepositoryService - org.eclipse.jgit.lib.Repository repository = open(); + org.eclipse.jgit.lib.Repository repository = open(); Differ.Diff diff = Differ.diff(repository, request); @@ -78,12 +77,19 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand { static class DequoteOutputStream extends OutputStream { + private static final String[] DEQUOTE_STARTS = { + "--- ", + "+++ ", + "diff --git " + }; + private final OutputStream target; - private boolean afterNL = false; + private boolean afterNL = true; private boolean writeToBuffer = false; - private int minusCount = 0; - private int plusCount = 0; + private int numberOfPotentialBeginning = -1; + private int potentialBeginningCharCount = 0; + private boolean inPotentialQuotedLine = false; private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); @@ -93,54 +99,88 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand { @Override public void write(int i) throws IOException { - if (i == (int) '+' && afterNL) { - plusCount = 1; + if (i == (int) '\n') { + handleNewLine(i); + return; + } + + if (afterNL) { afterNL = false; - target.write(i); - } else if (i == (int) '+' && plusCount > 0) { - ++plusCount; - afterNL = false; - target.write(i); - } else if (i == (int) '-' && afterNL) { - minusCount = 1; - afterNL = false; - target.write(i); - } else if (i == (int) '-' && minusCount > 0) { - ++minusCount; - afterNL = false; - target.write(i); - } else if (i == (int) ' ' && plusCount == 3) { - writeToBuffer = true; - buffer.reset(); - afterNL = false; - plusCount = 0; - target.write(i); - } else if (i == (int) ' ' && minusCount == 3) { - minusCount = 0; - afterNL = false; - writeToBuffer = true; - buffer.reset(); - target.write(i); - } else if (i == (int) '\n') { - afterNL = true; - if (writeToBuffer) { - byte[] bytes = buffer.toByteArray(); - String dequote = QuotedString.GIT_PATH.dequote(bytes, 0, bytes.length); - target.write(dequote.getBytes(UTF_8)); - writeToBuffer = false; + if (foundPotentialBeginning(i)) { + return; } - target.write(i); - } else if (writeToBuffer) { + numberOfPotentialBeginning = -1; + } + + if (inPotentialQuotedLine && i == '"') { + handleQuote(); + return; + } + + if (numberOfPotentialBeginning > -1 && checkForFurtherBeginning(i)) { + return; + } + + if (writeToBuffer) { buffer.write(i); - afterNL = false; } else { target.write(i); - afterNL = false; - minusCount = 0; - plusCount = 0; } } + private boolean checkForFurtherBeginning(int i) throws IOException { + if (i == DEQUOTE_STARTS[numberOfPotentialBeginning].charAt(potentialBeginningCharCount)) { + if (potentialBeginningCharCount + 1 < DEQUOTE_STARTS[numberOfPotentialBeginning].length()) { + ++potentialBeginningCharCount; + } else { + inPotentialQuotedLine = true; + } + target.write(i); + return true; + } else { + numberOfPotentialBeginning = -1; + } + return false; + } + + private boolean foundPotentialBeginning(int i) throws IOException { + for (int n = 0; n < DEQUOTE_STARTS.length; ++n) { + if (i == DEQUOTE_STARTS[n].charAt(0)) { + numberOfPotentialBeginning = n; + potentialBeginningCharCount = 1; + target.write(i); + return true; + } + } + return false; + } + + private void handleQuote() throws IOException { + if (writeToBuffer) { + buffer.write('"'); + dequoteBuffer(); + } else { + writeToBuffer = true; + buffer.reset(); + buffer.write('"'); + } + } + + private void handleNewLine(int i) throws IOException { + afterNL = true; + if (writeToBuffer) { + dequoteBuffer(); + } + target.write(i); + } + + private void dequoteBuffer() throws IOException { + byte[] bytes = buffer.toByteArray(); + String dequote = QuotedString.GIT_PATH.dequote(bytes, 0, bytes.length); + target.write(dequote.getBytes(UTF_8)); + writeToBuffer = false; + } + @Override public void flush() throws IOException { target.flush(); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitDiffCommand_DequoteOutputStreamTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitDiffCommand_DequoteOutputStreamTest.java index 790bb34b4e..8eaab4fc16 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitDiffCommand_DequoteOutputStreamTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitDiffCommand_DequoteOutputStreamTest.java @@ -10,7 +10,7 @@ public class GitDiffCommand_DequoteOutputStreamTest { @Test void shouldDequoteText() throws IOException { - String s = "diff --git \"a/\\303\\272\\303\\274\\303\\276\\303\\253\\303\\251\\303\\245\\303\\253\\303\\245\\303\\251 \\303\\245g\\303\\260f\\303\\237\" \"b/\\303\\272\\303\\274\\303\\276\\303\\253\\303\\251\\303\\245\\303\\253\\303\\245\\303\\251 \\303\\245g\\303\\260f\\303\\237\"\n" + + String s = "diff --git \"a/file \\303\\272\\303\\274\\303\\276\\303\\253\\303\\251\\303\\245\\303\\253\\303\\245\\303\\251 a\" \"b/file \\303\\272\\303\\274\\303\\276\\303\\253\\303\\251\\303\\245\\303\\253\\303\\245\\303\\251 b\"\n" + "new file mode 100644\n" + "index 0000000..8cb0607\n" + "--- /dev/null\n" + @@ -24,7 +24,7 @@ public class GitDiffCommand_DequoteOutputStreamTest { stream.write(bytes, 0, bytes.length); stream.flush(); - Assertions.assertThat(buffer.toString()).isEqualTo("diff --git \"a/\\303\\272\\303\\274\\303\\276\\303\\253\\303\\251\\303\\245\\303\\253\\303\\245\\303\\251 \\303\\245g\\303\\260f\\303\\237\" \"b/\\303\\272\\303\\274\\303\\276\\303\\253\\303\\251\\303\\245\\303\\253\\303\\245\\303\\251 \\303\\245g\\303\\260f\\303\\237\"\n" + + Assertions.assertThat(buffer.toString()).isEqualTo("diff --git a/file úüþëéåëåé a b/file úüþëéåëåé b\n" + "new file mode 100644\n" + "index 0000000..8cb0607\n" + "--- /dev/null\n" + From e9856b1643fd0de48af6b3ae5440cd9db8c9d59d Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 18 Nov 2019 15:05:36 +0000 Subject: [PATCH 5/5] Close branch bugfix/decode_git_filenames_in_diff