diff options
author | Christian Halstrick <christian.halstrick@sap.com> | 2012-01-16 10:53:13 -0500 |
---|---|---|
committer | Code Review <codereview-daemon@eclipse.org> | 2012-01-16 10:53:13 -0500 |
commit | a9892fba462e03cec1bfa4fee9525fc9de108a2f (patch) | |
tree | 1c145091d0a80c885730cc897c25ae30e4a1c156 /org.eclipse.jgit | |
parent | 03b5416a35ad78773fb0a97a98686fec18c0c05e (diff) | |
parent | 76dd9d1d46007fc49639d264631658114f4fbd24 (diff) | |
download | jgit-a9892fba462e03cec1bfa4fee9525fc9de108a2f.tar.gz jgit-a9892fba462e03cec1bfa4fee9525fc9de108a2f.zip |
Merge "Support more of AutoCRLF"
Diffstat (limited to 'org.eclipse.jgit')
6 files changed, 258 insertions, 10 deletions
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 465f01ada9..9b397e88c9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -45,6 +45,7 @@ package org.eclipse.jgit.dircache; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; @@ -62,6 +63,7 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.CoreConfig.AutoCRLF; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.EmptyTreeIterator; @@ -73,6 +75,7 @@ import org.eclipse.jgit.treewalk.WorkingTreeOptions; import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; +import org.eclipse.jgit.util.io.AutoCRLFOutputStream; /** * This class handles checking out one or two trees merging with the index. @@ -926,14 +929,19 @@ public class DirCacheCheckout { ObjectLoader ol = or.open(entry.getObjectId()); File parentDir = f.getParentFile(); File tmpFile = File.createTempFile("._" + f.getName(), null, parentDir); - FileOutputStream channel = new FileOutputStream(tmpFile); + WorkingTreeOptions opt = repo.getConfig().get(WorkingTreeOptions.KEY); + FileOutputStream rawChannel = new FileOutputStream(tmpFile); + OutputStream channel; + if (opt.getAutoCRLF() == AutoCRLF.TRUE) + channel = new AutoCRLFOutputStream(rawChannel); + else + channel = rawChannel; try { ol.copyTo(channel); } finally { channel.close(); } FS fs = repo.getFS(); - WorkingTreeOptions opt = repo.getConfig().get(WorkingTreeOptions.KEY); if (opt.isFileMode() && fs.supportsExecute()) { if (FileMode.EXECUTABLE_FILE.equals(entry.getRawMode())) { if (!fs.canExecute(tmpFile)) @@ -954,6 +962,9 @@ public class DirCacheCheckout { } } entry.setLastModified(f.lastModified()); - entry.setLength((int) ol.getSize()); + if (opt.getAutoCRLF() != AutoCRLF.FALSE) + entry.setLength(f.length()); // AutoCRLF wants on-disk-size + else + entry.setLength((int) ol.getSize()); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/ObjectDirectoryInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/ObjectDirectoryInserter.java index 77902dfb40..ffd5c4149f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/ObjectDirectoryInserter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/ObjectDirectoryInserter.java @@ -97,8 +97,8 @@ class ObjectDirectoryInserter extends ObjectInserter { throws IOException { if (len <= buffer().length) { byte[] buf = buffer(); - IO.readFully(is, buf, 0, (int) len); - return insert(type, buf, 0, (int) len); + int actLen = IO.readFully(is, buf, 0); + return insert(type, buf, 0, actLen); } else { MessageDigest md = digest(); 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 2a42e05d39..fa57b71ad1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java @@ -72,6 +72,7 @@ import org.eclipse.jgit.ignore.IgnoreNode; import org.eclipse.jgit.ignore.IgnoreRule; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.CoreConfig; +import org.eclipse.jgit.lib.CoreConfig.AutoCRLF; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; @@ -402,7 +403,7 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { } } - private InputStream filterClean(InputStream in) { + private InputStream filterClean(InputStream in) throws IOException { return new EolCanonicalizingInputStream(in); } @@ -498,7 +499,13 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { * the file could not be opened for reading. */ public InputStream openEntryStream() throws IOException { - return current().openInputStream(); + InputStream rawis = current().openInputStream(); + InputStream is; + if (getOptions().getAutoCRLF() != AutoCRLF.FALSE) + is = new EolCanonicalizingInputStream(rawis); + else + is = rawis; + return is; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java index 439fe09b5e..cafc94057b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java @@ -142,7 +142,13 @@ public class IO { throw new IOException(MessageFormat.format( JGitText.get().fileIsTooLarge, path)); final byte[] buf = new byte[(int) sz]; - IO.readFully(in, buf, 0, buf.length); + int actSz = IO.readFully(in, buf, 0); + + if (actSz == sz) { + byte[] ret = new byte[actSz]; + System.arraycopy(buf, 0, ret, 0, actSz); + return ret; + } return buf; } finally { try { @@ -254,6 +260,31 @@ public class IO { } /** + * Read the entire byte array into memory, unless input is shorter + * + * @param fd + * input stream to read the data from. + * @param dst + * buffer that must be fully populated, [off, off+len). + * @param off + * position within the buffer to start writing to. + * @return number of bytes in buffer or stream, whichever is shortest + * @throws IOException + * there was an error reading from the stream. + */ + public static int readFully(InputStream fd, byte[] dst, int off) + throws IOException { + int r; + int len = 0; + while ((r = fd.read(dst, off, dst.length - off)) >= 0 + && len < dst.length) { + off += r; + len += r; + } + return len; + } + + /** * Skip an entire region of an input stream. * <p> * The input stream's position is moved forward by the number of requested 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 new file mode 100644 index 0000000000..a4c1573909 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2011, Robin Rosenberg + * 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.OutputStream; + +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. + */ +public class AutoCRLFOutputStream extends OutputStream { + + private final OutputStream out; + + private int buf = -1; + + private byte[] binbuf = new byte[8000]; + + private int binbufcnt = 0; + + private boolean isBinary; + + /** + * @param out + */ + public AutoCRLFOutputStream(OutputStream out) { + this.out = out; + } + + @Override + public void write(int b) throws IOException { + int overflow = buffer((byte) b); + if (overflow >= 0) + return; + if (isBinary) { + out.write(b); + return; + } + if (b == '\n') { + if (buf == '\r') { + out.write('\n'); + buf = -1; + } else if (buf == -1) { + out.write('\r'); + out.write('\n'); + buf = -1; + } + } else if (b == '\r') { + out.write(b); + buf = '\r'; + } else { + out.write(b); + buf = -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, int off, int len) throws IOException { + int overflow = buffer(b, off, len); + if (overflow < 0) + return; + off = off + len - overflow; + 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) { + byte c = b[i]; + if (c == '\r') { + buf = '\r'; + } else if (c == '\n') { + if (buf != '\r') { + if (lastw < i) { + out.write(b, lastw, i - lastw); + } + out.write('\r'); + lastw = i; + } + buf = -1; + } else { + buf = -1; + } + } + if (lastw < off + len) { + out.write(b, lastw, off + len - lastw); + } + if (b[off + len - 1] == '\r') + buf = '\r'; + } + + private int buffer(byte b) throws IOException { + if (binbufcnt > binbuf.length) + return 1; + binbuf[binbufcnt++] = b; + if (binbufcnt == binbuf.length) + decideMode(); + return 0; + } + + 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 { + isBinary = RawText.isBinary(binbuf, binbufcnt); + int cachedLen = binbufcnt; + binbufcnt = binbuf.length + 1; // full! + write(binbuf, 0, cachedLen); + } + + @Override + public void flush() throws IOException { + if (binbufcnt < binbuf.length) + decideMode(); + buf = -1; + } + + @Override + public void close() throws IOException { + flush(); + super.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 4bdd2b3e55..387d9b82bf 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,8 +46,11 @@ 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'. + * An input stream which canonicalizes EOLs bytes on the fly to '\n', unless the + * first 8000 bytes indicate the stream is binary. * * Note: Make sure to apply this InputStream only to text files! */ @@ -62,6 +65,10 @@ public class EolCanonicalizingInputStream extends InputStream { private int ptr; + private boolean isBinary; + + private boolean modeDetected; + /** * Creates a new InputStream, wrapping the specified stream * @@ -95,7 +102,8 @@ public class EolCanonicalizingInputStream extends InputStream { } byte b = buf[ptr++]; - if (b != '\r') { + if (isBinary || b != '\r') { + // Logic for binary files ends here bs[off++] = b; continue; } @@ -124,6 +132,10 @@ public class EolCanonicalizingInputStream extends InputStream { cnt = in.read(buf, 0, buf.length); if (cnt < 1) return false; + if (!modeDetected) { + isBinary = RawText.isBinary(buf, cnt); + modeDetected = true; + } ptr = 0; return true; } |