Browse Source

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>
stable-0.9
Shawn O. Pearce 14 years ago
parent
commit
9f61c615e8
  1. 32
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
  2. 3
      org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/AbstractTreeIteratorTest.java
  3. 3
      org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java
  4. 3
      org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
  5. 3
      org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
  6. 115
      org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
  7. 18
      org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
  8. 10
      org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
  9. 11
      org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java

32
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)); 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 { public void testReadLong() throws ConfigInvalidException {
assertReadLong(1L); assertReadLong(1L);
assertReadLong(-1L); assertReadLong(-1L);

3
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.Constants;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
public class AbstractTreeIteratorTest extends TestCase { public class AbstractTreeIteratorTest extends TestCase {
@ -62,7 +63,7 @@ public class AbstractTreeIteratorTest extends TestCase {
public class FakeTreeIterator extends WorkingTreeIterator { public class FakeTreeIterator extends WorkingTreeIterator {
public FakeTreeIterator(String pathName, FileMode fileMode) { public FakeTreeIterator(String pathName, FileMode fileMode) {
super(prefix(pathName), new WorkingTreeOptions(false)); super(prefix(pathName), new WorkingTreeOptions(AutoCRLF.FALSE));
mode = fileMode.getBits(); mode = fileMode.getBits();
final int s = pathName.lastIndexOf('/'); final int s = pathName.lastIndexOf('/');

3
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.ObjectReader;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
/** /**
@ -87,7 +88,7 @@ public class FileTreeIteratorWithTimeControl extends FileTreeIterator {
public FileTreeIteratorWithTimeControl(File f, FS fs, public FileTreeIteratorWithTimeControl(File f, FS fs,
TreeSet<Long> modTimes) { TreeSet<Long> modTimes) {
super(f, fs, new WorkingTreeOptions(false)); super(f, fs, new WorkingTreeOptions(AutoCRLF.FALSE));
this.modTimes = modTimes; this.modTimes = modTimes;
} }

3
org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties

@ -136,6 +136,9 @@ emptyPathNotPermitted=Empty path not permitted.
encryptionError=Encryption error: {0} encryptionError=Encryption error: {0}
endOfFileInEscape=End of file in escape endOfFileInEscape=End of file in escape
entryNotFoundByPath=Entry not found by path: {0} 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} errorDecodingFromFile=Error decoding from file {0}
errorEncodingFromFile=Error encoding from file {0} errorEncodingFromFile=Error encoding from file {0}
errorInBase64CodeReadingStream=Error in Base64 code reading stream. errorInBase64CodeReadingStream=Error in Base64 code reading stream.

3
org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java

@ -196,6 +196,9 @@ public class JGitText extends TranslationBundle {
/***/ public String encryptionError; /***/ public String encryptionError;
/***/ public String endOfFileInEscape; /***/ public String endOfFileInEscape;
/***/ public String entryNotFoundByPath; /***/ public String entryNotFoundByPath;
/***/ public String enumValueNotSupported2;
/***/ public String enumValueNotSupported3;
/***/ public String enumValuesNotAvailable;
/***/ public String errorDecodingFromFile; /***/ public String errorDecodingFromFile;
/***/ public String errorEncodingFromFile; /***/ public String errorEncodingFromFile;
/***/ public String errorInBase64CodeReadingStream; /***/ public String errorInBase64CodeReadingStream;

115
org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java

@ -333,6 +333,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 * Get string value
* *
@ -625,6 +714,32 @@ public class Config {
setString(section, subsection, name, value ? "true" : "false"); setString(section, subsection, name, value ? "true" : "false");
} }
/**
* Add or modify a configuration value. The parameters will result in a
* configuration entry like this.
*
* <pre>
* [section &quot;subsection&quot;]
* 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 * Add or modify a configuration value. The parameters will result in a
* configuration entry like this. * configuration entry like this.

18
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 compression;
private final int packIndexVersion; private final int packIndexVersion;
private final boolean logAllRefUpdates; private final boolean logAllRefUpdates;
private final boolean autoCRLF; private final AutoCRLF autoCRLF;
private CoreConfig(final Config rc) { private CoreConfig(final Config rc) {
compression = rc.getInt("core", "compression", DEFAULT_COMPRESSION); compression = rc.getInt("core", "compression", DEFAULT_COMPRESSION);
packIndexVersion = rc.getInt("pack", "indexversion", 2); packIndexVersion = rc.getInt("pack", "indexversion", 2);
logAllRefUpdates = rc.getBoolean("core", "logallrefupdates", true); 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 * @return whether automatic CRLF conversion has been configured
*/ */
public boolean isAutoCRLF() { public AutoCRLF getAutoCRLF() {
return autoCRLF; return autoCRLF;
} }
} }

10
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) { 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) { private boolean isBinary(Entry entry, byte[] content, int sz) {

11
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.Config;
import org.eclipse.jgit.lib.CoreConfig; import org.eclipse.jgit.lib.CoreConfig;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
/** /**
* Contains options used by the WorkingTreeIterator. * Contains options used by the WorkingTreeIterator.
@ -57,7 +58,7 @@ public class WorkingTreeOptions {
* @return created working tree options * @return created working tree options
*/ */
public static WorkingTreeOptions createDefaultInstance() { 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 * @return created working tree options
*/ */
public static WorkingTreeOptions createConfigurationInstance(Config config) { 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 * Indicates whether EOLs of text files should be converted to '\n' before
* calculating the blob ID. * calculating the blob ID.
**/ **/
private final boolean autoCRLF; private final AutoCRLF autoCRLF;
/** /**
* Creates new options. * Creates new options.
@ -85,7 +86,7 @@ public class WorkingTreeOptions {
* indicates whether EOLs of text files should be converted to * indicates whether EOLs of text files should be converted to
* '\n' before calculating the blob ID. * '\n' before calculating the blob ID.
*/ */
public WorkingTreeOptions(boolean autoCRLF) { public WorkingTreeOptions(AutoCRLF autoCRLF) {
this.autoCRLF = autoCRLF; this.autoCRLF = autoCRLF;
} }
@ -95,7 +96,7 @@ public class WorkingTreeOptions {
* *
* @return true if EOLs should be canonicalized. * @return true if EOLs should be canonicalized.
*/ */
public boolean isAutoCRLF() { public AutoCRLF getAutoCRLF() {
return autoCRLF; return autoCRLF;
} }
} }

Loading…
Cancel
Save