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>
This commit is contained in:
parent
67263e2056
commit
9f61c615e8
|
@ -229,6 +229,38 @@ public void testReadBoolean_OnOff2() throws ConfigInvalidException {
|
|||
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);
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
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 @@ private static String prefix(String path) {
|
|||
|
||||
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('/');
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
|
||||
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 FileTreeIteratorWithTimeControl(Repository repo,
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -196,6 +196,9 @@ public static JGitText get() {
|
|||
/***/ 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;
|
||||
|
|
|
@ -333,6 +333,95 @@ public boolean getBoolean(final String section, String subsection,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -625,6 +714,32 @@ public void setBoolean(final String section, final String subsection,
|
|||
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 "subsection"]
|
||||
* 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.
|
||||
|
|
|
@ -61,19 +61,31 @@ public CoreConfig parse(final Config cfg) {
|
|||
}
|
||||
};
|
||||
|
||||
/** 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 boolean isLogAllRefUpdates() {
|
|||
/**
|
||||
* @return whether automatic CRLF conversion has been configured
|
||||
*/
|
||||
public boolean isAutoCRLF() {
|
||||
public AutoCRLF getAutoCRLF() {
|
||||
return autoCRLF;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -299,7 +299,15 @@ private static void safeClose(final InputStream in) {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
|
||||
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 static WorkingTreeOptions createDefaultInstance() {
|
|||
* @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 static WorkingTreeOptions createConfigurationInstance(Config config) {
|
|||
* 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 WorkingTreeOptions(boolean autoCRLF) {
|
|||
*
|
||||
* @return true if EOLs should be canonicalized.
|
||||
*/
|
||||
public boolean isAutoCRLF() {
|
||||
public AutoCRLF getAutoCRLF() {
|
||||
return autoCRLF;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue