summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Wolf <twolf@apache.org>2022-12-16 23:23:03 +0100
committerThomas Wolf <twolf@apache.org>2022-12-26 11:51:25 +0100
commit9a6d6024884300929edba63465ea12d260276f90 (patch)
tree354e36e8ece258b6d6bb87717a1c9d142b9de6b4
parentaeb74f63d431fb1799ef474045935aada5f3418a (diff)
downloadjgit-9a6d6024884300929edba63465ea12d260276f90.tar.gz
jgit-9a6d6024884300929edba63465ea12d260276f90.zip
PatchApplier: fix handling of last newline in text patch
If the last line came from the patch, use the patch to determine whether or not there should be a trailing newline. Otherwise use the old text. Add test cases for - no newline at end, last line not in patch hunk - no newline at end, last line in patch hunk - patch removing the last newline - patch adding a newline at the end of file not having one all for core.autocrlf false, true, and input. Add a test case where the "no newline" indicator line is not the last line of the last hunk. This can happen if the patch ends with removals at the file end. Bug: 581234 Change-Id: I09d079b51479b89400ad300d0662c1dcb50deab6 Also-by: Yuriy Mitrofanov <a2terminator@mail.ru> Signed-off-by: Thomas Wolf <twolf@apache.org>
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl.patch11
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_PostImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_PreImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf.patch11
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf_PostImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf_PreImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d.patch13
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_PostImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_PreImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf.patch13
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf_PostImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf_PreImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e.patch14
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_PostImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_PreImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf.patch14
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf_PostImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf_PreImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl.patch15
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_PostImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_PreImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf.patch15
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf_PostImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf_PreImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e.patch297
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_PostImage233
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_PreImage209
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl.patch17
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl_PostImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl_PreImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl.patch18
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl_PostImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl_PreImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl.patch17
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl_PostImage8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl_PreImage8
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java261
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/patch/PatchApplier.java42
38 files changed, 1358 insertions, 18 deletions
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl.patch
new file mode 100644
index 0000000000..444f7f7438
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl.patch
@@ -0,0 +1,11 @@
+diff --git a/x_add_nl b/x_add_nl
+index 33a3e0e..71ac1b5 100644
+--- a/x_add_nl
++++ b/x_add_nl
+@@ -5,4 +5,4 @@ d
+ e
+ f
+ g
+-h
+\ No newline at end of file
++h
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_PostImage
new file mode 100644
index 0000000000..71ac1b5791
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_PostImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_PreImage
new file mode 100644
index 0000000000..33a3e0ed4d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_PreImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf.patch
new file mode 100644
index 0000000000..503d34562f
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf.patch
@@ -0,0 +1,11 @@
+diff --git a/x_add_nl_crlf b/x_add_nl_crlf
+index 33a3e0e..71ac1b5 100644
+--- a/x_add_nl_crlf
++++ b/x_add_nl_crlf
+@@ -5,4 +5,4 @@ d
+ e
+ f
+ g
+-h
+\ No newline at end of file
++h
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf_PostImage
new file mode 100644
index 0000000000..95801b09e9
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf_PostImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf_PreImage
new file mode 100644
index 0000000000..a8a98da26c
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_add_nl_crlf_PreImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d.patch
new file mode 100644
index 0000000000..cc9025608c
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d.patch
@@ -0,0 +1,13 @@
+diff --git a/x_d b/x_d
+index 33a3e0e..9d2bc43 100644
+--- a/x_d
++++ b/x_d
+@@ -1,7 +1,7 @@
+ a
+ b
+ c
+-d
++D
+ e
+ f
+ g
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_PostImage
new file mode 100644
index 0000000000..9d2bc43600
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_PostImage
@@ -0,0 +1,8 @@
+a
+b
+c
+D
+e
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_PreImage
new file mode 100644
index 0000000000..33a3e0ed4d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_PreImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf.patch
new file mode 100644
index 0000000000..8ec3f8b105
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf.patch
@@ -0,0 +1,13 @@
+diff --git a/x_d_crlf b/x_d_crlf
+index 33a3e0e..9d2bc43 100644
+--- a/x_d_crlf
++++ b/x_d_crlf
+@@ -1,7 +1,7 @@
+ a
+ b
+ c
+-d
++D
+ e
+ f
+ g
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf_PostImage
new file mode 100644
index 0000000000..ecae1d61cd
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf_PostImage
@@ -0,0 +1,8 @@
+a
+b
+c
+D
+e
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf_PreImage
new file mode 100644
index 0000000000..a8a98da26c
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_d_crlf_PreImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e.patch
new file mode 100644
index 0000000000..413e4f88e9
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e.patch
@@ -0,0 +1,14 @@
+diff --git a/x_e b/x_e
+index 33a3e0e..b3ab996 100644
+--- a/x_e
++++ b/x_e
+@@ -2,7 +2,7 @@ a
+ b
+ c
+ d
+-e
++E
+ f
+ g
+ h
+\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_PostImage
new file mode 100644
index 0000000000..b3ab996d14
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_PostImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+E
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_PreImage
new file mode 100644
index 0000000000..33a3e0ed4d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_PreImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf.patch
new file mode 100644
index 0000000000..e674454220
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf.patch
@@ -0,0 +1,14 @@
+diff --git a/x_e_crlf b/x_e_crlf
+index 33a3e0e..b3ab996 100644
+--- a/x_e_crlf
++++ b/x_e_crlf
+@@ -2,7 +2,7 @@ a
+ b
+ c
+ d
+-e
++E
+ f
+ g
+ h
+\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf_PostImage
new file mode 100644
index 0000000000..d327752d12
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf_PostImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+E
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf_PreImage
new file mode 100644
index 0000000000..a8a98da26c
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_e_crlf_PreImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl.patch
new file mode 100644
index 0000000000..34ed246378
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl.patch
@@ -0,0 +1,15 @@
+diff --git a/x_last_rm_nl b/x_last_rm_nl
+index 71ac1b5..b3ab996 100644
+--- a/x_last_rm_nl
++++ b/x_last_rm_nl
+@@ -2,7 +2,7 @@ a
+ b
+ c
+ d
+-e
++E
+ f
+ g
+-h
++h
+\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_PostImage
new file mode 100644
index 0000000000..b3ab996d14
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_PostImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+E
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_PreImage
new file mode 100644
index 0000000000..71ac1b5791
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_PreImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf.patch
new file mode 100644
index 0000000000..3f74024ec0
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf.patch
@@ -0,0 +1,15 @@
+diff --git a/x_last_rm_nl_crlf b/x_last_rm_nl_crlf
+index 71ac1b5..b3ab996 100644
+--- a/x_last_rm_nl_crlf
++++ b/x_last_rm_nl_crlf
+@@ -2,7 +2,7 @@ a
+ b
+ c
+ d
+-e
++E
+ f
+ g
+-h
++h
+\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf_PostImage
new file mode 100644
index 0000000000..d327752d12
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf_PostImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+E
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf_PreImage
new file mode 100644
index 0000000000..95801b09e9
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/x_last_rm_nl_crlf_PreImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e.patch
new file mode 100644
index 0000000000..f531033845
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e.patch
@@ -0,0 +1,297 @@
+diff --git a/z_e b/z_e
+index 8d8786f..7888356 100644
+--- a/z_e
++++ b/z_e
+@@ -20,6 +20,7 @@
+ package org.jsonschema2pojo.util;
+
+ import java.util.ArrayList;
++import java.util.Collections;
+ import java.util.List;
+ import java.util.regex.Matcher;
+ import java.util.regex.Pattern;
+@@ -36,76 +37,81 @@
+ private static final Pattern UNDERSCORE_PATTERN_1 = Pattern.compile("([A-Z]+)([A-Z][a-z])");
+ private static final Pattern UNDERSCORE_PATTERN_2 = Pattern.compile("([a-z\\d])([A-Z])");
+
+- private List<RuleAndReplacement> plurals = new ArrayList<RuleAndReplacement>();
+- private List<RuleAndReplacement> singulars = new ArrayList<RuleAndReplacement>();
+- private List<String> uncountables = new ArrayList<String>();
++ private final List<RuleAndReplacement> plurals;
++ private final List<RuleAndReplacement> singulars;
++ private final List<String> uncountables;
+
+- private static Inflector instance = new Inflector();
++ private static Inflector instance = createDefaultBuilder().build();
+
+- private Inflector() {
+- // Woo, you can't touch me.
+-
+- initialize();
++ private Inflector(Builder builder) {
++ plurals = Collections.unmodifiableList(builder.plurals);
++ singulars = Collections.unmodifiableList(builder.singulars);
++ uncountables = Collections.unmodifiableList(builder.uncountables);
+ }
+
+- private void initialize() {
+- plural("$", "s");
+- plural("s$", "s");
+- plural("(ax|test)is$", "$1es");
+- plural("(octop|vir)us$", "$1i");
+- plural("(alias|status)$", "$1es");
+- plural("(bu)s$", "$1es");
+- plural("(buffal|tomat)o$", "$1oes");
+- plural("([ti])um$", "$1a");
+- plural("sis$", "ses");
+- plural("(?:([^f])fe|([lr])f)$", "$1$2ves");
+- plural("(hive)$", "$1s");
+- plural("([^aeiouy]|qu)y$", "$1ies");
+- plural("([^aeiouy]|qu)ies$", "$1y");
+- plural("(x|ch|ss|sh)$", "$1es");
+- plural("(matr|vert|ind)ix|ex$", "$1ices");
+- plural("([m|l])ouse$", "$1ice");
+- plural("(ox)$", "$1en");
+- plural("(quiz)$", "$1zes");
++ public static Inflector.Builder createDefaultBuilder()
++ {
++ Builder builder = builder();
+
+- singular("s$", "");
+- singular("(n)ews$", "$1ews");
+- singular("([ti])a$", "$1um");
+- singular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis");
+- singular("(^analy)ses$", "$1sis");
+- singular("([^f])ves$", "$1fe");
+- singular("(hive)s$", "$1");
+- singular("(tive)s$", "$1");
+- singular("([lr])ves$", "$1f");
+- singular("([^aeiouy]|qu)ies$", "$1y");
+- singular("(s)eries$", "$1eries");
+- singular("(m)ovies$", "$1ovie");
+- singular("(x|ch|ss|sh)es$", "$1");
+- singular("([m|l])ice$", "$1ouse");
+- singular("(bus)es$", "$1");
+- singular("(o)es$", "$1");
+- singular("(shoe)s$", "$1");
+- singular("(cris|ax|test)es$", "$1is");
+- singular("([octop|vir])i$", "$1us");
+- singular("(alias|status)es$", "$1");
+- singular("^(ox)en", "$1");
+- singular("(vert|ind)ices$", "$1ex");
+- singular("(matr)ices$", "$1ix");
+- singular("(quiz)zes$", "$1");
+- singular("(ess)$", "$1");
++ builder.plural("$", "s")
++ .plural("s$", "s")
++ .plural("(ax|test)is$", "$1es")
++ .plural("(octop|vir)us$", "$1i")
++ .plural("(alias|status)$", "$1es")
++ .plural("(bu)s$", "$1es")
++ .plural("(buffal|tomat)o$", "$1oes")
++ .plural("([ti])um$", "$1a")
++ .plural("sis$", "ses")
++ .plural("(?:([^f])fe|([lr])f)$", "$1$2ves")
++ .plural("(hive)$", "$1s")
++ .plural("([^aeiouy]|qu)y$", "$1ies")
++ .plural("([^aeiouy]|qu)ies$", "$1y")
++ .plural("(x|ch|ss|sh)$", "$1es")
++ .plural("(matr|vert|ind)ix|ex$", "$1ices")
++ .plural("([m|l])ouse$", "$1ice")
++ .plural("(ox)$", "$1en")
++ .plural("(quiz)$", "$1zes");
+
+- singular("men$", "man");
+- plural("man$", "men");
++ builder.singular("s$", "")
++ .singular("(n)ews$", "$1ews")
++ .singular("([ti])a$", "$1um")
++ .singular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis")
++ .singular("(^analy)ses$", "$1sis")
++ .singular("([^f])ves$", "$1fe")
++ .singular("(hive)s$", "$1")
++ .singular("(tive)s$", "$1")
++ .singular("([lr])ves$", "$1f")
++ .singular("([^aeiouy]|qu)ies$", "$1y")
++ .singular("(s)eries$", "$1eries")
++ .singular("(m)ovies$", "$1ovie")
++ .singular("(x|ch|ss|sh)es$", "$1")
++ .singular("([m|l])ice$", "$1ouse")
++ .singular("(bus)es$", "$1")
++ .singular("(o)es$", "$1")
++ .singular("(shoe)s$", "$1")
++ .singular("(cris|ax|test)es$", "$1is")
++ .singular("([octop|vir])i$", "$1us")
++ .singular("(alias|status)es$", "$1")
++ .singular("^(ox)en", "$1")
++ .singular("(vert|ind)ices$", "$1ex")
++ .singular("(matr)ices$", "$1ix")
++ .singular("(quiz)zes$", "$1")
++ .singular("(ess)$", "$1");
+
+- irregular("curve", "curves");
+- irregular("leaf", "leaves");
+- irregular("roof", "rooves");
+- irregular("person", "people");
+- irregular("child", "children");
+- irregular("sex", "sexes");
+- irregular("move", "moves");
++ builder.singular("men$", "man")
++ .plural("man$", "men");
+
+- uncountable(new String[] { "equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "s" });
++ builder.irregular("curve", "curves")
++ .irregular("leaf", "leaves")
++ .irregular("roof", "rooves")
++ .irregular("person", "people")
++ .irregular("child", "children")
++ .irregular("sex", "sexes")
++ .irregular("move", "moves");
++
++ builder.uncountable(new String[] { "equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "s" });
++
++ return builder;
+ }
+
+ public static Inflector getInstance() {
+@@ -122,28 +128,27 @@
+ return underscoredWord;
+ }
+
+- public synchronized String pluralize(String word) {
++ public String pluralize(String word) {
+ if (uncountables.contains(word.toLowerCase())) {
+ return word;
+ }
+ return replaceWithFirstRule(word, plurals);
+ }
+
+- public synchronized String singularize(String word) {
++ public String singularize(String word) {
+ if (uncountables.contains(word.toLowerCase())) {
+ return word;
+ }
+ return replaceWithFirstRule(word, singulars);
+ }
+
+- private String replaceWithFirstRule(String word, List<RuleAndReplacement> ruleAndReplacements) {
++ private static String replaceWithFirstRule(String word, List<RuleAndReplacement> ruleAndReplacements) {
+
+ for (RuleAndReplacement rar : ruleAndReplacements) {
+- String rule = rar.getRule();
+ String replacement = rar.getReplacement();
+
+ // Return if we find a match.
+- Matcher matcher = Pattern.compile(rule, Pattern.CASE_INSENSITIVE).matcher(word);
++ Matcher matcher = rar.getPattern().matcher(word);
+ if (matcher.find()) {
+ return matcher.replaceAll(replacement);
+ }
+@@ -161,49 +166,68 @@
+ return tableize(className);
+ }
+
+- private void plural(String rule, String replacement) {
+- plurals.add(0, new RuleAndReplacement(rule, replacement));
++ public static Builder builder()
++ {
++ return new Builder();
+ }
+
+- private void singular(String rule, String replacement) {
+- singulars.add(0, new RuleAndReplacement(rule, replacement));
++ // Ugh, no open structs in Java (not-natively at least).
++ private static class RuleAndReplacement {
++ private final String rule;
++ private final String replacement;
++ private final Pattern pattern;
++
++ public RuleAndReplacement(String rule, String replacement) {
++ this.rule = rule;
++ this.replacement = replacement;
++ this.pattern = Pattern.compile(rule, Pattern.CASE_INSENSITIVE);
++ }
++
++ public String getReplacement() {
++ return replacement;
++ }
++
++ public String getRule() {
++ return rule;
++ }
++
++ public Pattern getPattern() {
++ return pattern;
++ }
+ }
+
+- private void irregular(String singular, String plural) {
+- plural(singular, plural);
+- singular(plural, singular);
+- }
++ public static class Builder
++ {
++ private List<RuleAndReplacement> plurals = new ArrayList<RuleAndReplacement>();
++ private List<RuleAndReplacement> singulars = new ArrayList<RuleAndReplacement>();
++ private List<String> uncountables = new ArrayList<String>();
+
+- private void uncountable(String... words) {
+- for (String word : words) {
+- uncountables.add(word);
++ public Builder plural(String rule, String replacement) {
++ plurals.add(0, new RuleAndReplacement(rule, replacement));
++ return this;
++ }
++
++ public Builder singular(String rule, String replacement) {
++ singulars.add(0, new RuleAndReplacement(rule, replacement));
++ return this;
++ }
++
++ public Builder irregular(String singular, String plural) {
++ plural(singular, plural);
++ singular(plural, singular);
++ return this;
++ }
++
++ public Builder uncountable(String... words) {
++ for (String word : words) {
++ uncountables.add(word);
++ }
++ return this;
++ }
++
++ public Inflector build()
++ {
++ return new Inflector(this);
+ }
+ }
+ }
+-
+-// Ugh, no open structs in Java (not-natively at least).
+-class RuleAndReplacement {
+- private String rule;
+- private String replacement;
+-
+- public RuleAndReplacement(String rule, String replacement) {
+- this.rule = rule;
+- this.replacement = replacement;
+- }
+-
+- public String getReplacement() {
+- return replacement;
+- }
+-
+- public void setReplacement(String replacement) {
+- this.replacement = replacement;
+- }
+-
+- public String getRule() {
+- return rule;
+- }
+-
+- public void setRule(String rule) {
+- this.rule = rule;
+- }
+-}
+\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_PostImage
new file mode 100644
index 0000000000..7888356948
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_PostImage
@@ -0,0 +1,233 @@
+/**
+ * Copyright © 2007 Chu Yeow Cheah
+ *
+ * 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.
+ *
+ * Copied verbatim from http://dzone.com/snippets/java-inflections, used
+ * and licensed with express permission from the author Chu Yeow Cheah.
+ */
+
+package org.jsonschema2pojo.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Transforms words (from singular to plural, from camelCase to under_score,
+ * etc.). I got bored of doing Real Work...
+ *
+ * @author chuyeow
+ */
+public class Inflector {
+
+ // Pfft, can't think of a better name, but this is needed to avoid the price of initializing the pattern on each call.
+ private static final Pattern UNDERSCORE_PATTERN_1 = Pattern.compile("([A-Z]+)([A-Z][a-z])");
+ private static final Pattern UNDERSCORE_PATTERN_2 = Pattern.compile("([a-z\\d])([A-Z])");
+
+ private final List<RuleAndReplacement> plurals;
+ private final List<RuleAndReplacement> singulars;
+ private final List<String> uncountables;
+
+ private static Inflector instance = createDefaultBuilder().build();
+
+ private Inflector(Builder builder) {
+ plurals = Collections.unmodifiableList(builder.plurals);
+ singulars = Collections.unmodifiableList(builder.singulars);
+ uncountables = Collections.unmodifiableList(builder.uncountables);
+ }
+
+ public static Inflector.Builder createDefaultBuilder()
+ {
+ Builder builder = builder();
+
+ builder.plural("$", "s")
+ .plural("s$", "s")
+ .plural("(ax|test)is$", "$1es")
+ .plural("(octop|vir)us$", "$1i")
+ .plural("(alias|status)$", "$1es")
+ .plural("(bu)s$", "$1es")
+ .plural("(buffal|tomat)o$", "$1oes")
+ .plural("([ti])um$", "$1a")
+ .plural("sis$", "ses")
+ .plural("(?:([^f])fe|([lr])f)$", "$1$2ves")
+ .plural("(hive)$", "$1s")
+ .plural("([^aeiouy]|qu)y$", "$1ies")
+ .plural("([^aeiouy]|qu)ies$", "$1y")
+ .plural("(x|ch|ss|sh)$", "$1es")
+ .plural("(matr|vert|ind)ix|ex$", "$1ices")
+ .plural("([m|l])ouse$", "$1ice")
+ .plural("(ox)$", "$1en")
+ .plural("(quiz)$", "$1zes");
+
+ builder.singular("s$", "")
+ .singular("(n)ews$", "$1ews")
+ .singular("([ti])a$", "$1um")
+ .singular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis")
+ .singular("(^analy)ses$", "$1sis")
+ .singular("([^f])ves$", "$1fe")
+ .singular("(hive)s$", "$1")
+ .singular("(tive)s$", "$1")
+ .singular("([lr])ves$", "$1f")
+ .singular("([^aeiouy]|qu)ies$", "$1y")
+ .singular("(s)eries$", "$1eries")
+ .singular("(m)ovies$", "$1ovie")
+ .singular("(x|ch|ss|sh)es$", "$1")
+ .singular("([m|l])ice$", "$1ouse")
+ .singular("(bus)es$", "$1")
+ .singular("(o)es$", "$1")
+ .singular("(shoe)s$", "$1")
+ .singular("(cris|ax|test)es$", "$1is")
+ .singular("([octop|vir])i$", "$1us")
+ .singular("(alias|status)es$", "$1")
+ .singular("^(ox)en", "$1")
+ .singular("(vert|ind)ices$", "$1ex")
+ .singular("(matr)ices$", "$1ix")
+ .singular("(quiz)zes$", "$1")
+ .singular("(ess)$", "$1");
+
+ builder.singular("men$", "man")
+ .plural("man$", "men");
+
+ builder.irregular("curve", "curves")
+ .irregular("leaf", "leaves")
+ .irregular("roof", "rooves")
+ .irregular("person", "people")
+ .irregular("child", "children")
+ .irregular("sex", "sexes")
+ .irregular("move", "moves");
+
+ builder.uncountable(new String[] { "equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "s" });
+
+ return builder;
+ }
+
+ public static Inflector getInstance() {
+ return instance;
+ }
+
+ private String underscore(String camelCasedWord) {
+
+ // Regexes in Java are fucking stupid...
+ String underscoredWord = UNDERSCORE_PATTERN_1.matcher(camelCasedWord).replaceAll("$1_$2");
+ underscoredWord = UNDERSCORE_PATTERN_2.matcher(underscoredWord).replaceAll("$1_$2");
+ underscoredWord = underscoredWord.replace('-', '_').toLowerCase();
+
+ return underscoredWord;
+ }
+
+ public String pluralize(String word) {
+ if (uncountables.contains(word.toLowerCase())) {
+ return word;
+ }
+ return replaceWithFirstRule(word, plurals);
+ }
+
+ public String singularize(String word) {
+ if (uncountables.contains(word.toLowerCase())) {
+ return word;
+ }
+ return replaceWithFirstRule(word, singulars);
+ }
+
+ private static String replaceWithFirstRule(String word, List<RuleAndReplacement> ruleAndReplacements) {
+
+ for (RuleAndReplacement rar : ruleAndReplacements) {
+ String replacement = rar.getReplacement();
+
+ // Return if we find a match.
+ Matcher matcher = rar.getPattern().matcher(word);
+ if (matcher.find()) {
+ return matcher.replaceAll(replacement);
+ }
+ }
+ return word;
+ }
+
+ private String tableize(String className) {
+ return pluralize(underscore(className));
+ }
+
+ private String tableize(Class<?> klass) {
+ // Strip away package name - we only want the 'base' class name.
+ String className = klass.getName().replace(klass.getPackage().getName() + ".", "");
+ return tableize(className);
+ }
+
+ public static Builder builder()
+ {
+ return new Builder();
+ }
+
+ // Ugh, no open structs in Java (not-natively at least).
+ private static class RuleAndReplacement {
+ private final String rule;
+ private final String replacement;
+ private final Pattern pattern;
+
+ public RuleAndReplacement(String rule, String replacement) {
+ this.rule = rule;
+ this.replacement = replacement;
+ this.pattern = Pattern.compile(rule, Pattern.CASE_INSENSITIVE);
+ }
+
+ public String getReplacement() {
+ return replacement;
+ }
+
+ public String getRule() {
+ return rule;
+ }
+
+ public Pattern getPattern() {
+ return pattern;
+ }
+ }
+
+ public static class Builder
+ {
+ private List<RuleAndReplacement> plurals = new ArrayList<RuleAndReplacement>();
+ private List<RuleAndReplacement> singulars = new ArrayList<RuleAndReplacement>();
+ private List<String> uncountables = new ArrayList<String>();
+
+ public Builder plural(String rule, String replacement) {
+ plurals.add(0, new RuleAndReplacement(rule, replacement));
+ return this;
+ }
+
+ public Builder singular(String rule, String replacement) {
+ singulars.add(0, new RuleAndReplacement(rule, replacement));
+ return this;
+ }
+
+ public Builder irregular(String singular, String plural) {
+ plural(singular, plural);
+ singular(plural, singular);
+ return this;
+ }
+
+ public Builder uncountable(String... words) {
+ for (String word : words) {
+ uncountables.add(word);
+ }
+ return this;
+ }
+
+ public Inflector build()
+ {
+ return new Inflector(this);
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_PreImage
new file mode 100644
index 0000000000..8d8786f58c
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_PreImage
@@ -0,0 +1,209 @@
+/**
+ * Copyright © 2007 Chu Yeow Cheah
+ *
+ * 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.
+ *
+ * Copied verbatim from http://dzone.com/snippets/java-inflections, used
+ * and licensed with express permission from the author Chu Yeow Cheah.
+ */
+
+package org.jsonschema2pojo.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Transforms words (from singular to plural, from camelCase to under_score,
+ * etc.). I got bored of doing Real Work...
+ *
+ * @author chuyeow
+ */
+public class Inflector {
+
+ // Pfft, can't think of a better name, but this is needed to avoid the price of initializing the pattern on each call.
+ private static final Pattern UNDERSCORE_PATTERN_1 = Pattern.compile("([A-Z]+)([A-Z][a-z])");
+ private static final Pattern UNDERSCORE_PATTERN_2 = Pattern.compile("([a-z\\d])([A-Z])");
+
+ private List<RuleAndReplacement> plurals = new ArrayList<RuleAndReplacement>();
+ private List<RuleAndReplacement> singulars = new ArrayList<RuleAndReplacement>();
+ private List<String> uncountables = new ArrayList<String>();
+
+ private static Inflector instance = new Inflector();
+
+ private Inflector() {
+ // Woo, you can't touch me.
+
+ initialize();
+ }
+
+ private void initialize() {
+ plural("$", "s");
+ plural("s$", "s");
+ plural("(ax|test)is$", "$1es");
+ plural("(octop|vir)us$", "$1i");
+ plural("(alias|status)$", "$1es");
+ plural("(bu)s$", "$1es");
+ plural("(buffal|tomat)o$", "$1oes");
+ plural("([ti])um$", "$1a");
+ plural("sis$", "ses");
+ plural("(?:([^f])fe|([lr])f)$", "$1$2ves");
+ plural("(hive)$", "$1s");
+ plural("([^aeiouy]|qu)y$", "$1ies");
+ plural("([^aeiouy]|qu)ies$", "$1y");
+ plural("(x|ch|ss|sh)$", "$1es");
+ plural("(matr|vert|ind)ix|ex$", "$1ices");
+ plural("([m|l])ouse$", "$1ice");
+ plural("(ox)$", "$1en");
+ plural("(quiz)$", "$1zes");
+
+ singular("s$", "");
+ singular("(n)ews$", "$1ews");
+ singular("([ti])a$", "$1um");
+ singular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis");
+ singular("(^analy)ses$", "$1sis");
+ singular("([^f])ves$", "$1fe");
+ singular("(hive)s$", "$1");
+ singular("(tive)s$", "$1");
+ singular("([lr])ves$", "$1f");
+ singular("([^aeiouy]|qu)ies$", "$1y");
+ singular("(s)eries$", "$1eries");
+ singular("(m)ovies$", "$1ovie");
+ singular("(x|ch|ss|sh)es$", "$1");
+ singular("([m|l])ice$", "$1ouse");
+ singular("(bus)es$", "$1");
+ singular("(o)es$", "$1");
+ singular("(shoe)s$", "$1");
+ singular("(cris|ax|test)es$", "$1is");
+ singular("([octop|vir])i$", "$1us");
+ singular("(alias|status)es$", "$1");
+ singular("^(ox)en", "$1");
+ singular("(vert|ind)ices$", "$1ex");
+ singular("(matr)ices$", "$1ix");
+ singular("(quiz)zes$", "$1");
+ singular("(ess)$", "$1");
+
+ singular("men$", "man");
+ plural("man$", "men");
+
+ irregular("curve", "curves");
+ irregular("leaf", "leaves");
+ irregular("roof", "rooves");
+ irregular("person", "people");
+ irregular("child", "children");
+ irregular("sex", "sexes");
+ irregular("move", "moves");
+
+ uncountable(new String[] { "equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "s" });
+ }
+
+ public static Inflector getInstance() {
+ return instance;
+ }
+
+ private String underscore(String camelCasedWord) {
+
+ // Regexes in Java are fucking stupid...
+ String underscoredWord = UNDERSCORE_PATTERN_1.matcher(camelCasedWord).replaceAll("$1_$2");
+ underscoredWord = UNDERSCORE_PATTERN_2.matcher(underscoredWord).replaceAll("$1_$2");
+ underscoredWord = underscoredWord.replace('-', '_').toLowerCase();
+
+ return underscoredWord;
+ }
+
+ public synchronized String pluralize(String word) {
+ if (uncountables.contains(word.toLowerCase())) {
+ return word;
+ }
+ return replaceWithFirstRule(word, plurals);
+ }
+
+ public synchronized String singularize(String word) {
+ if (uncountables.contains(word.toLowerCase())) {
+ return word;
+ }
+ return replaceWithFirstRule(word, singulars);
+ }
+
+ private String replaceWithFirstRule(String word, List<RuleAndReplacement> ruleAndReplacements) {
+
+ for (RuleAndReplacement rar : ruleAndReplacements) {
+ String rule = rar.getRule();
+ String replacement = rar.getReplacement();
+
+ // Return if we find a match.
+ Matcher matcher = Pattern.compile(rule, Pattern.CASE_INSENSITIVE).matcher(word);
+ if (matcher.find()) {
+ return matcher.replaceAll(replacement);
+ }
+ }
+ return word;
+ }
+
+ private String tableize(String className) {
+ return pluralize(underscore(className));
+ }
+
+ private String tableize(Class<?> klass) {
+ // Strip away package name - we only want the 'base' class name.
+ String className = klass.getName().replace(klass.getPackage().getName() + ".", "");
+ return tableize(className);
+ }
+
+ private void plural(String rule, String replacement) {
+ plurals.add(0, new RuleAndReplacement(rule, replacement));
+ }
+
+ private void singular(String rule, String replacement) {
+ singulars.add(0, new RuleAndReplacement(rule, replacement));
+ }
+
+ private void irregular(String singular, String plural) {
+ plural(singular, plural);
+ singular(plural, singular);
+ }
+
+ private void uncountable(String... words) {
+ for (String word : words) {
+ uncountables.add(word);
+ }
+ }
+}
+
+// Ugh, no open structs in Java (not-natively at least).
+class RuleAndReplacement {
+ private String rule;
+ private String replacement;
+
+ public RuleAndReplacement(String rule, String replacement) {
+ this.rule = rule;
+ this.replacement = replacement;
+ }
+
+ public String getReplacement() {
+ return replacement;
+ }
+
+ public void setReplacement(String replacement) {
+ this.replacement = replacement;
+ }
+
+ public String getRule() {
+ return rule;
+ }
+
+ public void setRule(String rule) {
+ this.rule = rule;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl.patch
new file mode 100644
index 0000000000..0fe4b4593b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl.patch
@@ -0,0 +1,17 @@
+diff --git a/z_e_add_nl b/z_e_add_nl
+index 33a3e0e..274cb0e 100644
+--- a/z_e_add_nl
++++ b/z_e_add_nl
+@@ -2,7 +2,7 @@ a
+ b
+ c
+ d
+-e
+-f
+-g
+-h
+\ No newline at end of file
++E
++F
++G
++H
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl_PostImage
new file mode 100644
index 0000000000..274cb0e649
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl_PostImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+E
+F
+G
+H
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl_PreImage
new file mode 100644
index 0000000000..33a3e0ed4d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_add_nl_PreImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl.patch
new file mode 100644
index 0000000000..bce13e463e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl.patch
@@ -0,0 +1,18 @@
+diff --git a/z_e_no_nl b/z_e_no_nl
+index 33a3e0e..234fedc 100644
+--- a/z_e_no_nl
++++ b/z_e_no_nl
+@@ -2,7 +2,7 @@ a
+ b
+ c
+ d
+-e
+-f
+-g
+-h
+\ No newline at end of file
++E
++F
++G
++H
+\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl_PostImage
new file mode 100644
index 0000000000..234fedc28e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl_PostImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+E
+F
+G
+H \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl_PreImage
new file mode 100644
index 0000000000..33a3e0ed4d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_no_nl_PreImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl.patch
new file mode 100644
index 0000000000..d669706eaa
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl.patch
@@ -0,0 +1,17 @@
+diff --git a/z_e_rm_nl b/z_e_rm_nl
+index 71ac1b5..234fedc 100644
+--- a/z_e_rm_nl
++++ b/z_e_rm_nl
+@@ -2,7 +2,7 @@ a
+ b
+ c
+ d
+-e
+-f
+-g
+-h
++E
++F
++G
++H
+\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl_PostImage
new file mode 100644
index 0000000000..234fedc28e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl_PostImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+E
+F
+G
+H \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl_PreImage
new file mode 100644
index 0000000000..71ac1b5791
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/z_e_rm_nl_PreImage
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+h
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java
index 1e430da089..bcde022d40 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java
@@ -354,6 +354,7 @@ public class PatchApplierTest {
Result result = applyPatch();
verifyChange(result, "ShiftDown2");
}
+
}
public static class InCore extends Base {
@@ -361,10 +362,44 @@ public class PatchApplierTest {
public InCore() {
super(true);
}
+
+ @Test
+ public void testNoNewlineAtEnd() throws Exception {
+ init("x_d");
+
+ Result result = applyPatch();
+ verifyChange(result, "x_d");
+ }
+
+ @Test
+ public void testNoNewlineAtEndInHunk() throws Exception {
+ init("x_e");
+
+ Result result = applyPatch();
+ verifyChange(result, "x_e");
+ }
+
+ @Test
+ public void testAddNewlineAtEnd() throws Exception {
+ init("x_add_nl");
+
+ Result result = applyPatch();
+ verifyChange(result, "x_add_nl");
+ }
+
+ @Test
+ public void testRemoveNewlineAtEnd() throws Exception {
+ init("x_last_rm_nl");
+
+ Result result = applyPatch();
+ verifyChange(result, "x_last_rm_nl");
+ }
}
public static class WithWorktree extends Base {
- public WithWorktree() { super(false); }
+ public WithWorktree() {
+ super(false);
+ }
@Test
public void testModifyNL1() throws Exception {
@@ -473,6 +508,230 @@ public class PatchApplierTest {
}
}
+ @Test
+ public void testNoNewlineAtEndAutoCRLF_true() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+
+ init("x_d_crlf", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_d_crlf");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testNoNewlineAtEndAutoCRLF_false() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+
+ init("x_d", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_d");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testNoNewlineAtEndAutoCRLF_input() throws Exception {
+ try {
+ db.getConfig().setString(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, "input");
+
+ init("x_d", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_d");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testNoNewlineAtEndInHunkAutoCRLF_true() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+
+ init("x_e_crlf", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_e_crlf");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testNoNewlineAtEndInHunkAutoCRLF_false() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+
+ init("x_e", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_e");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testNoNewlineAtEndInHunkAutoCRLF_input() throws Exception {
+ try {
+ db.getConfig().setString(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, "input");
+
+ init("x_e", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_e");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testAddNewlineAtEndAutoCRLF_true() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+
+ init("x_add_nl_crlf", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_add_nl_crlf");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testAddNewlineAtEndAutoCRLF_false() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+
+ init("x_add_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_add_nl");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testAddNewlineAtEndAutoCRLF_input() throws Exception {
+ try {
+ db.getConfig().setString(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, "input");
+
+ init("x_add_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_add_nl");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testRemoveNewlineAtEndAutoCRLF_true() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+
+ init("x_last_rm_nl_crlf", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_last_rm_nl_crlf");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testRemoveNewlineAtEndAutoCRLF_false() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+
+ init("x_last_rm_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_last_rm_nl");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testRemoveNewlineAtEndAutoCRLF_input() throws Exception {
+ try {
+ db.getConfig().setString(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, "input");
+
+ init("x_last_rm_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_last_rm_nl");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testEditExample() throws Exception {
+ init("z_e", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "z_e");
+ }
+
+ @Test
+ public void testEditNoNewline() throws Exception {
+ init("z_e_no_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "z_e_no_nl");
+ }
+
+ @Test
+ public void testEditAddNewline() throws Exception {
+ init("z_e_add_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "z_e_add_nl");
+ }
+
+ @Test
+ public void testEditRemoveNewline() throws Exception {
+ init("z_e_rm_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "z_e_rm_nl");
+ }
+
// Clean/smudge filter for testFiltering. The smudgetest test resources
// were created with C git using a clean filter sed -e "s/A/E/g" and the
// smudge filter sed -e "s/E/A/g". To keep the test independent of the
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/PatchApplier.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/PatchApplier.java
index 50b92c189a..2a4de1331d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/PatchApplier.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/PatchApplier.java
@@ -24,6 +24,7 @@ import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
import java.time.Instant;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -93,6 +94,9 @@ import org.eclipse.jgit.util.sha1.SHA1;
*/
public class PatchApplier {
+ private static final byte[] NO_EOL = "\\ No newline at end of file" //$NON-NLS-1$
+ .getBytes(StandardCharsets.US_ASCII);
+
/** The tree before applying the patch. Only non-null for inCore operation. */
@Nullable
private final RevTree beforeTree;
@@ -762,6 +766,8 @@ public class PatchApplier {
int afterLastHunk = 0;
int lineNumberShift = 0;
int lastHunkNewLine = -1;
+ boolean lastWasRemoval = false;
+ boolean noNewLineAtEndOfNew = false;
for (HunkHeader hh : fh.getHunks()) {
// We assume hunks to be ordered
if (hh.getNewStartLine() <= lastHunkNewLine) {
@@ -850,17 +856,26 @@ public class PatchApplier {
if (!hunkLine.hasRemaining()) {
// Completely empty line; accept as empty context line
applyAt++;
+ lastWasRemoval = false;
continue;
}
switch (hunkLine.array()[hunkLine.position()]) {
case ' ':
applyAt++;
+ lastWasRemoval = false;
break;
case '-':
newLines.remove(applyAt);
+ lastWasRemoval = true;
break;
case '+':
newLines.add(applyAt++, slice(hunkLine, 1));
+ lastWasRemoval = false;
+ break;
+ case '\\':
+ if (!lastWasRemoval && isNoNewlineAtEnd(hunkLine)) {
+ noNewLineAtEndOfNew = true;
+ }
break;
default:
break;
@@ -868,12 +883,15 @@ public class PatchApplier {
}
afterLastHunk = applyAt;
}
- if (!isNoNewlineAtEndOfFile(fh)) {
+ // If the last line should have a newline, add a null sentinel
+ if (lastHunkNewLine >= 0 && afterLastHunk == newLines.size()) {
+ // Last line came from the patch
+ if (!noNewLineAtEndOfNew) {
+ newLines.add(null);
+ }
+ } else if (!rt.isMissingNewlineAtEnd()) {
newLines.add(null);
}
- if (!rt.isMissingNewlineAtEnd()) {
- oldLines.add(null);
- }
// We could check if old == new, but the short-circuiting complicates
// logic for inCore patching, so just write the new thing regardless.
@@ -931,19 +949,9 @@ public class PatchApplier {
return ByteBuffer.wrap(b.array(), newOffset, b.limit() - newOffset);
}
- private boolean isNoNewlineAtEndOfFile(FileHeader fh) {
- List<? extends HunkHeader> hunks = fh.getHunks();
- if (hunks == null || hunks.isEmpty()) {
- return false;
- }
- HunkHeader lastHunk = hunks.get(hunks.size() - 1);
- byte[] buf = new byte[lastHunk.getEndOffset()
- - lastHunk.getStartOffset()];
- System.arraycopy(lastHunk.getBuffer(), lastHunk.getStartOffset(), buf,
- 0, buf.length);
- RawText lhrt = new RawText(buf);
- return lhrt.getString(lhrt.size() - 1)
- .equals("\\ No newline at end of file"); //$NON-NLS-1$
+ private boolean isNoNewlineAtEnd(ByteBuffer hunkLine) {
+ return Arrays.equals(NO_EOL, 0, NO_EOL.length, hunkLine.array(),
+ hunkLine.position(), hunkLine.limit());
}
/**