diff options
author | Shawn O. Pearce <spearce@spearce.org> | 2010-09-07 17:14:27 -0700 |
---|---|---|
committer | Shawn O. Pearce <spearce@spearce.org> | 2010-09-07 17:14:27 -0700 |
commit | 9f61c615e858c038a754dc512476ccf215385d8f (patch) | |
tree | d60be279c7615e01ac56549dde4b2ca561d17ae5 | |
parent | 67263e2056108e471d684c3cef9e719724b51220 (diff) | |
download | jgit-9f61c615e858c038a754dc512476ccf215385d8f.tar.gz jgit-9f61c615e858c038a754dc512476ccf215385d8f.zip |
Support core.autocrlf = input
The core.autocrlf variable can take on three values: false, true,
and input. Parsing it as a boolean is wrong, we instead need to
parse a tri-state enumeration.
Add support for parsing and setting enum values from Java from and
to the text based configuration file, and use that to handle the
autocrlf variable.
Bug: 301775
Change-Id: I81b9e33087a33d2ef2eac89ba93b9e83b7ecc223
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
9 files changed, 187 insertions, 11 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java index e12e869ec5..eb9f03c550 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java @@ -229,6 +229,38 @@ public class ConfigTest extends TestCase { assertFalse(c.getBoolean("s", "b", true)); } + static enum TestEnum { + ONE_TWO; + } + + public void testGetEnum() throws ConfigInvalidException { + Config c = parse("[s]\na = ON\nb = input\nc = true\nd = off\n"); + assertSame(CoreConfig.AutoCRLF.TRUE, c.getEnum("s", null, "a", + CoreConfig.AutoCRLF.FALSE)); + + assertSame(CoreConfig.AutoCRLF.INPUT, c.getEnum("s", null, "b", + CoreConfig.AutoCRLF.FALSE)); + + assertSame(CoreConfig.AutoCRLF.TRUE, c.getEnum("s", null, "c", + CoreConfig.AutoCRLF.FALSE)); + + assertSame(CoreConfig.AutoCRLF.FALSE, c.getEnum("s", null, "d", + CoreConfig.AutoCRLF.TRUE)); + + c = new Config(); + assertSame(CoreConfig.AutoCRLF.FALSE, c.getEnum("s", null, "d", + CoreConfig.AutoCRLF.FALSE)); + + c = parse("[s \"b\"]\n\tc = one two\n"); + assertSame(TestEnum.ONE_TWO, c.getEnum("s", "b", "c", TestEnum.ONE_TWO)); + } + + public void testSetEnum() { + final Config c = new Config(); + c.setEnum("s", "b", "c", TestEnum.ONE_TWO); + assertEquals("[s \"b\"]\n\tc = one two\n", c.toText()); + } + public void testReadLong() throws ConfigInvalidException { assertReadLong(1L); assertReadLong(-1L); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/AbstractTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/AbstractTreeIteratorTest.java index 72354e4e95..cc7d0ad9ef 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/AbstractTreeIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/AbstractTreeIteratorTest.java @@ -52,6 +52,7 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.CoreConfig.AutoCRLF; public class AbstractTreeIteratorTest extends TestCase { @@ -62,7 +63,7 @@ public class AbstractTreeIteratorTest extends TestCase { public class FakeTreeIterator extends WorkingTreeIterator { public FakeTreeIterator(String pathName, FileMode fileMode) { - super(prefix(pathName), new WorkingTreeOptions(false)); + super(prefix(pathName), new WorkingTreeOptions(AutoCRLF.FALSE)); mode = fileMode.getBits(); final int s = pathName.lastIndexOf('/'); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java index 58fb5297a2..f15454ba07 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java @@ -48,6 +48,7 @@ import java.util.TreeSet; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.CoreConfig.AutoCRLF; import org.eclipse.jgit.util.FS; /** @@ -87,7 +88,7 @@ public class FileTreeIteratorWithTimeControl extends FileTreeIterator { public FileTreeIteratorWithTimeControl(File f, FS fs, TreeSet<Long> modTimes) { - super(f, fs, new WorkingTreeOptions(false)); + super(f, fs, new WorkingTreeOptions(AutoCRLF.FALSE)); this.modTimes = modTimes; } diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties index cd932c6d83..e8ec148bdd 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties @@ -136,6 +136,9 @@ emptyPathNotPermitted=Empty path not permitted. encryptionError=Encryption error: {0} endOfFileInEscape=End of file in escape entryNotFoundByPath=Entry not found by path: {0} +enumValueNotSupported2=Invalid value: {0}.{1}={2} +enumValueNotSupported3=Invalid value: {0}.{1}.{2}={3} +enumValuesNotAvailable=Enumerated values of type {0} not available errorDecodingFromFile=Error decoding from file {0} errorEncodingFromFile=Error encoding from file {0} errorInBase64CodeReadingStream=Error in Base64 code reading stream. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java index 7fa265847b..c7b5a9ee63 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java @@ -196,6 +196,9 @@ public class JGitText extends TranslationBundle { /***/ public String encryptionError; /***/ public String endOfFileInEscape; /***/ public String entryNotFoundByPath; + /***/ public String enumValueNotSupported2; + /***/ public String enumValueNotSupported3; + /***/ public String enumValuesNotAvailable; /***/ public String errorDecodingFromFile; /***/ public String errorEncodingFromFile; /***/ public String errorInBase64CodeReadingStream; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java index 884f49845c..daad67e29c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java @@ -334,6 +334,95 @@ public class Config { } /** + * Parse an enumeration from the configuration. + * + * @param <T> + * type of the enumeration object. + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @param defaultValue + * default value to return if no value was present. + * @return the selected enumeration value, or {@code defaultValue}. + */ + public <T extends Enum<?>> T getEnum(final String section, + final String subsection, final String name, final T defaultValue) { + final T[] all = allValuesOf(defaultValue); + return getEnum(all, section, subsection, name, defaultValue); + } + + @SuppressWarnings("unchecked") + private static <T> T[] allValuesOf(final T value) { + try { + return (T[]) value.getClass().getMethod("values").invoke(null); + } catch (Exception err) { + String typeName = value.getClass().getName(); + String msg = MessageFormat.format( + JGitText.get().enumValuesNotAvailable, typeName); + throw new IllegalArgumentException(msg, err); + } + } + + /** + * Parse an enumeration from the configuration. + * + * @param <T> + * type of the enumeration object. + * @param all + * all possible values in the enumeration which should be + * recognized. Typically {@code EnumType.values()}. + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @param defaultValue + * default value to return if no value was present. + * @return the selected enumeration value, or {@code defaultValue}. + */ + public <T extends Enum<?>> T getEnum(final T[] all, final String section, + final String subsection, final String name, final T defaultValue) { + String value = getString(section, subsection, name); + if (value == null) + return defaultValue; + + String n = value.replace(' ', '_'); + T trueState = null; + T falseState = null; + for (T e : all) { + if (StringUtils.equalsIgnoreCase(e.name(), n)) + return e; + else if (StringUtils.equalsIgnoreCase(e.name(), "TRUE")) + trueState = e; + else if (StringUtils.equalsIgnoreCase(e.name(), "FALSE")) + falseState = e; + } + + // This is an odd little fallback. C Git sometimes allows boolean + // values in a tri-state with other things. If we have both a true + // and a false value in our enumeration, assume its one of those. + // + if (trueState != null && falseState != null) { + try { + return StringUtils.toBoolean(n) ? trueState : falseState; + } catch (IllegalArgumentException err) { + // Fall through and use our custom error below. + } + } + + if (subsection != null) + throw new IllegalArgumentException(MessageFormat.format(JGitText + .get().enumValueNotSupported3, section, name, value)); + else + throw new IllegalArgumentException(MessageFormat.format(JGitText + .get().enumValueNotSupported2, section, name, value)); + } + + /** * Get string value * * @param section @@ -634,6 +723,32 @@ public class Config { * name = value * </pre> * + * @param <T> + * type of the enumeration object. + * @param section + * section name, e.g "branch" + * @param subsection + * optional subsection value, e.g. a branch name + * @param name + * parameter name, e.g. "filemode" + * @param value + * parameter value + */ + public <T extends Enum<?>> void setEnum(final String section, + final String subsection, final String name, final T value) { + String n = value.name().toLowerCase().replace('_', ' '); + setString(section, subsection, name, n); + } + + /** + * Add or modify a configuration value. The parameters will result in a + * configuration entry like this. + * + * <pre> + * [section "subsection"] + * name = value + * </pre> + * * @param section * section name, e.g "branch" * @param subsection diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java index 249b95ec3c..f644d2c697 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java @@ -61,19 +61,31 @@ public class CoreConfig { } }; + /** Permissible values for {@code core.autocrlf}. */ + public static enum AutoCRLF { + /** Automatic CRLF->LF conversion is disabled. */ + FALSE, + + /** Automatic CRLF->LF conversion is enabled. */ + TRUE, + + /** CRLF->LF performed, but no LF->CRLF. */ + INPUT; + } + private final int compression; private final int packIndexVersion; private final boolean logAllRefUpdates; - private final boolean autoCRLF; + private final AutoCRLF autoCRLF; private CoreConfig(final Config rc) { compression = rc.getInt("core", "compression", DEFAULT_COMPRESSION); packIndexVersion = rc.getInt("pack", "indexversion", 2); logAllRefUpdates = rc.getBoolean("core", "logallrefupdates", true); - autoCRLF = rc.getBoolean("core", "autocrlf", false); + autoCRLF = rc.getEnum("core", null, "autocrlf", AutoCRLF.FALSE); } /** @@ -101,7 +113,7 @@ public class CoreConfig { /** * @return whether automatic CRLF conversion has been configured */ - public boolean isAutoCRLF() { + public AutoCRLF getAutoCRLF() { return autoCRLF; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java index 5cc061bbb4..b292c3cdd3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java @@ -299,7 +299,15 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { } private boolean mightNeedCleaning(Entry entry) { - return options.isAutoCRLF(); + switch (options.getAutoCRLF()) { + case FALSE: + default: + return false; + + case TRUE: + case INPUT: + return true; + } } private boolean isBinary(Entry entry, byte[] content, int sz) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java index 50da3302d6..6929046c25 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java @@ -44,6 +44,7 @@ package org.eclipse.jgit.treewalk; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.CoreConfig; +import org.eclipse.jgit.lib.CoreConfig.AutoCRLF; /** * Contains options used by the WorkingTreeIterator. @@ -57,7 +58,7 @@ public class WorkingTreeOptions { * @return created working tree options */ public static WorkingTreeOptions createDefaultInstance() { - return new WorkingTreeOptions(false); + return new WorkingTreeOptions(AutoCRLF.FALSE); } /** @@ -69,14 +70,14 @@ public class WorkingTreeOptions { * @return created working tree options */ public static WorkingTreeOptions createConfigurationInstance(Config config) { - return new WorkingTreeOptions(config.get(CoreConfig.KEY).isAutoCRLF()); + return new WorkingTreeOptions(config.get(CoreConfig.KEY).getAutoCRLF()); } /** * Indicates whether EOLs of text files should be converted to '\n' before * calculating the blob ID. **/ - private final boolean autoCRLF; + private final AutoCRLF autoCRLF; /** * Creates new options. @@ -85,7 +86,7 @@ public class WorkingTreeOptions { * indicates whether EOLs of text files should be converted to * '\n' before calculating the blob ID. */ - public WorkingTreeOptions(boolean autoCRLF) { + public WorkingTreeOptions(AutoCRLF autoCRLF) { this.autoCRLF = autoCRLF; } @@ -95,7 +96,7 @@ public class WorkingTreeOptions { * * @return true if EOLs should be canonicalized. */ - public boolean isAutoCRLF() { + public AutoCRLF getAutoCRLF() { return autoCRLF; } } |