All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gitective.core.TreeUtils Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2011 Kevin Sawicki 
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */
package org.gitective.core;

import static org.eclipse.jgit.lib.FileMode.TYPE_MASK;
import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;
import static org.eclipse.jgit.treewalk.filter.TreeFilter.ANY_DIFF;

import java.io.IOException;

import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.MutableObjectId;
import org.eclipse.jgit.lib.ObjectId;
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.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;

/**
 * Utilities for dealing with Git trees.
 */
public abstract class TreeUtils {

	/**
	 * Interface for visiting elements in a tree
	 */
	public static interface ITreeVisitor {

		/**
		 * Visit the given element
		 *
		 * @param mode
		 *            mode of current entry
		 * @param path
		 *            parent path of entry, null for root entries
		 * @param name
		 *            name of current entry
		 * @param id
		 *            id of current entry
		 * @return true to continue, false to abort
		 */
		boolean accept(FileMode mode, String path, String name, AnyObjectId id);
	}

	/**
	 * Get the tree associated with the given commit.
	 *
	 * @param walk
	 * @param commit
	 * @return tree
	 * @throws IOException
	 */
	protected static RevTree getTree(final RevWalk walk, final RevCommit commit)
			throws IOException {
		final RevTree tree = commit.getTree();
		if (tree != null)
			return tree;
		walk.parseHeaders(commit);
		return commit.getTree();
	}

	/**
	 * Create a tree walk with the commit's parents.
	 *
	 * @param reader
	 * @param rWalk
	 * @param commit
	 * @return tree walk
	 * @throws IOException
	 */
	protected static TreeWalk withParents(final ObjectReader reader,
			final RevWalk rWalk, final RevCommit commit) throws IOException {
		final TreeWalk walk = new TreeWalk(reader);
		final int parentCount = commit.getParentCount();
		switch (parentCount) {
		case 0:
			walk.addTree(new EmptyTreeIterator());
			break;
		case 1:
			walk.addTree(getTree(rWalk, commit.getParent(0)));
			break;
		default:
			final RevCommit[] parents = commit.getParents();
			for (int i = 0; i < parentCount; i++)
				walk.addTree(getTree(rWalk, parents[i]));
		}
		walk.addTree(getTree(rWalk, commit));
		return walk;
	}

	/**
	 * Create a tree walk with all the trees from the given commit's parents.
	 *
	 * @param repository
	 * @param commitId
	 * @return tree walk
	 */
	public static TreeWalk withParents(final Repository repository,
			final AnyObjectId commitId) {
		if (repository == null)
			throw new IllegalArgumentException(
					Assert.formatNotNull("Repository"));
		if (commitId == null)
			throw new IllegalArgumentException(
					Assert.formatNotNull("Commit id"));

		final ObjectReader reader = repository.newObjectReader();
		final RevWalk walk = new RevWalk(reader);
		try {
			return withParents(reader, walk, walk.parseCommit(commitId));
		} catch (IOException e) {
			walk.close();
			throw new GitException(e, repository);
		}
	}

	/**
	 * Create a tree walk with all the trees from the given revision's commit
	 * parents.
	 *
	 * @param repository
	 * @param revision
	 * @return tree walk
	 */
	public static TreeWalk withParents(final Repository repository,
			final String revision) {
		if (repository == null)
			throw new IllegalArgumentException(
					Assert.formatNotNull("Repository"));
		if (revision == null)
			throw new IllegalArgumentException(Assert.formatNotNull("Revision"));
		if (revision.length() == 0)
			throw new IllegalArgumentException(
					Assert.formatNotEmpty("Revision"));

		final ObjectId commit = CommitUtils.strictResolve(repository, revision);
		final ObjectReader reader = repository.newObjectReader();
		final RevWalk walk = new RevWalk(reader);
		try {
			return withParents(reader, walk, walk.parseCommit(commit));
		} catch (IOException e) {
			walk.close();
			throw new GitException(e, repository);
		}
	}

