package com.link_intersystems.gitdirstat.domain;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
public class IndexUpdate {
String rewriteBranchName = "rewrite_branch";
private HistoryUpdate historyUpdate;
private GitRepository gitRepository;
private CacheCommitUpdate cacheCommitUpdate;
private Set<ObjectId> touchedCommits = new HashSet<ObjectId>();
private DirCache dirCache;
private CachingObjectReader cachingObjectReader;
IndexUpdate(GitRepository gitRepository, HistoryUpdate historyUpdate) {
this.gitRepository = gitRepository;
this.historyUpdate = historyUpdate;
ObjectReader objectReader = gitRepository.getObjectReader();
cachingObjectReader = new CachingObjectReader(objectReader);
}
public CacheCommitUpdate beginUpdate(Commit commit) throws GitAPIException,
IOException {
cacheCommitUpdate = new CacheCommitUpdate(gitRepository, commit,
historyUpdate, this);
return cacheCommitUpdate;
}
public void close() throws GitAPIException {
cachingObjectReader.release();
if (dirCache != null) {
dirCache.unlock();
}
}
Set<ObjectId> getTouchedCommits() {
return touchedCommits;
}
public DirCache getDirCache() {
if (dirCache == null) {
dirCache = DirCache.newInCore();
}
return dirCache;
}
public DirCache resetDirCache(Commit commit) throws IOException {
DirCache dirCache = getDirCache();
RevCommit revCommit = commit.getRevCommit();
touchedCommits.add(revCommit);
resetIndex(revCommit, dirCache);
return dirCache;
}
private void resetIndex(RevCommit revCommit, DirCache dirCache)
throws IOException {
TreeWalk walk = new TreeWalk(cachingObjectReader);
walk.setRecursive(true);
RevTree revTree = revCommit.getTree();
walk.addTree(revTree);
DirCacheBuilder builder = dirCache.builder();
walk.addTree(new DirCacheIterator(dirCache));
buildDirCache(walk, builder);
builder.finish();
}
private void buildDirCache(TreeWalk walk, DirCacheBuilder builder)
throws MissingObjectException, IncorrectObjectTypeException,
CorruptObjectException, IOException {
while (walk.next()) {
AbstractTreeIterator cIter = walk.getTree(0,
AbstractTreeIterator.class);
if (cIter == null) {
// Not in commit, don't add to new index
continue;
}
final DirCacheEntry entry = new DirCacheEntry(walk.getRawPath());
entry.setFileMode(cIter.getEntryFileMode());
entry.setObjectIdFromRaw(cIter.idBuffer(), cIter.idOffset());
DirCacheIterator dcIter = walk.getTree(1, DirCacheIterator.class);
if (dcIter != null && dcIter.idEqual(cIter)) {
DirCacheEntry indexEntry = dcIter.getDirCacheEntry();
entry.setLastModified(indexEntry.getLastModified());
entry.setLength(indexEntry.getLength());
}
builder.add(entry);
}
}
private static class CachingObjectReader extends ObjectReader {
private Map<ObjectId, ObjectLoader> objectLoaderCache = new HashMap<ObjectId, ObjectLoader>();
private ObjectReader delegate;
public CachingObjectReader(ObjectReader delegate) {
this.delegate = delegate;
}
private CachingObjectReader(Map<ObjectId, ObjectLoader> rawTreeCache,
ObjectReader delegate) {
this.objectLoaderCache = rawTreeCache;
this.delegate = delegate;
}
@Override
public ObjectReader newReader() {
return new CachingObjectReader(objectLoaderCache, delegate);
}
@Override
public Collection<ObjectId> resolve(AbbreviatedObjectId id)
throws IOException {
return delegate.resolve(id);
}
@Override
public ObjectLoader open(AnyObjectId objectId, int typeHint)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
ObjectLoader objectLoader = objectLoaderCache.get(objectId);
if (objectLoader == null) {
objectLoader = delegate.open(objectId, Constants.OBJ_TREE);
objectLoaderCache.put(objectId.copy(), objectLoader);
}
return objectLoader;
}
@Override
public Set<ObjectId> getShallowCommits() throws IOException {
return delegate.getShallowCommits();
}
@Override
public void release() {
super.release();
objectLoaderCache.clear();
}
}
}