Browse Source

Handle content length in WorkingTreeIterator

Content length is computed and cached (short term) in the working
tree iterator when core.autocrlf is set.

Hopefully this is a cleaner fix than my previous attempt to make
autocrlf work.

Change-Id: I1b6bbb643101a00db94e5514b5e2b069f338907a
tags/v2.0.0.201206130900-r
Robin Rosenberg 12 years ago
parent
commit
3f4725c179

+ 30
- 38
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java View File

package org.eclipse.jgit.api; package org.eclipse.jgit.api;


import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;


import java.io.File; import java.io.File;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryTestCase; import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
} }


@Test @Test
public void testAddExistingSingleFileWithNewLine() throws IOException,
public void testAddExistingSingleSmallFileWithNewLine() throws IOException,
NoFilepatternException { NoFilepatternException {
File file = new File(db.getWorkTree(), "a.txt"); File file = new File(db.getWorkTree(), "a.txt");
FileUtils.createNewFile(file); FileUtils.createNewFile(file);
indexState(CONTENT)); indexState(CONTENT));
} }


@Test
public void testAddExistingSingleMediumSizeFileWithNewLine()
throws IOException, NoFilepatternException {
File file = new File(db.getWorkTree(), "a.txt");
FileUtils.createNewFile(file);
StringBuilder data = new StringBuilder();
for (int i = 0; i < 1000; ++i) {
data.append("row1\r\nrow2");
}
String crData = data.toString();
PrintWriter writer = new PrintWriter(file);
writer.print(crData);
writer.close();
String lfData = data.toString().replaceAll("\r", "");
Git git = new Git(db);
db.getConfig().setString("core", null, "autocrlf", "false");
git.add().addFilepattern("a.txt").call();
assertEquals("[a.txt, mode:100644, content:" + data + "]",
indexState(CONTENT));
db.getConfig().setString("core", null, "autocrlf", "true");
git.add().addFilepattern("a.txt").call();
assertEquals("[a.txt, mode:100644, content:" + lfData + "]",
indexState(CONTENT));
db.getConfig().setString("core", null, "autocrlf", "input");
git.add().addFilepattern("a.txt").call();
assertEquals("[a.txt, mode:100644, content:" + lfData + "]",
indexState(CONTENT));
}

@Test @Test
public void testAddExistingSingleBinaryFile() throws IOException, public void testAddExistingSingleBinaryFile() throws IOException,
NoFilepatternException { NoFilepatternException {
assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0)); assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
} }


@Test
public void testSubmoduleDeleteNotStagedWithUpdate() throws Exception {
Git git = new Git(db);
writeTrashFile("file.txt", "content");
git.add().addFilepattern("file.txt").call();
assertNotNull(git.commit().setMessage("create file").call());

SubmoduleAddCommand command = new SubmoduleAddCommand(db);
String path = "sub";
command.setPath(path);
String uri = db.getDirectory().toURI().toString();
command.setURI(uri);
Repository repo = command.call();
assertNotNull(repo);
assertNotNull(git.commit().setMessage("add submodule").call());

assertTrue(git.status().call().isClean());

FileUtils.delete(repo.getWorkTree(), FileUtils.RECURSIVE);
FileUtils.mkdir(new File(db.getWorkTree(), path), false);

assertNotNull(git.add().addFilepattern(".").setUpdate(true).call());

Status status = git.status().call();
assertFalse(status.isClean());
assertTrue(status.getAdded().isEmpty());
assertTrue(status.getChanged().isEmpty());
assertTrue(status.getRemoved().isEmpty());
assertTrue(status.getUntracked().isEmpty());
assertTrue(status.getModified().isEmpty());
assertEquals(1, status.getMissing().size());
assertEquals(path, status.getMissing().iterator().next());
}