	/**
	 * Create a tree walk with all the trees from the given commit's parents.
	 *
	 * @param walk
	 * @param commit
	 * @return tree walk
	 */
	public static TreeWalk withParents(final RevWalk walk,
			final RevCommit commit) {
		if (walk == null)
			throw new IllegalArgumentException(Assert.formatNotNull("Walk"));
		if (commit == null)
			throw new IllegalArgumentException(Assert.formatNotNull("Commit"));

		try {
			return withParents(walk.getObjectReader(), walk, commit);
		} catch (IOException e) {
			throw new GitException(e, null);
		}
	}

	/**
	 * Create a tree walk configured to diff the given commit against all the
	 * parent commits.
	 *
	 * @param repository
	 * @param commitId
	 * @return tree walk
	 */
	public static TreeWalk diffWithParents(final Repository repository,
			final AnyObjectId commitId) {
		final TreeWalk walk = withParents(repository, commitId);
		walk.setFilter(ANY_DIFF);
		return walk;
	}

	/**
	 * Create a tree walk configured to diff the given commit against all the
	 * parent commits.
	 *
	 * @param walk
	 * @param commit
	 * @return tree walk
	 */
	public static TreeWalk diffWithParents(final RevWalk walk,
			final RevCommit commit) {
		final TreeWalk treeWalk = withParents(walk, commit);
		treeWalk.setFilter(ANY_DIFF);
		return treeWalk;
	}

	/**
	 * Create a tree walk configured to diff the given revision against all the
	 * parent commits.
	 *
	 * @param repository
	 * @param revision
	 * @return tree walk
	 */
	public static TreeWalk diffWithParents(final Repository repository,
			final String revision) {
		final TreeWalk walk = withParents(repository, revision);
		walk.setFilter(ANY_DIFF);
		return walk;
	}

	/**
	 * Create a tree walk configured with the given commit revisions
	 *
	 * @param repository
	 * @param revisions
	 * @return tree walk
	 */
	public static TreeWalk withCommits(final Repository repository,
			final String... revisions) {
		if (repository == null)
			throw new IllegalArgumentException(
					Assert.formatNotNull("Repository"));
		if (revisions == null)
			throw new IllegalArgumentException(
					Assert.formatNotNull("Revisions"));
		if (revisions.length == 0)
			throw new IllegalArgumentException(
					Assert.formatNotEmpty("Revisions"));

		final TreeWalk walk = new TreeWalk(repository);
		try {
			for (String revision : revisions)
				walk.addTree(CommitUtils.getCommit(repository, revision)
						.getTree());
		} catch (IOException e) {
			throw new GitException(e, repository);
		}
		return walk;
	}

	/**
	 * Create a tree walk configured with the given commits
	 *
	 * @param repository
	 * @param commits
	 * @return tree walk
	 */
	public static TreeWalk withCommits(final Repository repository,
			final ObjectId... commits) {
		if (repository == null)
			throw new IllegalArgumentException(
					Assert.formatNotNull("Repository"));
		if (commits == null)
			throw new IllegalArgumentException(Assert.formatNotNull("Commits"));
		if (commits.length == 0)
			throw new IllegalArgumentException(Assert.formatNotEmpty("Commits"));

		final TreeWalk walk = new TreeWalk(repository);
		try {
			for (ObjectId commit : commits)
				walk.addTree(CommitUtils.getCommit(repository, commit)
						.getTree());
		} catch (IOException e) {
			throw new GitException(e, repository);
		}
		return walk;
	}

	/**
	 * Create a tree walk configured to diff the given commits
	 *
	 * @param repository
	 * @param commits
	 * @return tree walk
	 */
	public static TreeWalk diffWithCommits(final Repository repository,
			final ObjectId... commits) {
		final TreeWalk walk = withCommits(repository, commits);
		walk.setFilter(ANY_DIFF);
		return walk;
	}

	/**
	 * Create a tree walk configured to diff the given commit revisions
	 *
	 * @param repository
	 * @param revisions
	 * @return tree walk
	 */
	public static TreeWalk diffWithCommits(final Repository repository,
			final String... revisions) {
		final TreeWalk walk = withCommits(repository, revisions);
		walk.setFilter(ANY_DIFF);
		return walk;
	}

