diff options
author | Nitzan Gur-Furman <nitzan@google.com> | 2023-07-19 10:37:39 +0200 |
---|---|---|
committer | Nitzan Gur-Furman <nitzan@google.com> | 2023-08-01 10:37:24 +0200 |
commit | c353645a09b677644c55daa9dcff7df54529dc04 (patch) | |
tree | d0302970bcafa12fdf9167b0575514d895dad6e9 | |
parent | ec11129b1d2ff5f7a909c05deb84e422fcd83084 (diff) | |
download | jgit-c353645a09b677644c55daa9dcff7df54529dc04.tar.gz jgit-c353645a09b677644c55daa9dcff7df54529dc04.zip |
Move footer-line parsing methods from RevCommit to FooterLine
This allows extracting footers from a messages not associated with a
commit.
The public API of RevCommit is kept intact.
Change-Id: I5809c23df7b7d49641a4be3a26d6f987d3d57c9b
Bug: Google b/287891316
4 files changed, 228 insertions, 163 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java index 113f3bee82..01f6a3a0a0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java @@ -16,76 +16,74 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import java.io.IOException; import java.util.List; import org.eclipse.jgit.junit.RepositoryTestCase; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.junit.Test; public class FooterLineTest extends RepositoryTestCase { @Test - public void testNoFooters_EmptyBody() throws IOException { - final RevCommit commit = parse(""); - final List<FooterLine> footers = commit.getFooterLines(); + public void testNoFooters_EmptyBody() { + String msg = buildMessage(""); + List<FooterLine> footers = FooterLine.fromMessage(msg); assertNotNull(footers); assertEquals(0, footers.size()); } @Test - public void testNoFooters_NewlineOnlyBody1() throws IOException { - final RevCommit commit = parse("\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testNoFooters_NewlineOnlyBody1() { + String msg = buildMessage("\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); assertNotNull(footers); assertEquals(0, footers.size()); } @Test - public void testNoFooters_NewlineOnlyBody5() throws IOException { - final RevCommit commit = parse("\n\n\n\n\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testNoFooters_NewlineOnlyBody5() { + String msg = buildMessage("\n\n\n\n\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); assertNotNull(footers); assertEquals(0, footers.size()); } @Test - public void testNoFooters_OneLineBodyNoLF() throws IOException { - final RevCommit commit = parse("this is a commit"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testNoFooters_OneLineBodyNoLF() { + String msg = buildMessage("this is a commit"); + List<FooterLine> footers = FooterLine.fromMessage(msg); assertNotNull(footers); assertEquals(0, footers.size()); } @Test - public void testNoFooters_OneLineBodyWithLF() throws IOException { - final RevCommit commit = parse("this is a commit\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testNoFooters_OneLineBodyWithLF() { + String msg = buildMessage("this is a commit\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); assertNotNull(footers); assertEquals(0, footers.size()); } @Test - public void testNoFooters_ShortBodyNoLF() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testNoFooters_ShortBodyNoLF() { + String msg = buildMessage("subject\n\nbody of commit"); + List<FooterLine> footers = FooterLine.fromMessage(msg); assertNotNull(footers); assertEquals(0, footers.size()); } @Test - public void testNoFooters_ShortBodyWithLF() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testNoFooters_ShortBodyWithLF() { + String msg = buildMessage("subject\n\nbody of commit\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); assertNotNull(footers); assertEquals(0, footers.size()); } @Test - public void testSignedOffBy_OneUserNoLF() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n" - + "Signed-off-by: A. U. Thor <a@example.com>"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testSignedOffBy_OneUserNoLF() { + String msg = buildMessage("subject\n\nbody of commit\n" + "\n" + + "Signed-off-by: A. U. Thor <a@example.com>"); + List<FooterLine> footers = FooterLine.fromMessage(msg); FooterLine f; assertNotNull(footers); @@ -98,10 +96,10 @@ public class FooterLineTest extends RepositoryTestCase { } @Test - public void testSignedOffBy_OneUserWithLF() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n" - + "Signed-off-by: A. U. Thor <a@example.com>\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testSignedOffBy_OneUserWithLF() { + String msg = buildMessage("subject\n\nbody of commit\n" + "\n" + + "Signed-off-by: A. U. Thor <a@example.com>\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); FooterLine f; assertNotNull(footers); @@ -114,14 +112,13 @@ public class FooterLineTest extends RepositoryTestCase { } @Test - public void testSignedOffBy_IgnoreWhitespace() throws IOException { + public void testSignedOffBy_IgnoreWhitespace() { // We only ignore leading whitespace on the value, trailing // is assumed part of the value. // - final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n" - + "Signed-off-by: A. U. Thor <a@example.com> \n"); - final List<FooterLine> footers = commit.getFooterLines(); - FooterLine f; + String msg = buildMessage("subject\n\nbody of commit\n" + "\n" + + "Signed-off-by: A. U. Thor <a@example.com> \n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); FooterLine f; assertNotNull(footers); assertEquals(1, footers.size()); @@ -133,10 +130,10 @@ public class FooterLineTest extends RepositoryTestCase { } @Test - public void testEmptyValueNoLF() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n" - + "Signed-off-by:"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testEmptyValueNoLF() { + String msg = buildMessage("subject\n\nbody of commit\n" + "\n" + + "Signed-off-by:"); + List<FooterLine> footers = FooterLine.fromMessage(msg); FooterLine f; assertNotNull(footers); @@ -149,10 +146,10 @@ public class FooterLineTest extends RepositoryTestCase { } @Test - public void testEmptyValueWithLF() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n" - + "Signed-off-by:\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testEmptyValueWithLF() { + String msg = buildMessage("subject\n\nbody of commit\n" + "\n" + + "Signed-off-by:\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); FooterLine f; assertNotNull(footers); @@ -165,10 +162,10 @@ public class FooterLineTest extends RepositoryTestCase { } @Test - public void testShortKey() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n" - + "K:V\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testShortKey() { + String msg = buildMessage("subject\n\nbody of commit\n" + "\n" + + "K:V\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); FooterLine f; assertNotNull(footers); @@ -181,10 +178,10 @@ public class FooterLineTest extends RepositoryTestCase { } @Test - public void testNonDelimtedEmail() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n" - + "Acked-by: re@example.com\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testNonDelimtedEmail() { + String msg = buildMessage("subject\n\nbody of commit\n" + "\n" + + "Acked-by: re@example.com\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); FooterLine f; assertNotNull(footers); @@ -197,10 +194,10 @@ public class FooterLineTest extends RepositoryTestCase { } @Test - public void testNotEmail() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n" - + "Acked-by: Main Tain Er\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testNotEmail() { + String msg = buildMessage("subject\n\nbody of commit\n" + "\n" + + "Acked-by: Main Tain Er\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); FooterLine f; assertNotNull(footers); @@ -213,15 +210,15 @@ public class FooterLineTest extends RepositoryTestCase { } @Test - public void testSignedOffBy_ManyUsers() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit\n" - + "Not-A-Footer-Line: this line must not be read as a footer\n" - + "\n" // paragraph break, now footers appear in final block - + "Signed-off-by: A. U. Thor <a@example.com>\n" - + "CC: <some.mailing.list@example.com>\n" - + "Acked-by: Some Reviewer <sr@example.com>\n" - + "Signed-off-by: Main Tain Er <mte@example.com>\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testSignedOffBy_ManyUsers() { + String msg = buildMessage("subject\n\nbody of commit\n" + + "Not-A-Footer-Line: this line must not be read as a footer\n" + + "\n" // paragraph break, now footers appear in final block + + "Signed-off-by: A. U. Thor <a@example.com>\n" + + "CC: <some.mailing.list@example.com>\n" + + "Acked-by: Some Reviewer <sr@example.com>\n" + + "Signed-off-by: Main Tain Er <mte@example.com>\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); FooterLine f; assertNotNull(footers); @@ -249,16 +246,16 @@ public class FooterLineTest extends RepositoryTestCase { } @Test - public void testSignedOffBy_SkipNonFooter() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit\n" - + "Not-A-Footer-Line: this line must not be read as a footer\n" - + "\n" // paragraph break, now footers appear in final block - + "Signed-off-by: A. U. Thor <a@example.com>\n" - + "CC: <some.mailing.list@example.com>\n" - + "not really a footer line but we'll skip it anyway\n" - + "Acked-by: Some Reviewer <sr@example.com>\n" - + "Signed-off-by: Main Tain Er <mte@example.com>\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testSignedOffBy_SkipNonFooter() { + String msg = buildMessage("subject\n\nbody of commit\n" + + "Not-A-Footer-Line: this line must not be read as a footer\n" + + "\n" // paragraph break, now footers appear in final block + + "Signed-off-by: A. U. Thor <a@example.com>\n" + + "CC: <some.mailing.list@example.com>\n" + + "not really a footer line but we'll skip it anyway\n" + + "Acked-by: Some Reviewer <sr@example.com>\n" + + "Signed-off-by: Main Tain Er <mte@example.com>\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); FooterLine f; assertNotNull(footers); @@ -282,15 +279,16 @@ public class FooterLineTest extends RepositoryTestCase { } @Test - public void testFilterFootersIgnoreCase() throws IOException { - final RevCommit commit = parse("subject\n\nbody of commit\n" - + "Not-A-Footer-Line: this line must not be read as a footer\n" - + "\n" // paragraph break, now footers appear in final block - + "Signed-Off-By: A. U. Thor <a@example.com>\n" - + "CC: <some.mailing.list@example.com>\n" - + "Acked-by: Some Reviewer <sr@example.com>\n" - + "signed-off-by: Main Tain Er <mte@example.com>\n"); - final List<String> footers = commit.getFooterLines("signed-off-by"); + public void testFilterFootersIgnoreCase() { + String msg = buildMessage("subject\n\nbody of commit\n" + + "Not-A-Footer-Line: this line must not be read as a footer\n" + + "\n" // paragraph break, now footers appear in final block + + "Signed-Off-By: A. U. Thor <a@example.com>\n" + + "CC: <some.mailing.list@example.com>\n" + + "Acked-by: Some Reviewer <sr@example.com>\n" + + "signed-off-by: Main Tain Er <mte@example.com>\n"); + List<String> footers = FooterLine.getValues( + FooterLine.fromMessage(msg), "signed-off-by"); assertNotNull(footers); assertEquals(2, footers.size()); @@ -300,38 +298,33 @@ public class FooterLineTest extends RepositoryTestCase { } @Test - public void testMatchesBugId() throws IOException { - final RevCommit commit = parse("this is a commit subject for test\n" - + "\n" // paragraph break, now footers appear in final block - + "Simple-Bug-Id: 42\n"); - final List<FooterLine> footers = commit.getFooterLines(); + public void testMatchesBugId() { + String msg = buildMessage("this is a commit subject for test\n" + + "\n" // paragraph break, now footers appear in final block + + "Simple-Bug-Id: 42\n"); + List<FooterLine> footers = FooterLine.fromMessage(msg); assertNotNull(footers); assertEquals(1, footers.size()); - final FooterLine line = footers.get(0); + FooterLine line = footers.get(0); assertNotNull(line); assertEquals("Simple-Bug-Id", line.getKey()); assertEquals("42", line.getValue()); - final FooterKey bugid = new FooterKey("Simple-Bug-Id"); + FooterKey bugid = new FooterKey("Simple-Bug-Id"); assertTrue("matches Simple-Bug-Id", line.matches(bugid)); assertFalse("not Signed-off-by", line.matches(FooterKey.SIGNED_OFF_BY)); assertFalse("not CC", line.matches(FooterKey.CC)); } - private RevCommit parse(String msg) throws IOException { - final StringBuilder buf = new StringBuilder(); + private String buildMessage(String msg) { + StringBuilder buf = new StringBuilder(); buf.append("tree " + ObjectId.zeroId().name() + "\n"); buf.append("author A. U. Thor <a@example.com> 1 +0000\n"); buf.append("committer A. U. Thor <a@example.com> 1 +0000\n"); buf.append("\n"); buf.append(msg); - - try (RevWalk walk = new RevWalk(db)) { - RevCommit c = new RevCommit(ObjectId.zeroId()); - c.parseCanonical(walk, Constants.encode(buf.toString())); - return c; - } + return buf.toString(); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterLine.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterLine.java index 676573c2f2..eeaccc6d33 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterLine.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterLine.java @@ -11,6 +11,9 @@ package org.eclipse.jgit.revwalk; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.eclipse.jgit.util.RawParseUtils; @@ -47,6 +50,108 @@ public final class FooterLine { } /** + * Extract the footer lines from the given message. + * + * @param str + * the message to extract footers from. + * @return ordered list of footer lines; empty list if no footers found. + * @see RevCommit#getFooterLines() + */ + public static List<FooterLine> fromMessage( + String str) { + return fromMessage(str.getBytes()); + } + + /** + * Extract the footer lines from the given message. + * + * @param raw + * the raw message to extract footers from. + * @return ordered list of footer lines; empty list if no footers found. + * @see RevCommit#getFooterLines() + */ + public static List<FooterLine> fromMessage( + byte[] raw) { + int ptr = raw.length - 1; + while (raw[ptr] == '\n') // trim any trailing LFs, not interesting + ptr--; + + int msgB = RawParseUtils.commitMessage(raw, 0); + ArrayList<FooterLine> r = new ArrayList<>(4); + Charset enc = RawParseUtils.guessEncoding(raw); + for (;;) { + ptr = RawParseUtils.prevLF(raw, ptr); + if (ptr <= msgB) + break; // Don't parse commit headers as footer lines. + + int keyStart = ptr + 2; + if (raw[keyStart] == '\n') + break; // Stop at first paragraph break, no footers above it. + + int keyEnd = RawParseUtils.endOfFooterLineKey(raw, keyStart); + if (keyEnd < 0) + continue; // Not a well formed footer line, skip it. + + // Skip over the ': *' at the end of the key before the value. + // + int valStart = keyEnd + 1; + while (valStart < raw.length && raw[valStart] == ' ') + valStart++; + + // Value ends at the LF, and does not include it. + // + int valEnd = RawParseUtils.nextLF(raw, valStart); + if (raw[valEnd - 1] == '\n') + valEnd--; + + r.add(new FooterLine(raw, enc, keyStart, keyEnd, valStart, valEnd)); + } + Collections.reverse(r); + return r; + } + + /** + * Get the values of all footer lines with the given key. + * + * @param footers + * list of footers to find the values in. + * @param keyName + * footer key to find values of, case-insensitive. + * @return values of footers with key of {@code keyName}, ordered by their + * order of appearance. Duplicates may be returned if the same + * footer appeared more than once. Empty list if no footers appear + * with the specified key, or there are no footers at all. + * @see #fromMessage + */ + public static List<String> getValues(List<FooterLine> footers, String keyName) { + return getValues(footers, new FooterKey(keyName)); + } + + /** + * Get the values of all footer lines with the given key. + * + * @param footers + * list of footers to find the values in. + * @param key + * footer key to find values of, case-insensitive. + * @return values of footers with key of {@code keyName}, ordered by their + * order of appearance. Duplicates may be returned if the same + * footer appeared more than once. Empty list if no footers appear + * with the specified key, or there are no footers at all. + * @see #fromMessage + */ + public static List<String> getValues(List<FooterLine> footers, FooterKey key) { + if (footers.isEmpty()) + return Collections.emptyList(); + ArrayList<String> r = new ArrayList<>(footers.size()); + for (FooterLine f : footers) { + if (f.matches(key)) + r.add(f.getValue()); + } + return r; + } + + /** * Whether keys match * * @param key diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java index 4619938147..0392ea428c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java @@ -11,15 +11,13 @@ package org.eclipse.jgit.revwalk; -import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.util.RawParseUtils.guessEncoding; import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import org.eclipse.jgit.annotations.Nullable; @@ -484,7 +482,8 @@ public class RevCommit extends RevObject { if (msgB < 0) { return ""; //$NON-NLS-1$ } - return RawParseUtils.decode(guessEncoding(), raw, msgB, raw.length); + return RawParseUtils.decode(guessEncoding(buffer), raw, msgB, + raw.length); } /** @@ -510,7 +509,8 @@ public class RevCommit extends RevObject { } int msgE = RawParseUtils.endOfParagraph(raw, msgB); - String str = RawParseUtils.decode(guessEncoding(), raw, msgB, msgE); + String str = RawParseUtils.decode(guessEncoding(buffer), raw, msgB, + msgE); if (hasLF(raw, msgB, msgE)) { str = StringUtils.replaceLineBreaksWithSpace(str); } @@ -562,14 +562,6 @@ public class RevCommit extends RevObject { return RawParseUtils.parseEncoding(buffer); } - private Charset guessEncoding() { - try { - return getEncoding(); - } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { - return UTF_8; - } - } - /** * Parse the footer lines (e.g. "Signed-off-by") for machine processing. * <p> @@ -592,50 +584,14 @@ public class RevCommit extends RevObject { * @return ordered list of footer lines; empty list if no footers found. */ public final List<FooterLine> getFooterLines() { - final byte[] raw = buffer; - int ptr = raw.length - 1; - while (raw[ptr] == '\n') // trim any trailing LFs, not interesting - ptr--; - - final int msgB = RawParseUtils.commitMessage(raw, 0); - final ArrayList<FooterLine> r = new ArrayList<>(4); - final Charset enc = guessEncoding(); - for (;;) { - ptr = RawParseUtils.prevLF(raw, ptr); - if (ptr <= msgB) - break; // Don't parse commit headers as footer lines. - - final int keyStart = ptr + 2; - if (raw[keyStart] == '\n') - break; // Stop at first paragraph break, no footers above it. - - final int keyEnd = RawParseUtils.endOfFooterLineKey(raw, keyStart); - if (keyEnd < 0) - continue; // Not a well formed footer line, skip it. - - // Skip over the ': *' at the end of the key before the value. - // - int valStart = keyEnd + 1; - while (valStart < raw.length && raw[valStart] == ' ') - valStart++; - - // Value ends at the LF, and does not include it. - // - int valEnd = RawParseUtils.nextLF(raw, valStart); - if (raw[valEnd - 1] == '\n') - valEnd--; - - r.add(new FooterLine(raw, enc, keyStart, keyEnd, valStart, valEnd)); - } - Collections.reverse(r); - return r; + return FooterLine.fromMessage(buffer); } /** * Get the values of all footer lines with the given key. * * @param keyName - * footer key to find values of, case insensitive. + * footer key to find values of, case-insensitive. * @return values of footers with key of {@code keyName}, ordered by their * order of appearance. Duplicates may be returned if the same * footer appeared more than once. Empty list if no footers appear @@ -643,30 +599,22 @@ public class RevCommit extends RevObject { * @see #getFooterLines() */ public final List<String> getFooterLines(String keyName) { - return getFooterLines(new FooterKey(keyName)); + return FooterLine.getValues(getFooterLines(), keyName); } /** * Get the values of all footer lines with the given key. * - * @param keyName - * footer key to find values of, case insensitive. + * @param key + * footer key to find values of, case-insensitive. * @return values of footers with key of {@code keyName}, ordered by their * order of appearance. Duplicates may be returned if the same * footer appeared more than once. Empty list if no footers appear * with the specified key, or there are no footers at all. * @see #getFooterLines() */ - public final List<String> getFooterLines(FooterKey keyName) { - final List<FooterLine> src = getFooterLines(); - if (src.isEmpty()) - return Collections.emptyList(); - final ArrayList<String> r = new ArrayList<>(src.size()); - for (FooterLine f : src) { - if (f.matches(keyName)) - r.add(f.getValue()); - } - return r; + public final List<String> getFooterLines(FooterKey key) { + return FooterLine.getValues(getFooterLines(), key); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java index 0e8e9b3d84..1c98336b99 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java @@ -868,6 +868,25 @@ public final class RawParseUtils { } /** + * Parse the "encoding " header into a character set reference. + * <p> + * If unsuccessful, return UTF-8. + * + * @param buffer + * buffer to scan. + * @return the Java character set representation. Never null. Default to + * UTF-8. + * @see #parseEncoding(byte[]) + */ + public static Charset guessEncoding(byte[] buffer) { + try { + return parseEncoding(buffer); + } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { + return UTF_8; + } + } + + /** * Parse a name string (e.g. author, committer, tagger) into a PersonIdent. * <p> * Leading spaces won't be trimmed from the string, i.e. will show up in the |