private DirCacheEntry addEntryToBuilder(String path, File file, private DirCacheEntry addEntryToBuilder(String path, File file,
ObjectInserter newObjectInserter, DirCacheBuilder builder, int stage) ObjectInserter newObjectInserter, DirCacheBuilder builder, int stage)
throws IOException { throws IOException {

+ 3
- 1
org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java View File

entry.setLength(sz); entry.setLength(sz);
entry.setLastModified(f entry.setLastModified(f
.getEntryLastModified()); .getEntryLastModified());
long contentSize = f
.getEntryContentLength();
InputStream in = f.openEntryStream(); InputStream in = f.openEntryStream();
try { try {
entry.setObjectId(inserter.insert( entry.setObjectId(inserter.insert(
Constants.OBJ_BLOB, sz, in));
Constants.OBJ_BLOB, contentSize, in));
} finally { } finally {
in.close(); in.close();
} }

+ 2
- 2
org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java View File

// insert object // insert object
if (inserter == null) if (inserter == null)
inserter = repo.newObjectInserter(); inserter = repo.newObjectInserter();
long contentLength = fTree.getEntryContentLength();
InputStream inputStream = fTree.openEntryStream(); InputStream inputStream = fTree.openEntryStream();
try { try {
dcEntry.setObjectId(inserter.insert( dcEntry.setObjectId(inserter.insert(
Constants.OBJ_BLOB, entryLength,
Constants.OBJ_BLOB, contentLength,
inputStream)); inputStream));
} finally { } finally {
inputStream.close(); inputStream.close();

+ 2
- 2
org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java View File

entry.setLength(wtIter.getEntryLength()); entry.setLength(wtIter.getEntryLength());
entry.setLastModified(wtIter.getEntryLastModified()); entry.setLastModified(wtIter.getEntryLastModified());
entry.setFileMode(wtIter.getEntryFileMode()); entry.setFileMode(wtIter.getEntryFileMode());
long contentLength = wtIter.getEntryContentLength();
InputStream in = wtIter.openEntryStream(); InputStream in = wtIter.openEntryStream();
try { try {
entry.setObjectId(inserter.insert( entry.setObjectId(inserter.insert(
Constants.OBJ_BLOB,
wtIter.getEntryLength(), in));
Constants.OBJ_BLOB, contentLength, in));
} finally { } finally {
in.close(); in.close();
} }

+ 2
- 1
org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java View File

@Override @Override
public ObjectStream openStream() throws MissingObjectException, public ObjectStream openStream() throws MissingObjectException,
IOException { IOException {
long contentLength = ptr.getEntryContentLength();
InputStream in = ptr.openEntryStream(); InputStream in = ptr.openEntryStream();
in = new BufferedInputStream(in); in = new BufferedInputStream(in);
return new ObjectStream.Filter(getType(), getSize(), in);
return new ObjectStream.Filter(getType(), contentLength, in);
} }


@Override @Override

+ 72
- 35
org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java View File

import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig; import org.eclipse.jgit.lib.CoreConfig;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
/** Repository that is the root level being iterated over */ /** Repository that is the root level being iterated over */
protected Repository repository; protected Repository repository;


/** Cached canonical length, initialized from {@link #idBuffer()} */
private long canonLen = -1;

/** /**
* Create a new iterator with no parent. * Create a new iterator with no parent.
* *
state.initializeDigestAndReadBuffer(); state.initializeDigestAndReadBuffer();


final long len = e.getLength(); final long len = e.getLength();
if (!mightNeedCleaning())
return computeHash(is, len);

if (len <= MAXIMUM_FILE_SIZE_TO_READ_FULLY) {
ByteBuffer rawbuf = IO.readWholeStream(is, (int) len);
byte[] raw = rawbuf.array();
int n = rawbuf.limit();
if (!isBinary(raw, n)) {
rawbuf = filterClean(raw, n);
raw = rawbuf.array();
n = rawbuf.limit();
}
return computeHash(new ByteArrayInputStream(raw, 0, n), n);
}

if (isBinary(e))
return computeHash(is, len);

final long canonLen;
final InputStream lenIs = filterClean(e.openInputStream());
try {
canonLen = computeLength(lenIs);
} finally {
safeClose(lenIs);
}

return computeHash(filterClean(is), canonLen);
InputStream filteredIs = possiblyFilteredInputStream(e, is, len);
return computeHash(filteredIs, canonLen);
} finally { } finally {
safeClose(is); safeClose(is);
} }
} }
} }


private InputStream possiblyFilteredInputStream(final Entry e,
final InputStream is, final long len) throws IOException {
InputStream filteredIs;
if (!mightNeedCleaning()) {
filteredIs = is;
canonLen = len;
} else {
if (len <= MAXIMUM_FILE_SIZE_TO_READ_FULLY) {
ByteBuffer rawbuf = IO.readWholeStream(is, (int) len);
byte[] raw = rawbuf.array();
int n = rawbuf.limit();
if (!isBinary(raw, n)) {
rawbuf = filterClean(raw, n);
raw = rawbuf.array();
n = rawbuf.limit();
}
filteredIs = new ByteArrayInputStream(raw, 0, n);
canonLen = n;
} else {
if (isBinary(e)) {
filteredIs = is;
canonLen = len;
} else {
final InputStream lenIs = filterClean(e
.openInputStream());
try {
canonLen = computeLength(lenIs);
} finally {
safeClose(lenIs);
}
filteredIs = filterClean(is);
}
}
}
return filteredIs;
}

private static void safeClose(final InputStream in) { private static void safeClose(final InputStream in) {
try { try {
in.close(); in.close();
@Override @Override
public void next(final int delta) throws CorruptObjectException { public void next(final int delta) throws CorruptObjectException {
ptr += delta; ptr += delta;
if (!eof())
if (!eof()) {
canonLen = -1;
parseEntry(); parseEntry();
}
} }


@Override @Override
} }


/** /**
* Get the byte length of this entry.
* Get the raw byte length of this entry.
* *
* @return size of this file, in bytes. * @return size of this file, in bytes.
*/ */
return current().getLength(); return current().getLength();
} }


/**
* Get the filtered input length of this entry
*
* @return size of the content, in bytes
* @throws IOException
*/
public long getEntryContentLength() throws IOException {
if (canonLen == -1) {
long rawLen = getEntryLength();
if (rawLen == 0)
canonLen = 0;
InputStream is = current().openInputStream();
try {
// canonLen gets updated here
possiblyFilteredInputStream(current(), is, current()
.getLength());
} finally {
safeClose(is);
}
}
return canonLen;
}

/** /**
* Get the last modified time of this entry. * Get the last modified time of this entry.
* *
*/ */
public InputStream openEntryStream() throws IOException { public InputStream openEntryStream() throws IOException {
InputStream rawis = current().openInputStream(); InputStream rawis = current().openInputStream();
InputStream is;
if (getOptions().getAutoCRLF() != AutoCRLF.FALSE)
is = new EolCanonicalizingInputStream(rawis, true);
if (mightNeedCleaning())
return filterClean(rawis);
else else
is = rawis;
return is;
return rawis;
} }


/** /**

Loading…
Cancel
Save