io.github.svndump_to_git.git.model.tree.utils.GitTreeProcessor Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2014 The Kuali Foundation Licensed under the
* Educational Community License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.osedu.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS"
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package io.github.svndump_to_git.git.model.tree.utils;
import java.io.IOException;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
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.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import io.github.svndump_to_git.git.model.tree.GitTreeData;
import io.github.svndump_to_git.git.model.tree.GitTreeNodeData;
import io.github.svndump_to_git.git.model.tree.GitTreeNodeInitializer;
import io.github.svndump_to_git.git.model.tree.GitTreeNodeInitializerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Kuali Student Team
*
*/
public class GitTreeProcessor {
private static final Logger log = LoggerFactory
.getLogger(GitTreeProcessor.class);
private Repository repo;
private ObjectReader objectReader;
private GitTreeNodeInitializer nodeInitializer;
/**
*
*/
public GitTreeProcessor(Repository repo) {
this.repo = repo;
this.nodeInitializer = new GitTreeNodeInitializerImpl(this);
this.objectReader = repo.newObjectReader();
}
/**
* @return the nodeInitializer
*/
public GitTreeNodeInitializer getNodeInitializer() {
return nodeInitializer;
}
public static interface GitTreeBlobVisitor {
/**
*
* @param blobId
* @param path
* @return true if the visiting should continue; false if it should
* stop.
*
*/
public boolean visitBlob(ObjectId blobId, String path, String name)
throws MissingObjectException, IncorrectObjectTypeException,
IOException;
}
public static interface GitTreePathVisitor {
public boolean visitPath(String path, String name);
}
public void visitBlobs(ObjectId commitId, GitTreeBlobVisitor visitor)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
visitBlobs(commitId, visitor, null);
}
public void visitBlobs(ObjectId commitId, GitTreeBlobVisitor visitor,
TreeFilter treeFilter) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
RevWalk walk = new RevWalk(repo);
RevCommit commit = walk.parseCommit(commitId);
// a commit points to a tree
ObjectId treeId = commit.getTree().getId();
TreeWalk treeWalk = new TreeWalk(repo);
treeWalk.addTree(treeId);
treeWalk.setRecursive(true);
if (treeFilter != null)
treeWalk.setFilter(treeFilter);
if (treeWalk.getTreeCount() == 0) {
log.warn("no trees to parse");
}
while (treeWalk.next()) {
final FileMode mode = treeWalk.getFileMode(0);
if (mode != FileMode.REGULAR_FILE)
continue;
/*
* We only want the blob's
*/
ObjectId blobId = treeWalk.getObjectId(0);
String path = treeWalk.getPathString();
String name = treeWalk.getNameString();
if (!visitor.visitBlob(blobId, path, name))
return; // stop when the visitor indicates its done.
}
treeWalk.close();
walk.close();
}
/**
* Compute if the path given exists in the commit tree.
*
* @param commitId
* @param path
* @return true if the path exists in the commit tree.
* @throws MissingObjectException
* @throws IncorrectObjectTypeException
* @throws IOException
*/
public boolean treeContainsPath(ObjectId commitId, String path)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
ObjectId objectId = getObjectId(commitId, path);
if (objectId != null)
return true;
else
return false;
}
public ObjectLoader getBlob(ObjectId blobId) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
return objectReader.open(blobId, Constants.OBJ_BLOB);
}
public List getBlobAsStringLines(ObjectId blobId)
throws MissingObjectException, IOException {
ObjectLoader loader = getBlob(blobId);
return IOUtils.readLines(loader.openStream());
}
/**
* Extract the existing Git Tree Data for the commit indicated.
*
* We index the blob's but also note the object id's of the tree's so that
* we can optimize creation of the new tree data at the end.
*
* i.e. only have to create new trees for the data that has changed.
*
* @param parentId
* @return the fully constructed mutable GitTreeData structure representing
* the tree committed in the indicated parent commit.
* @throws MissingObjectException
* @throws IncorrectObjectTypeException
* @throws IOException
*/
public GitTreeData extractExistingTreeDataFromCommit(ObjectId parentId)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
ObjectId treeId = getTreeId(parentId);
GitTreeData tree = new GitTreeData(nodeInitializer);
if (treeId == null)
return tree;
GitTreeNodeData root = extractExistingTreeData(treeId, "");
tree.setRoot(root);
return tree;
}
public GitTreeNodeData extractExistingTreeData(ObjectId treeId, String name)
throws MissingObjectException, IncorrectObjectTypeException,
CorruptObjectException, IOException {
GitTreeNodeData treeData = new GitTreeNodeData(nodeInitializer, name);
treeData.setGitTreeObjectId(treeId);
TreeWalk tw = new TreeWalk(repo);
tw.setRecursive(false);
tw.addTree(treeId);
while (tw.next()) {
FileMode fileMode = tw.getFileMode(0);
String entryName = tw.getNameString();
ObjectId objectId = tw.getObjectId(0);
if (fileMode.equals(FileMode.TREE)) {
GitTreeNodeData subTree = new GitTreeNodeData(nodeInitializer,
entryName);
subTree.setGitTreeObjectId(objectId);
treeData.addDirectTree(entryName, subTree);
} else if (fileMode.equals(FileMode.REGULAR_FILE)) {
treeData.addDirectBlob(entryName, objectId);
}
}
/*
* This tree is initialized the subtree's are not.
*/
treeData.setInitialized(true);
treeData.setDirty(false);
tw.close();
return treeData;
}
public ObjectId getTreeId(ObjectId parentId) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
return getObjectId(parentId, "");
}
public ObjectId getObjectId(ObjectId parentId, String branchSubPath)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
ObjectId treeId = null;
RevWalk rw = new RevWalk(repo);
RevCommit parentCommit = rw.parseCommit(parentId);
rw.close();
String[] subPathParts = branchSubPath.split("/");
int currentPartIndex = 0;
if (branchSubPath != null && !branchSubPath.isEmpty()) {
TreeWalk tw = new TreeWalk(repo);
tw.addTree(parentCommit.getTree().getId());
while (tw.next()) {
String currentPathPart = subPathParts[currentPartIndex];
if (currentPartIndex == (subPathParts.length - 1)) {
// on the last element consider blobs
String name = tw.getNameString();
if (name.equals(currentPathPart)) {
treeId = tw.getObjectId(0);
break;
}
} else {
if (tw.getFileMode(0).equals(FileMode.TYPE_TREE)) {
String name = tw.getNameString();
if (name.equals(currentPathPart)) {
currentPartIndex++;
if (currentPartIndex >= subPathParts.length) {
// we are done
treeId = tw.getObjectId(0);
break;
} else {
tw.enterSubtree();
}
}
}
}
}
tw.close();
return treeId;
}
else if (branchSubPath.length() == 0) {
return parentCommit.getTree().getId();
}
else
return null;
}
}