Java tutorial
/* * 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 org.kuali.student.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.RevTree; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.kuali.student.git.model.tree.GitTreeData; import org.kuali.student.git.model.tree.GitTreeNodeData; import org.kuali.student.git.model.tree.GitTreeNodeInitializer; import org.kuali.student.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.release(); walk.release(); } /** * 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<String> 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.release(); 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.release(); 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.release(); return treeId; } else if (branchSubPath.length() == 0) { return parentCommit.getTree().getId(); } else return null; } }