	/**
	 * Get the id of the tree at the path in the given commit.
	 *
	 * @param repository
	 * @param commit
	 * @param path
	 * @return tree id, null if not present
	 */
	protected static ObjectId lookupId(final Repository repository,
			final RevCommit commit, final String path) {
		final TreeWalk walk;
		try {
			walk = TreeWalk.forPath(repository, path, commit.getTree());
		} catch (IOException e) {
			throw new GitException(e, repository);
		}
		if (walk == null)
			return null;
		if ((walk.getRawMode(0) & TYPE_MASK) != TYPE_TREE)
			return null;
		return walk.getObjectId(0);
	}

	/**
	 * Get the id of the tree at the path in the given commit
	 *
	 * @param repository
	 * @param commitId
	 * @param path
	 * @return tree id or null if no tree id at path
	 */
	public static ObjectId getId(final Repository repository,
			final ObjectId commitId, final String path) {
		if (repository == null)
			throw new IllegalArgumentException(
					Assert.formatNotNull("Repository"));
		if (commitId == null)
			throw new IllegalArgumentException(
					Assert.formatNotNull("Commit Id"));
		if (path == null)
			throw new IllegalArgumentException(Assert.formatNotNull("Path"));
		if (path.length() == 0)
			throw new IllegalArgumentException(Assert.formatNotNull("Path"));

		final RevCommit commit = CommitUtils.parse(repository, commitId);
		return lookupId(repository, commit, path);
	}

	/**
	 * Get the id of the tree at the path in the given revision
	 *
	 * @param repository
	 * @param revision
	 * @param path
	 * @return tree id or null if no tree id at path
	 */
	public static ObjectId getId(final Repository repository,
			final String revision, final String path) {
		if (repository == null)
			throw new IllegalArgumentException(
					Assert.formatNotNull("Repository"));
		if (revision == null)
			throw new IllegalArgumentException(Assert.formatNotNull("Revision"));
		if (revision.length() == 0)
			throw new IllegalArgumentException(
					Assert.formatNotEmpty("Revision"));
		if (path == null)
			throw new IllegalArgumentException(Assert.formatNotNull("Path"));
		if (path.length() == 0)
			throw new IllegalArgumentException(Assert.formatNotNull("Path"));

		final RevCommit commit = CommitUtils.parse(repository,
				CommitUtils.strictResolve(repository, revision));
		return lookupId(repository, commit, path);
	}

	/**
	 * Visit entries in the given tree
	 *
	 * @param repository
	 * @param treeId
	 * @param visitor
	 * @return true if fully completed, false if terminated early
	 */
	public static boolean visit(final Repository repository,
			final ObjectId treeId, final ITreeVisitor visitor) {
		if (repository == null)
			throw new IllegalArgumentException(
					Assert.formatNotNull("Repository"));
		if (treeId == null)
			throw new IllegalArgumentException(Assert.formatNotNull("Tree Id"));
		if (visitor == null)
			throw new IllegalArgumentException(Assert.formatNotNull("Visitor"));

		final TreeWalk walk = new TreeWalk(repository);
		walk.setPostOrderTraversal(true);
		final MutableObjectId id = new MutableObjectId();
		try {
			walk.addTree(treeId);
			if (!visit(repository, walk, id, null, visitor))
				return false;
		} catch (IOException e) {
			throw new GitException(e, repository);
		} finally {
			walk.close();
		}
		return true;
	}

	private static boolean visit(final Repository repository,
			final TreeWalk walk, final MutableObjectId id, final String path,
			final ITreeVisitor visitor) throws IOException {
		while (walk.next()) {
			if (walk.isPostChildren())
				break;

			if (walk.isSubtree()) {
				final String subTreePath = walk.getPathString();
				walk.enterSubtree();
				if (!visit(repository, walk, id, subTreePath, visitor))
					return false;
			}

			walk.getObjectId(id, 0);
			if (!visitor.accept(walk.getFileMode(0), path,
					walk.getNameString(), id))
				return false;
		}
		return true;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy