aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src/org/eclipse/jgit
diff options
context:
space:
mode:
authorIvan Motsch <ivan.motsch@bsiag.com>2016-02-25 15:39:41 +0100
committerChristian Halstrick <christian.halstrick@sap.com>2016-03-07 17:24:32 +0100
commitb811e4399ea578a07595bac790ad619b9fcb1300 (patch)
treef250d10e959185a6162f5748a5afcd7fe06ad239 /org.eclipse.jgit/src/org/eclipse/jgit
parent846ef78a02edceb99940d7aa92dcd2462a85c602 (diff)
downloadjgit-b811e4399ea578a07595bac790ad619b9fcb1300.tar.gz
jgit-b811e4399ea578a07595bac790ad619b9fcb1300.zip
Add EOL stream type detection to TreeWalk
TreeWalk provides the new method getEolStreamType. This new method can be used with EolStreamTypeUtil in order to create a wrapped InputStream or OutputStream when reading / writing files. The implementation implements support for the git configuration options core.crlf, core.eol and the .gitattributes "text", "eol" and "binary" CQ: 10896 Bug: 486563 Change-Id: Ie4f6367afc2a6aec1de56faf95120fff0339a358 Signed-off-by: Ivan Motsch <ivan.motsch@bsiag.com> Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java22
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java12
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java127
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java40
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java13
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java89
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java146
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java14
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/Holder.java77
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java23
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java199
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java200
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolCanonicalizingInputStream.java123
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java255
18 files changed, 1106 insertions, 251 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
index a83814eb46..d803efd649 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
@@ -66,7 +66,7 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.treewalk.WorkingTreeOptions;
import org.eclipse.jgit.util.IO;
-import org.eclipse.jgit.util.io.EolCanonicalizingInputStream;
+import org.eclipse.jgit.util.io.AutoLFInputStream;
/**
* Blame command for building a {@link BlameResult} for a file path.
@@ -248,7 +248,7 @@ public class BlameCommand extends GitCommand<BlameResult> {
rawText = new RawText(inTree);
break;
case TRUE:
- EolCanonicalizingInputStream in = new EolCanonicalizingInputStream(
+ AutoLFInputStream in = new AutoLFInputStream(
new FileInputStream(inTree), true);
// Canonicalization should lead to same or shorter length
// (CRLF to LF), so the file size on disk is an upper size bound
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
index 4f918fa357..c37c317c51 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -59,6 +59,7 @@ import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheCheckout;
+import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
@@ -68,6 +69,7 @@ import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
@@ -395,7 +397,8 @@ public class CheckoutCommand extends GitCommand<Ref> {
RefNotFoundException {
DirCache dc = repo.lockDirCache();
try (RevWalk revWalk = new RevWalk(repo);
- TreeWalk treeWalk = new TreeWalk(revWalk.getObjectReader())) {
+ TreeWalk treeWalk = new TreeWalk(repo,
+ revWalk.getObjectReader())) {
treeWalk.setRecursive(true);
if (!checkoutAllPaths)
treeWalk.setFilter(PathFilterGroup.createFromStrings(paths));
@@ -426,20 +429,23 @@ public class CheckoutCommand extends GitCommand<Ref> {
if (path.equals(previousPath))
continue;
+ final EolStreamType eolStreamType = treeWalk.getEolStreamType();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
int stage = ent.getStage();
if (stage > DirCacheEntry.STAGE_0) {
if (checkoutStage != null) {
if (stage == checkoutStage.number)
- checkoutPath(ent, r);
+ checkoutPath(ent, r, new CheckoutMetadata(
+ eolStreamType, null));
} else {
UnmergedPathException e = new UnmergedPathException(
ent);
throw new JGitInternalException(e.getMessage(), e);
}
} else {
- checkoutPath(ent, r);
+ checkoutPath(ent, r,
+ new CheckoutMetadata(eolStreamType, null));
}
}
});
@@ -457,20 +463,24 @@ public class CheckoutCommand extends GitCommand<Ref> {
while (treeWalk.next()) {
final ObjectId blobId = treeWalk.getObjectId(0);
final FileMode mode = treeWalk.getFileMode(0);
+ final EolStreamType eolStreamType = treeWalk.getEolStreamType();
editor.add(new PathEdit(treeWalk.getPathString()) {
public void apply(DirCacheEntry ent) {
ent.setObjectId(blobId);
ent.setFileMode(mode);
- checkoutPath(ent, r);
+ checkoutPath(ent, r,
+ new CheckoutMetadata(eolStreamType, null));
}
});
}
editor.commit();
}
- private void checkoutPath(DirCacheEntry entry, ObjectReader reader) {
+ private void checkoutPath(DirCacheEntry entry, ObjectReader reader,
+ CheckoutMetadata checkoutMetadata) {
try {
- DirCacheCheckout.checkoutEntry(repo, entry, reader, true);
+ DirCacheCheckout.checkoutEntry(repo, entry, reader, true,
+ checkoutMetadata);
} catch (IOException e) {
throw new JGitInternalException(MessageFormat.format(
JGitText.get().checkoutConflictWithFile,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
index 8ef550871f..1699b9f3d7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -54,11 +54,13 @@ import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheCheckout;
+import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.CheckoutConflictException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
@@ -336,6 +338,7 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
// Not in commit, don't create untracked
continue;
+ final EolStreamType eolStreamType = walk.getEolStreamType();
final DirCacheEntry entry = new DirCacheEntry(walk.getRawPath());
entry.setFileMode(cIter.getEntryFileMode());
entry.setObjectIdFromRaw(cIter.idBuffer(), cIter.idOffset());
@@ -350,14 +353,17 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
}
}
- checkoutPath(entry, reader);
+ checkoutPath(entry, reader,
+ new CheckoutMetadata(eolStreamType, null));
}
}
}
- private void checkoutPath(DirCacheEntry entry, ObjectReader reader) {
+ private void checkoutPath(DirCacheEntry entry, ObjectReader reader,
+ CheckoutMetadata checkoutMetadata) {
try {
- DirCacheCheckout.checkoutEntry(repo, entry, reader, true);
+ DirCacheCheckout.checkoutEntry(repo, entry, reader, true,
+ checkoutMetadata);
} catch (IOException e) {
throw new JGitInternalException(MessageFormat.format(
JGitText.get().checkoutConflictWithFile,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
index 2cdaf24019..ef32ac929a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
@@ -245,12 +245,14 @@ public class StashCreateCommand extends GitCommand<RevCommit> {
DirCache cache = repo.lockDirCache();
ObjectId commitId;
try (ObjectInserter inserter = repo.newObjectInserter();
- TreeWalk treeWalk = new TreeWalk(reader)) {
+ TreeWalk treeWalk = new TreeWalk(repo, reader)) {
treeWalk.setRecursive(true);
treeWalk.addTree(headCommit.getTree());
treeWalk.addTree(new DirCacheIterator(cache));
treeWalk.addTree(new FileTreeIterator(repo));
+ treeWalk.getTree(2, FileTreeIterator.class)
+ .setDirCacheIterator(treeWalk, 1);
treeWalk.setFilter(AndTreeFilter.create(new SkipWorkTreeFilter(
1), new IndexDiffFilter(1, 2)));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index a1e1d15ac6..3fcaa38395 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -62,6 +62,7 @@ import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
+import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
import org.eclipse.jgit.lib.CoreConfig.SymLinks;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.NullProgressMonitor;
@@ -84,16 +85,43 @@ import org.eclipse.jgit.util.FS.ExecutionResult;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.SystemReader;
-import org.eclipse.jgit.util.io.AutoCRLFOutputStream;
+import org.eclipse.jgit.util.io.EolStreamTypeUtil;
/**
* This class handles checking out one or two trees merging with the index.
*/
public class DirCacheCheckout {
private static final int MAX_EXCEPTION_TEXT_SIZE = 10 * 1024;
+
+ /**
+ * Metadata used in checkout process
+ *
+ * @since 4.3
+ */
+ public static class CheckoutMetadata {
+ /** git attributes */
+ public final EolStreamType eolStreamType;
+
+ /** filter command to apply */
+ public final String smudgeFilterCommand;
+
+ /**
+ * @param eolStreamType
+ * @param smudgeFilterCommand
+ */
+ public CheckoutMetadata(EolStreamType eolStreamType,
+ String smudgeFilterCommand) {
+ this.eolStreamType = eolStreamType;
+ this.smudgeFilterCommand = smudgeFilterCommand;
+ }
+
+ static CheckoutMetadata EMPTY = new CheckoutMetadata(
+ EolStreamType.DIRECT, null);
+ }
+
private Repository repo;
- private HashMap<String, String> updated = new HashMap<String, String>();
+ private HashMap<String, CheckoutMetadata> updated = new HashMap<String, CheckoutMetadata>();
private ArrayList<String> conflicts = new ArrayList<String>();
@@ -120,7 +148,7 @@ public class DirCacheCheckout {
/**
* @return a list of updated paths and smudgeFilterCommands
*/
- public Map<String, String> getUpdated() {
+ public Map<String, CheckoutMetadata> getUpdated() {
return updated;
}
@@ -450,11 +478,12 @@ public class DirCacheCheckout {
if (file != null)
removeEmptyParents(file);
- for (String path : updated.keySet()) {
+ for (Map.Entry<String, CheckoutMetadata> e : updated.entrySet()) {
+ String path = e.getKey();
+ CheckoutMetadata meta = e.getValue();
DirCacheEntry entry = dc.getEntry(path);
if (!FileMode.GITLINK.equals(entry.getRawMode()))
- checkoutEntry(repo, entry, objectReader, false,
- updated.get(path));
+ checkoutEntry(repo, entry, objectReader, false, meta);
}
// commit the index builder - a new index is persisted
@@ -1006,8 +1035,8 @@ public class DirCacheCheckout {
private void update(String path, ObjectId mId, FileMode mode)
throws IOException {
if (!FileMode.TREE.equals(mode)) {
- updated.put(path,
- walk.getFilterCommand(Constants.ATTR_FILTER_TYPE_SMUDGE));
+ updated.put(path, new CheckoutMetadata(walk.getEolStreamType(),
+ walk.getFilterCommand(Constants.ATTR_FILTER_TYPE_SMUDGE)));
DirCacheEntry entry = new DirCacheEntry(path, DirCacheEntry.STAGE_0);
entry.setObjectId(mId);
@@ -1190,52 +1219,22 @@ public class DirCacheCheckout {
* @param deleteRecursive
* true to recursively delete final path if it exists on the file
* system
- *
- * @throws IOException
- * @since 4.2
- */
- public static void checkoutEntry(Repository repo, DirCacheEntry entry,
- ObjectReader or, boolean deleteRecursive) throws IOException {
- checkoutEntry(repo, entry, or, deleteRecursive, null);
- }
-
- /**
- * Updates the file in the working tree with content and mode from an entry
- * in the index. The new content is first written to a new temporary file in
- * the same directory as the real file. Then that new file is renamed to the
- * final filename.
- *
- * <p>
- * <b>Note:</b> if the entry path on local file system exists as a file, it
- * will be deleted and if it exists as a directory, it will be deleted
- * recursively, independently if has any content.
- * </p>
- *
- * <p>
- * TODO: this method works directly on File IO, we may need another
- * abstraction (like WorkingTreeIterator). This way we could tell e.g.
- * Eclipse that Files in the workspace got changed
- * </p>
- *
- * @param repo
- * repository managing the destination work tree.
- * @param entry
- * the entry containing new mode and content
- * @param or
- * object reader to use for checkout
- * @param deleteRecursive
- * true to recursively delete final path if it exists on the file
- * system
- * @param smudgeFilterCommand
- * the filter command to be run for smudging the entry to be
- * checked out
+ * @param checkoutMetadata
+ * containing
+ * <ul>
+ * <li>smudgeFilterCommand to be run for smudging the entry to be
+ * checked out</li>
+ * <li>eolStreamType used for stream conversion</li>
+ * </ul>
*
* @throws IOException
* @since 4.2
*/
public static void checkoutEntry(Repository repo, DirCacheEntry entry,
ObjectReader or, boolean deleteRecursive,
- String smudgeFilterCommand) throws IOException {
+ CheckoutMetadata checkoutMetadata) throws IOException {
+ if (checkoutMetadata == null)
+ checkoutMetadata = CheckoutMetadata.EMPTY;
ObjectLoader ol = or.open(entry.getObjectId());
File f = new File(repo.getWorkTree(), entry.getPathString());
File parentDir = f.getParentFile();
@@ -1257,12 +1256,19 @@ public class DirCacheCheckout {
File tmpFile = File.createTempFile(
"._" + f.getName(), null, parentDir); //$NON-NLS-1$
- OutputStream channel = new FileOutputStream(tmpFile);
- if (opt.getAutoCRLF() == AutoCRLF.TRUE)
- channel = new AutoCRLFOutputStream(channel);
- if (smudgeFilterCommand != null) {
- ProcessBuilder filterProcessBuilder = fs
- .runInShell(smudgeFilterCommand, new String[0]);
+ EolStreamType nonNullEolStreamType;
+ if (checkoutMetadata.eolStreamType != null) {
+ nonNullEolStreamType = checkoutMetadata.eolStreamType;
+ } else if (opt.getAutoCRLF() == AutoCRLF.TRUE) {
+ nonNullEolStreamType = EolStreamType.AUTO_CRLF;
+ } else {
+ nonNullEolStreamType = EolStreamType.DIRECT;
+ }
+ OutputStream channel = EolStreamTypeUtil.wrapOutputStream(
+ new FileOutputStream(tmpFile), nonNullEolStreamType);
+ if (checkoutMetadata.smudgeFilterCommand != null) {
+ ProcessBuilder filterProcessBuilder = fs.runInShell(
+ checkoutMetadata.smudgeFilterCommand, new String[0]);
filterProcessBuilder.directory(repo.getWorkTree());
filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY,
repo.getDirectory().getAbsolutePath());
@@ -1278,14 +1284,16 @@ public class DirCacheCheckout {
}
} catch (IOException | InterruptedException e) {
throw new IOException(new FilterFailedException(e,
- smudgeFilterCommand, entry.getPathString()));
+ checkoutMetadata.smudgeFilterCommand,
+ entry.getPathString()));
} finally {
channel.close();
}
if (rc != 0) {
throw new IOException(new FilterFailedException(rc,
- smudgeFilterCommand, entry.getPathString(),
+ checkoutMetadata.smudgeFilterCommand,
+ entry.getPathString(),
result.getStdout().toByteArray(MAX_EXCEPTION_TEXT_SIZE),
RawParseUtils.decode(result.getStderr()
.toByteArray(MAX_EXCEPTION_TEXT_SIZE))));
@@ -1301,10 +1309,11 @@ public class DirCacheCheckout {
// was filtered (either by autocrlf handling or smudge filters) ask the
// filesystem again for the length. Otherwise the objectloader knows the
// size
- if (opt.getAutoCRLF() == AutoCRLF.TRUE || smudgeFilterCommand != null) {
- entry.setLength(tmpFile.length());
- } else {
+ if (checkoutMetadata.eolStreamType == EolStreamType.DIRECT
+ && checkoutMetadata.smudgeFilterCommand == null) {
entry.setLength(ol.getSize());
+ } else {
+ entry.setLength(tmpFile.length());
}
if (opt.isFileMode() && fs.supportsExecute()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index a89bcee730..054d193017 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -107,6 +107,13 @@ public class ConfigConstants {
/** The "autocrlf" key */
public static final String CONFIG_KEY_AUTOCRLF = "autocrlf";
+ /**
+ * The "eol" key
+ *
+ * @since 4.3
+ */
+ public static final String CONFIG_KEY_EOL = "eol";
+
/** The "bare" key */
public static final String CONFIG_KEY_BARE = "bare";
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 5a7634a6f1..83efd43aa0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
@@ -76,6 +76,46 @@ public class CoreConfig {
}
/**
+ * Permissible values for {@code core.eol}.
+ * <p>
+ * https://git-scm.com/docs/gitattributes
+ *
+ * @since 4.3
+ */
+ public static enum EOL {
+ /** checkin with LF, checkout with CRLF. */
+ CRLF,
+
+ /** checkin with LF, checkout without conversion. */
+ LF,
+
+ /** use the platform's native line ending. */
+ NATIVE;
+ }
+
+ /**
+ * EOL stream conversion protocol
+ *
+ * @since 4.3
+ */
+ public static enum EolStreamType {
+ /** convert to CRLF without binary detection */
+ TEXT_CRLF,
+
+ /** convert to LF without binary detection */
+ TEXT_LF,
+
+ /** convert to CRLF with binary detection */
+ AUTO_CRLF,
+
+ /** convert to LF with binary detection */
+ AUTO_LF,
+
+ /** do not convert */
+ DIRECT;
+ }
+
+ /**
* Permissible values for {@code core.checkstat}
*
* @since 3.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
index d2195a874c..b9293ebfb6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
@@ -104,6 +104,19 @@ public class NameConflictTreeWalk extends TreeWalk {
/**
* Create a new tree walker for a given repository.
*
+ * @param repo
+ * the repository the walker will obtain data from.
+ * @param or
+ * the reader the walker will obtain tree data from.
+ * @since 4.3
+ */
+ public NameConflictTreeWalk(Repository repo, final ObjectReader or) {
+ super(repo, or);
+ }
+
+ /**
+ * Create a new tree walker for a given repository.
+ *
* @param or
* the reader the walker will obtain tree data from.
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
index 4775e96175..aecbac11ea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
@@ -49,6 +49,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.attributes.Attribute;
import org.eclipse.jgit.attributes.Attributes;
@@ -64,6 +65,7 @@ import org.eclipse.jgit.errors.StopWalkException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.MutableObjectId;
import org.eclipse.jgit.lib.ObjectId;
@@ -74,6 +76,7 @@ import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.jgit.util.QuotedString;
import org.eclipse.jgit.util.RawParseUtils;
+import org.eclipse.jgit.util.io.EolStreamTypeUtil;
/**
* Walks one or more {@link AbstractTreeIterator}s in parallel.
@@ -161,7 +164,44 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
public static TreeWalk forPath(final ObjectReader reader, final String path,
final AnyObjectId... trees) throws MissingObjectException,
IncorrectObjectTypeException, CorruptObjectException, IOException {
- TreeWalk tw = new TreeWalk(reader);
+ return forPath(null, reader, path, trees);
+ }
+
+ /**
+ * Open a tree walk and filter to exactly one path.
+ * <p>
+ * The returned tree walk is already positioned on the requested path, so
+ * the caller should not need to invoke {@link #next()} unless they are
+ * looking for a possible directory/file name conflict.
+ *
+ * @param repo
+ * repository to read config data and
+ * {@link AttributesNodeProvider} from.
+ * @param reader
+ * the reader the walker will obtain tree data from.
+ * @param path
+ * single path to advance the tree walk instance into.
+ * @param trees
+ * one or more trees to walk through, all with the same root.
+ * @return a new tree walk configured for exactly this one path; null if no
+ * path was found in any of the trees.
+ * @throws IOException
+ * reading a pack file or loose object failed.
+ * @throws CorruptObjectException
+ * an tree object could not be read as its data stream did not
+ * appear to be a tree, or could not be inflated.
+ * @throws IncorrectObjectTypeException
+ * an object we expected to be a tree was not a tree.
+ * @throws MissingObjectException
+ * a tree object was not found.
+ * @since 4.3
+ */
+ public static TreeWalk forPath(final @Nullable Repository repo,
+ final ObjectReader reader, final String path,
+ final AnyObjectId... trees)
+ throws MissingObjectException, IncorrectObjectTypeException,
+ CorruptObjectException, IOException {
+ TreeWalk tw = new TreeWalk(repo, reader);
PathFilter f = PathFilter.create(path);
tw.setFilter(f);
tw.reset(trees);
@@ -206,7 +246,7 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
final AnyObjectId... trees) throws MissingObjectException,
IncorrectObjectTypeException, CorruptObjectException, IOException {
try (ObjectReader reader = db.newObjectReader()) {
- return forPath(reader, path, trees);
+ return forPath(db, reader, path, trees);
}
}
@@ -282,9 +322,23 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
* when the walker is closed.
*/
public TreeWalk(final Repository repo) {
- this(repo.newObjectReader(), true);
- config = repo.getConfig();
- attributesNodeProvider = repo.createAttributesNodeProvider();
+ this(repo, repo.newObjectReader(), true);
+ }
+
+ /**
+ * Create a new tree walker for a given repository.
+ *
+ * @param repo
+ * the repository the walker will obtain data from. An
+ * ObjectReader will be created by the walker, and will be closed
+ * when the walker is closed.
+ * @param or
+ * the reader the walker will obtain tree data from. The reader
+ * is not closed when the walker is closed.
+ * @since 4.3
+ */
+ public TreeWalk(final @Nullable Repository repo, final ObjectReader or) {
+ this(repo, or, false);
}
/**
@@ -295,10 +349,18 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
* is not closed when the walker is closed.
*/
public TreeWalk(final ObjectReader or) {
- this(or, false);
+ this(null, or, false);
}
- private TreeWalk(final ObjectReader or, final boolean closeReader) {
+ private TreeWalk(final @Nullable Repository repo, final ObjectReader or,
+ final boolean closeReader) {
+ if (repo != null) {
+ config = repo.getConfig();
+ attributesNodeProvider = repo.createAttributesNodeProvider();
+ } else {
+ config = null;
+ attributesNodeProvider = null;
+ }
reader = or;
filter = TreeFilter.ALL;
trees = NO_TREES;
@@ -517,6 +579,19 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
}
}
+ /**
+ * @return the EOL stream type of the current entry using the config and
+ * {@link #getAttributes()} Note that this method may return null if
+ * the {@link TreeWalk} is not based on a working tree
+ * @since 4.3
+ */
+ public @Nullable EolStreamType getEolStreamType() {
+ if (attributesNodeProvider == null || config == null)
+ return null;
+ return EolStreamTypeUtil.detectStreamType(operationType,
+ config.get(WorkingTreeOptions.KEY), getAttributes());
+ }
+
/** Reset this walker so new tree iterators can be added to it. */
public void reset() {
attrs = null;
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 0d617ee7f9..ca8f9aa373 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -77,8 +77,8 @@ import org.eclipse.jgit.ignore.IgnoreNode;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig;
-import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.lib.CoreConfig.CheckStat;
+import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
import org.eclipse.jgit.lib.CoreConfig.SymLinks;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
@@ -88,10 +88,12 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.submodule.SubmoduleWalk;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FS.ExecutionResult;
+import org.eclipse.jgit.util.Holder;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.Paths;
import org.eclipse.jgit.util.RawParseUtils;
-import org.eclipse.jgit.util.io.EolCanonicalizingInputStream;
+import org.eclipse.jgit.util.io.AutoLFInputStream;
+import org.eclipse.jgit.util.io.EolStreamTypeUtil;
/**
* Walks a working directory tree as part of a {@link TreeWalk}.
@@ -140,7 +142,17 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
/** If there is a .gitignore file present, the parsed rules from it. */
private IgnoreNode ignoreNode;
- private String cleanFilterCommand;
+ /**
+ * cached clean filter command. Use a Ref in order to distinguish between
+ * the ref not cached yet and the value null
+ */
+ private Holder<String> cleanFilterCommandHolder;
+
+ /**
+ * cached eol stream type. Use a Ref in order to distinguish between the ref
+ * not cached yet and the value null
+ */
+ private Holder<EolStreamType> eolStreamTypeHolder;
/** Repository that is the root level being iterated over */
protected Repository repository;
@@ -357,8 +369,8 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
private InputStream possiblyFilteredInputStream(final Entry e,
final InputStream is, final long len) throws IOException {
- boolean mightNeedCleaning = mightNeedCleaning();
- if (!mightNeedCleaning) {
+ if (getCleanFilterCommand() == null
+ && getEolStreamType() == EolStreamType.DIRECT) {
canonLen = len;
return is;
}
@@ -376,11 +388,10 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
return new ByteArrayInputStream(raw, 0, n);
}
- // TODO: fix autocrlf causing mightneedcleaning
- if (!mightNeedCleaning && isBinary(e)) {
- canonLen = len;
- return is;
- }
+ if (getCleanFilterCommand() == null && isBinary(e)) {
+ canonLen = len;
+ return is;
+ }
final InputStream lenIs = filterClean(e.openInputStream());
try {
@@ -401,20 +412,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
}
}
- private boolean mightNeedCleaning() throws IOException {
- switch (getOptions().getAutoCRLF()) {
- case FALSE:
- default:
- if (getCleanFilterCommand() != null)
- return true;
- return false;
-
- case TRUE:
- case INPUT:
- return true;
- }
- }
-
private static boolean isBinary(byte[] content, int sz) {
return RawText.isBinary(content, sz);
}
@@ -467,12 +464,8 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
return in;
}
- private InputStream handleAutoCRLF(InputStream in) {
- AutoCRLF autoCRLF = getOptions().getAutoCRLF();
- if (autoCRLF == AutoCRLF.TRUE || autoCRLF == AutoCRLF.INPUT) {
- in = new EolCanonicalizingInputStream(in, true);
- }
- return in;
+ private InputStream handleAutoCRLF(InputStream in) throws IOException {
+ return EolStreamTypeUtil.wrapInputStream(in, getEolStreamType());
}
/**
@@ -531,7 +524,8 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
System.arraycopy(e.encodedName, 0, path, pathOffset, nameLen);
pathLen = pathOffset + nameLen;
canonLen = -1;
- cleanFilterCommand = null;
+ cleanFilterCommandHolder = null;
+ eolStreamTypeHolder = null;
}
/**
@@ -594,10 +588,11 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
*/
public InputStream openEntryStream() throws IOException {
InputStream rawis = current().openInputStream();
- if (mightNeedCleaning())
- return filterClean(rawis);
- else
+ if (getCleanFilterCommand() == null
+ && getEolStreamType() == EolStreamType.DIRECT)
return rawis;
+ else
+ return filterClean(rawis);
}
/**
@@ -971,10 +966,11 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
// Content differs: that's a real change, perhaps
if (reader == null) // deprecated use, do no further checks
return true;
- switch (getOptions().getAutoCRLF()) {
- case INPUT:
- case TRUE:
- InputStream dcIn = null;
+
+ switch (getEolStreamType()) {
+ case DIRECT:
+ return true;
+ default:
try {
ObjectLoader loader = reader.open(entry.getObjectId());
if (loader == null)
@@ -982,37 +978,26 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
// We need to compute the length, but only if it is not
// a binary stream.
- dcIn = new EolCanonicalizingInputStream(
- loader.openStream(), true, true /* abort if binary */);
long dcInLen;
- try {
+ try (InputStream dcIn = new AutoLFInputStream(
+ loader.openStream(), true,
+ true /* abort if binary */)) {
dcInLen = computeLength(dcIn);
- } catch (EolCanonicalizingInputStream.IsBinaryException e) {
+ } catch (AutoLFInputStream.IsBinaryException e) {
return true;
- } finally {
- dcIn.close();
}
- dcIn = new EolCanonicalizingInputStream(
- loader.openStream(), true);
- byte[] autoCrLfHash = computeHash(dcIn, dcInLen);
- boolean changed = getEntryObjectId().compareTo(
- autoCrLfHash, 0) != 0;
- return changed;
+ try (InputStream dcIn = new AutoLFInputStream(
+ loader.openStream(), true)) {
+ byte[] autoCrLfHash = computeHash(dcIn, dcInLen);
+ boolean changed = getEntryObjectId()
+ .compareTo(autoCrLfHash, 0) != 0;
+ return changed;
+ }
} catch (IOException e) {
return true;
- } finally {
- if (dcIn != null)
- try {
- dcIn.close();
- } catch (IOException e) {
- // empty
- }
}
- case FALSE:
- break;
}
- return true;
}
}
@@ -1308,10 +1293,43 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
* @since 4.2
*/
public String getCleanFilterCommand() throws IOException {
- if (cleanFilterCommand == null && state.walk != null) {
- cleanFilterCommand = state.walk
- .getFilterCommand(Constants.ATTR_FILTER_TYPE_CLEAN);
+ if (cleanFilterCommandHolder == null) {
+ String cmd = null;
+ if (state.walk != null) {
+ cmd = state.walk
+ .getFilterCommand(Constants.ATTR_FILTER_TYPE_CLEAN);
+ }
+ cleanFilterCommandHolder = new Holder<String>(cmd);
+ }
+ return cleanFilterCommandHolder.get();
+ }
+
+ /**
+ * @return the eol stream type for the current entry or <code>null</code> if
+ * it cannot be determined. When state or state.walk is null or the
+ * {@link TreeWalk} is not based on a {@link Repository} then null
+ * is returned.
+ * @throws IOException
+ * @since 4.3
+ */
+ public EolStreamType getEolStreamType() throws IOException {
+ if (eolStreamTypeHolder == null) {
+ EolStreamType type=null;
+ if (state.walk != null) {
+ type=state.walk.getEolStreamType();
+ } else {
+ switch (getOptions().getAutoCRLF()) {
+ case FALSE:
+ type = EolStreamType.DIRECT;
+ break;
+ case TRUE:
+ case INPUT:
+ type = EolStreamType.AUTO_LF;
+ break;
+ }
+ }
+ eolStreamTypeHolder = new Holder<EolStreamType>(type);
}
- return cleanFilterCommand;
+ return eolStreamTypeHolder.get();
}
}
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 a6dccce031..a8990b1e95 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java
@@ -48,6 +48,7 @@ import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Config.SectionParser;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.lib.CoreConfig.CheckStat;
+import org.eclipse.jgit.lib.CoreConfig.EOL;
import org.eclipse.jgit.lib.CoreConfig.HideDotFiles;
import org.eclipse.jgit.lib.CoreConfig.SymLinks;
@@ -64,6 +65,8 @@ public class WorkingTreeOptions {
private final AutoCRLF autoCRLF;
+ private final EOL eol;
+
private final CheckStat checkStat;
private final SymLinks symlinks;
@@ -75,6 +78,8 @@ public class WorkingTreeOptions {
ConfigConstants.CONFIG_KEY_FILEMODE, true);
autoCRLF = rc.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_AUTOCRLF, AutoCRLF.FALSE);
+ eol = rc.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_EOL, EOL.NATIVE);
checkStat = rc.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_CHECKSTAT, CheckStat.DEFAULT);
symlinks = rc.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
@@ -95,6 +100,15 @@ public class WorkingTreeOptions {
}
/**
+ * @return how text line endings should be normalized.
+ *
+ * @since 4.3
+ */
+ public EOL getEOL() {
+ return eol;
+ }
+
+ /**
* @return how stat data is compared
* @since 3.0
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Holder.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Holder.java
new file mode 100644
index 0000000000..3563e1bf1d
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Holder.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.util;
+
+/**
+ * Holder of an object.
+ *
+ * @param <T>
+ * the type of value held by this {@link Holder}
+ *
+ * @since 4.3
+ */
+public class Holder<T> {
+ private T value;
+
+ /**
+ * @param value
+ * is the initial value that is {@link #set(Object)}
+ */
+ public Holder(T value) {
+ set(value);
+ }
+
+ /**
+ * @return the value held by this {@link Holder}
+ */
+ public T get() {
+ return value;
+ }
+
+ /**
+ * @param value
+ * to be set as new value held by this {@link Holder}
+ */
+ public void set(T value) {
+ this.value = value;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java
index 98c5477de1..30f9ce95fc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java
@@ -50,7 +50,7 @@ import java.io.InputStream;
import org.eclipse.jgit.diff.RawText;
/**
- * An OutputStream that expands LF to CRLF.
+ * An InputStream that expands LF to CRLF.
*
* Existing CRLF are not expanded to CRCRLF, but retained as is.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
index f05da1c73c..3a72f7e1dc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
@@ -50,8 +50,11 @@ import org.eclipse.jgit.diff.RawText;
/**
* An OutputStream that expands LF to CRLF.
- * <p>
+ *
* Existing CRLF are not expanded to CRCRLF, but retained as is.
+ *
+ * A binary check on the first 8000 bytes is performed and in case of binary
+ * files, canonicalization is turned off (for the complete file).
*/
public class AutoCRLFOutputStream extends OutputStream {
@@ -67,13 +70,26 @@ public class AutoCRLFOutputStream extends OutputStream {
private int binbufcnt = 0;
+ private boolean detectBinary;
+
private boolean isBinary;
/**
* @param out
*/
public AutoCRLFOutputStream(OutputStream out) {
+ this(out, true);
+ }
+
+ /**
+ * @param out
+ * @param detectBinary
+ * whether binaries should be detected
+ * @since 4.3
+ */
+ public AutoCRLFOutputStream(OutputStream out, boolean detectBinary) {
this.out = out;
+ this.detectBinary = detectBinary;
}
@Override
@@ -141,7 +157,10 @@ public class AutoCRLFOutputStream extends OutputStream {
}
private void decideMode() throws IOException {
- isBinary = RawText.isBinary(binbuf, binbufcnt);
+ if (detectBinary) {
+ isBinary = RawText.isBinary(binbuf, binbufcnt);
+ detectBinary = false;
+ }
int cachedLen = binbufcnt;
binbufcnt = binbuf.length + 1; // full!
write(binbuf, 0, cachedLen);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java
new file mode 100644
index 0000000000..6e33f99127
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2010, 2013 Marc Strapetz <marc.strapetz@syntevo.com>
+ * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.jgit.diff.RawText;
+
+/**
+ * An InputStream that normalizes CRLF to LF.
+ *
+ * Existing single CR are not changed to LF, but retained as is.
+ *
+ * Optionally, a binary check on the first 8000 bytes is performed and in case
+ * of binary files, canonicalization is turned off (for the complete file).
+ * <p>
+ * This is the former EolCanonicalizingInputStream with a new name in order to
+ * have same naming for all LF / CRLF streams
+ *
+ * @since 4.3
+ */
+public class AutoLFInputStream extends InputStream {
+ private final byte[] single = new byte[1];
+
+ private final byte[] buf = new byte[8096];
+
+ private final InputStream in;
+
+ private int cnt;
+
+ private int ptr;
+
+ private boolean isBinary;
+
+ private boolean detectBinary;
+
+ private boolean abortIfBinary;
+
+ /**
+ * A special exception thrown when {@link AutoLFInputStream} is told to
+ * throw an exception when attempting to read a binary file. The exception
+ * may be thrown at any stage during reading.
+ *
+ * @since 3.3
+ */
+ public static class IsBinaryException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ IsBinaryException() {
+ super();
+ }
+ }
+
+ /**
+ * Creates a new InputStream, wrapping the specified stream
+ *
+ * @param in
+ * raw input stream
+ * @param detectBinary
+ * whether binaries should be detected
+ * @since 2.0
+ */
+ public AutoLFInputStream(InputStream in, boolean detectBinary) {
+ this(in, detectBinary, false);
+ }
+
+ /**
+ * Creates a new InputStream, wrapping the specified stream
+ *
+ * @param in
+ * raw input stream
+ * @param detectBinary
+ * whether binaries should be detected
+ * @param abortIfBinary
+ * throw an IOException if the file is binary
+ * @since 3.3
+ */
+ public AutoLFInputStream(InputStream in, boolean detectBinary,
+ boolean abortIfBinary) {
+ this.in = in;
+ this.detectBinary = detectBinary;
+ this.abortIfBinary = abortIfBinary;
+ }
+
+ @Override
+ public int read() throws IOException {
+ final int read = read(single, 0, 1);
+ return read == 1 ? single[0] & 0xff : -1;
+ }
+
+ @Override
+ public int read(byte[] bs, final int off, final int len)
+ throws IOException {
+ if (len == 0)
+ return 0;
+
+ if (cnt == -1)
+ return -1;
+
+ int i = off;
+ final int end = off + len;
+
+ while (i < end) {
+ if (ptr == cnt && !fillBuffer()) {
+ break;
+ }
+
+ byte b = buf[ptr++];
+ if (isBinary || b != '\r') {
+ // Logic for binary files ends here
+ bs[i++] = b;
+ continue;
+ }
+
+ if (ptr == cnt && !fillBuffer()) {
+ bs[i++] = '\r';
+ break;
+ }
+
+ if (buf[ptr] == '\n') {
+ bs[i++] = '\n';
+ ptr++;
+ } else
+ bs[i++] = '\r';
+ }
+
+ return i == off ? -1 : i - off;
+ }
+
+ /**
+ * @return true if the stream has detected as a binary so far
+ * @since 3.3
+ */
+ public boolean isBinary() {
+ return isBinary;
+ }
+
+ @Override
+ public void close() throws IOException {
+ in.close();
+ }
+
+ private boolean fillBuffer() throws IOException {
+ cnt = in.read(buf, 0, buf.length);
+ if (cnt < 1)
+ return false;
+ if (detectBinary) {
+ isBinary = RawText.isBinary(buf, cnt);
+ detectBinary = false;
+ if (isBinary && abortIfBinary)
+ throw new IsBinaryException();
+ }
+ ptr = 0;
+ return true;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java
new file mode 100644
index 0000000000..c932b00f3c
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.eclipse.jgit.diff.RawText;
+
+/**
+ * An OutputStream that reduces CRLF to LF.
+ *
+ * Existing single CR are not changed to LF, but retained as is.
+ *
+ * A binary check on the first 8000 bytes is performed and in case of binary
+ * files, canonicalization is turned off (for the complete file).
+ *
+ * @since 4.3
+ */
+public class AutoLFOutputStream extends OutputStream {
+
+ static final int BUFFER_SIZE = 8000;
+
+ private final OutputStream out;
+
+ private int buf = -1;
+
+ private byte[] binbuf = new byte[BUFFER_SIZE];
+
+ private byte[] onebytebuf = new byte[1];
+
+ private int binbufcnt = 0;
+
+ private boolean detectBinary;
+
+ private boolean isBinary;
+
+ /**
+ * @param out
+ */
+ public AutoLFOutputStream(OutputStream out) {
+ this(out, true);
+ }
+
+ /**
+ * @param out
+ * @param detectBinary
+ * whether binaries should be detected
+ */
+ public AutoLFOutputStream(OutputStream out, boolean detectBinary) {
+ this.out = out;
+ this.detectBinary = detectBinary;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ onebytebuf[0] = (byte) b;
+ write(onebytebuf, 0, 1);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ int overflow = buffer(b, 0, b.length);
+ if (overflow > 0) {
+ write(b, b.length - overflow, overflow);
+ }
+ }
+
+ @Override
+ public void write(byte[] b, final int startOff, final int startLen)
+ throws IOException {
+ final int overflow = buffer(b, startOff, startLen);
+ if (overflow < 0) {
+ return;
+ }
+ final int off = startOff + startLen - overflow;
+ final int len = overflow;
+ if (len == 0) {
+ return;
+ }
+ int lastw = off;
+ if (isBinary) {
+ out.write(b, off, len);
+ return;
+ }
+ for (int i = off; i < off + len; ++i) {
+ final byte c = b[i];
+ if (c == '\r') {
+ // skip write r but backlog r
+ if (lastw < i) {
+ out.write(b, lastw, i - lastw);
+ }
+ lastw = i + 1;
+ buf = '\r';
+ } else if (c == '\n') {
+ if (buf == '\r') {
+ out.write('\n');
+ lastw = i + 1;
+ buf = -1;
+ } else {
+ if (lastw < i + 1) {
+ out.write(b, lastw, i + 1 - lastw);
+ }
+ lastw = i + 1;
+ }
+ } else {
+ if (buf == '\r') {
+ out.write('\r');
+ lastw = i;
+ }
+ buf = -1;
+ }
+ }
+ if (lastw < off + len) {
+ out.write(b, lastw, off + len - lastw);
+ }
+ }
+
+ private int buffer(byte[] b, int off, int len) throws IOException {
+ if (binbufcnt > binbuf.length) {
+ return len;
+ }
+ int copy = Math.min(binbuf.length - binbufcnt, len);
+ System.arraycopy(b, off, binbuf, binbufcnt, copy);
+ binbufcnt += copy;
+ int remaining = len - copy;
+ if (remaining > 0) {
+ decideMode();
+ }
+ return remaining;
+ }
+
+ private void decideMode() throws IOException {
+ if (detectBinary) {
+ isBinary = RawText.isBinary(binbuf, binbufcnt);
+ detectBinary = false;
+ }
+ int cachedLen = binbufcnt;
+ binbufcnt = binbuf.length + 1; // full!
+ write(binbuf, 0, cachedLen);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (binbufcnt <= binbuf.length) {
+ decideMode();
+ }
+ out.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ flush();
+ if (buf == '\r') {
+ out.write(buf);
+ buf = -1;
+ }
+ out.close();
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolCanonicalizingInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolCanonicalizingInputStream.java
index 98485e9090..ee729e893e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolCanonicalizingInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolCanonicalizingInputStream.java
@@ -46,46 +46,16 @@ package org.eclipse.jgit.util.io;
import java.io.IOException;
import java.io.InputStream;
-import org.eclipse.jgit.diff.RawText;
-
/**
* An input stream which canonicalizes EOLs bytes on the fly to '\n'.
*
- * Optionally, a binary check on the first 8000 bytes is performed
- * and in case of binary files, canonicalization is turned off
- * (for the complete file).
+ * Optionally, a binary check on the first 8000 bytes is performed and in case
+ * of binary files, canonicalization is turned off (for the complete file).
+ *
+ * @deprecated use {@link AutoLFInputStream} instead
*/
-public class EolCanonicalizingInputStream extends InputStream {
- private final byte[] single = new byte[1];
-
- private final byte[] buf = new byte[8096];
-
- private final InputStream in;
-
- private int cnt;
-
- private int ptr;
-
- private boolean isBinary;
-
- private boolean detectBinary;
-
- private boolean abortIfBinary;
-
- /**
- * A special exception thrown when {@link EolCanonicalizingInputStream} is
- * told to throw an exception when attempting to read a binary file. The
- * exception may be thrown at any stage during reading.
- *
- * @since 3.3
- */
- public static class IsBinaryException extends IOException {
- private static final long serialVersionUID = 1L;
-
- IsBinaryException() {
- super();
- }
- }
+@Deprecated
+public class EolCanonicalizingInputStream extends AutoLFInputStream {
/**
* Creates a new InputStream, wrapping the specified stream
@@ -94,10 +64,9 @@ public class EolCanonicalizingInputStream extends InputStream {
* raw input stream
* @param detectBinary
* whether binaries should be detected
- * @since 2.0
*/
public EolCanonicalizingInputStream(InputStream in, boolean detectBinary) {
- this(in, detectBinary, false);
+ super(in, detectBinary);
}
/**
@@ -109,83 +78,25 @@ public class EolCanonicalizingInputStream extends InputStream {
* whether binaries should be detected
* @param abortIfBinary
* throw an IOException if the file is binary
- * @since 3.3
*/
public EolCanonicalizingInputStream(InputStream in, boolean detectBinary,
boolean abortIfBinary) {
- this.in = in;
- this.detectBinary = detectBinary;
- this.abortIfBinary = abortIfBinary;
- }
-
- @Override
- public int read() throws IOException {
- final int read = read(single, 0, 1);
- return read == 1 ? single[0] & 0xff : -1;
- }
-
- @Override
- public int read(byte[] bs, final int off, final int len) throws IOException {
- if (len == 0)
- return 0;
-
- if (cnt == -1)
- return -1;
-
- int i = off;
- final int end = off + len;
-
- while (i < end) {
- if (ptr == cnt && !fillBuffer()) {
- break;
- }
-
- byte b = buf[ptr++];
- if (isBinary || b != '\r') {
- // Logic for binary files ends here
- bs[i++] = b;
- continue;
- }
-
- if (ptr == cnt && !fillBuffer()) {
- bs[i++] = '\r';
- break;
- }
-
- if (buf[ptr] == '\n') {
- bs[i++] = '\n';
- ptr++;
- } else
- bs[i++] = '\r';
- }
-
- return i == off ? -1 : i - off;
+ super(in, detectBinary, abortIfBinary);
}
/**
- * @return true if the stream has detected as a binary so far
+ * A special exception thrown when {@link AutoLFInputStream} is told to
+ * throw an exception when attempting to read a binary file. The exception
+ * may be thrown at any stage during reading.
+ *
* @since 3.3
*/
- public boolean isBinary() {
- return isBinary;
- }
-
- @Override
- public void close() throws IOException {
- in.close();
- }
+ public static class IsBinaryException extends IOException {
+ private static final long serialVersionUID = 1L;
- private boolean fillBuffer() throws IOException {
- cnt = in.read(buf, 0, buf.length);
- if (cnt < 1)
- return false;
- if (detectBinary) {
- isBinary = RawText.isBinary(buf, cnt);
- detectBinary = false;
- if (isBinary && abortIfBinary)
- throw new IsBinaryException();
+ IsBinaryException() {
+ super();
}
- ptr = 0;
- return true;
}
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java
new file mode 100644
index 0000000000..c95992fbc2
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util.io;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.eclipse.jgit.attributes.Attributes;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
+import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
+import org.eclipse.jgit.treewalk.WorkingTreeOptions;
+
+/**
+ * Utility used to create input and output stream wrappers for
+ * {@link EolStreamType}
+ *
+ * @since 4.3
+ */
+public final class EolStreamTypeUtil {
+ private static final boolean FORCE_EOL_LF_ON_CHECKOUT = false;
+
+ private EolStreamTypeUtil() {
+ }
+
+ /**
+ * Convenience method used to detect if CRLF conversion has been configured
+ * using the
+ * <ul>
+ * <li>global repo options</li>
+ * <li>global attributes</li>
+ * <li>info attributes</li>
+ * <li>working tree .gitattributes</li>
+ *
+ * @param op
+ * is the {@link OperationType} of the current traversal
+ * @param options
+ * are the {@link Config} options with key
+ * {@link WorkingTreeOptions#KEY}
+ * @param attrs
+ * are the {@link Attributes} of the file for which the
+ * {@link EolStreamType} is to be detected
+ *
+ * @return the stream conversion {@link EolStreamType} to be performed for
+ * the selected {@link OperationType}
+ */
+ public static EolStreamType detectStreamType(OperationType op,
+ WorkingTreeOptions options, Attributes attrs) {
+ switch (op) {
+ case CHECKIN_OP:
+ return checkInStreamType(options, attrs);
+ case CHECKOUT_OP:
+ return checkOutStreamType(options, attrs);
+ default:
+ throw new IllegalArgumentException("unknown OperationType " + op); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * @param in
+ * original stream
+ * @param conversion
+ * to be performed
+ * @return the converted stream depending on {@link EolStreamType}
+ */
+ public static InputStream wrapInputStream(InputStream in,
+ EolStreamType conversion) {
+ switch (conversion) {
+ case TEXT_CRLF:
+ return new AutoCRLFInputStream(in, false);
+ case TEXT_LF:
+ return new AutoLFInputStream(in, false);
+ case AUTO_CRLF:
+ return new AutoCRLFInputStream(in, true);
+ case AUTO_LF:
+ return new AutoLFInputStream(in, true);
+ default:
+ return in;
+ }
+ }
+
+ /**
+ * @param out
+ * original stream
+ * @param conversion
+ * to be performed
+ * @return the converted stream depending on {@link EolStreamType}
+ */
+ public static OutputStream wrapOutputStream(OutputStream out,
+ EolStreamType conversion) {
+ switch (conversion) {
+ case TEXT_CRLF:
+ return new AutoCRLFOutputStream(out, false);
+ case AUTO_CRLF:
+ return new AutoCRLFOutputStream(out, true);
+ case TEXT_LF:
+ return new AutoLFOutputStream(out, false);
+ case AUTO_LF:
+ return new AutoLFOutputStream(out, true);
+ default:
+ return out;
+ }
+ }
+
+ private static EolStreamType checkInStreamType(WorkingTreeOptions options,
+ Attributes attrs) {
+ // old git system
+ if (attrs.isSet("crlf")) {//$NON-NLS-1$
+ return EolStreamType.TEXT_LF;
+ } else if (attrs.isUnset("crlf")) {//$NON-NLS-1$
+ return EolStreamType.DIRECT;
+ } else if ("input".equals(attrs.getValue("crlf"))) {//$NON-NLS-1$ //$NON-NLS-2$
+ return EolStreamType.TEXT_LF;
+ }
+
+ // new git system
+ if (attrs.isUnset("text")) {//$NON-NLS-1$
+ return EolStreamType.DIRECT;
+ }
+ String eol = attrs.getValue("eol"); //$NON-NLS-1$
+ if (eol != null)
+ // check-in is always normalized to LF
+ return EolStreamType.TEXT_LF;
+
+ if (attrs.isSet("text")) { //$NON-NLS-1$
+ return EolStreamType.TEXT_LF;
+ }
+
+ if ("auto".equals(attrs.getValue("text"))) { //$NON-NLS-1$ //$NON-NLS-2$
+ return EolStreamType.AUTO_LF;
+ }
+
+ switch (options.getAutoCRLF()) {
+ case TRUE:
+ case INPUT:
+ return EolStreamType.AUTO_LF;
+ case FALSE:
+ return EolStreamType.DIRECT;
+ }
+
+ return EolStreamType.DIRECT;
+ }
+
+ private static EolStreamType checkOutStreamType(WorkingTreeOptions options,
+ Attributes attrs) {
+ // old git system
+ if (attrs.isSet("crlf")) {//$NON-NLS-1$
+ return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF
+ : EolStreamType.DIRECT;
+ } else if (attrs.isUnset("crlf")) {//$NON-NLS-1$
+ return EolStreamType.DIRECT;
+ } else if ("input".equals(attrs.getValue("crlf"))) {//$NON-NLS-1$ //$NON-NLS-2$
+ return EolStreamType.DIRECT;
+ }
+
+ // new git system
+ if (attrs.isUnset("text")) {//$NON-NLS-1$
+ return EolStreamType.DIRECT;
+ }
+ String eol = attrs.getValue("eol"); //$NON-NLS-1$
+ if (eol != null && "crlf".equals(eol)) //$NON-NLS-1$
+ return EolStreamType.TEXT_CRLF;
+ if (eol != null && "lf".equals(eol)) //$NON-NLS-1$
+ return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF
+ : EolStreamType.DIRECT;
+
+ if (attrs.isSet("text")) { //$NON-NLS-1$
+ switch (options.getAutoCRLF()) {
+ case TRUE:
+ return EolStreamType.TEXT_CRLF;
+ default:
+ // no decision
+ }
+ switch (options.getEOL()) {
+ case CRLF:
+ return EolStreamType.TEXT_CRLF;
+ case LF:
+ return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF
+ : EolStreamType.DIRECT;
+ case NATIVE:
+ default:
+ return EolStreamType.DIRECT;
+ }
+ }
+
+ if ("auto".equals(attrs.getValue("text"))) { //$NON-NLS-1$ //$NON-NLS-2$
+ switch (options.getAutoCRLF()) {
+ case TRUE:
+ return EolStreamType.AUTO_CRLF;
+ default:
+ // no decision
+ }
+ switch (options.getEOL()) {
+ case CRLF:
+ return EolStreamType.AUTO_CRLF;
+ case LF:
+ return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF
+ : EolStreamType.DIRECT;
+ case NATIVE:
+ default:
+ return EolStreamType.DIRECT;
+ }
+ }
+
+ switch (options.getAutoCRLF()) {
+ case TRUE:
+ return EolStreamType.AUTO_CRLF;
+ default:
+ // no decision
+ }
+
+ return EolStreamType.DIRECT;
+ }
+
+}