Package org.gitective.core.filter.commit

Source Code of org.gitective.core.filter.commit.CommitDiffFilter$LocalDiffEntry

/*
* Copyright (c) 2011 Kevin Sawicki <kevinsawicki@gmail.com>
*
* 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.filter.commit;

import static org.eclipse.jgit.lib.FileMode.TYPE_FILE;
import static org.eclipse.jgit.lib.FileMode.TYPE_MASK;
import static org.eclipse.jgit.lib.NullProgressMonitor.INSTANCE;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.diff.RenameDetector;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.MutableObjectId;
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.gitective.core.TreeUtils;

/**
* Commit diff filter that computes the differences introduced by each commit
* visited and calls {@link #include(RevWalk, RevCommit, Collection)}.
*
* @see #include(RevWalk, RevCommit, Collection)
*/
public class CommitDiffFilter extends CommitFilter {

  private static class LocalDiffEntry extends DiffEntry {

    public LocalDiffEntry(final String path) {
      oldPath = path;
      newPath = path;
    }

    private LocalDiffEntry setOldMode(final FileMode mode) {
      oldMode = mode;
      return this;
    }

    private LocalDiffEntry setNewMode(final FileMode mode) {
      newMode = mode;
      return this;
    }

    private LocalDiffEntry setChangeType(final ChangeType type) {
      changeType = type;
      return this;
    }

    private LocalDiffEntry setNewId(final AbbreviatedObjectId id) {
      newId = id;
      return this;
    }
  }

  /**
   * True to detect renames, false otherwise
   */
  protected final boolean detectRenames;

  /**
   * Rename detector
   */
  protected RenameDetector renameDetector;

  /**
   * Create commit diff filter
   */
  public CommitDiffFilter() {
    this(false);
  }

  /**
   * Create commit diff filter
   *
   * @param detectRenames
   *            true to detect renames, false otherwise
   */
  public CommitDiffFilter(final boolean detectRenames) {
    this.detectRenames = detectRenames;
  }

  @Override
  public CommitFilter setRepository(Repository repository) {
    if (detectRenames)
      renameDetector = new RenameDetector(repository);
    return super.setRepository(repository);
  }

  /**
   * Create tree walk to compute differences for the given commits
   * <p>
   * Sub-classes may override this method to create a custom tree walk with
   * different filtering options set.
   * <p>
   * The last tree in the tree walk is assumed to be the tree of the current
   * commit
   *
   * @param walker
   * @param commit
   * @return tree walk
   */
  protected TreeWalk createTreeWalk(final RevWalk walker,
      final RevCommit commit) {
    final TreeWalk walk = TreeUtils.diffWithParents(walker, commit);
    walk.setRecursive(true);
    return walk;
  }

  @Override
  public boolean include(final RevWalk walker, final RevCommit commit)
      throws IOException {
    final TreeWalk walk = createTreeWalk(walker, commit);
    final List<DiffEntry> diffs;
    final int treeCount = walk.getTreeCount();
    switch (treeCount) {
    case 0:
    case 1:
      diffs = Collections.emptyList();
      break;
    case 2:
      diffs = DiffEntry.scan(walk);
      break;
    default:
      diffs = new ArrayList<DiffEntry>();
      final MutableObjectId currentId = new MutableObjectId();
      final int currentTree = treeCount - 1;
      while (walk.next()) {
        final int currentMode = walk.getRawMode(currentTree);
        int parentMode = 0;
        boolean same = false;
        for (int i = 0; i < currentTree; i++) {
          final int mode = walk.getRawMode(i);
          same = mode == currentMode && walk.idEqual(currentTree, i);
          if (same)
            break;
          parentMode |= mode;
        }
        if (same)
          continue;

        final LocalDiffEntry diff = new LocalDiffEntry(
            walk.getPathString());
        diff.setOldMode(FileMode.fromBits(parentMode));
        diff.setNewMode(FileMode.fromBits(currentMode));
        walk.getObjectId(currentId, currentTree);
        diff.setNewId(AbbreviatedObjectId.fromObjectId(currentId));
        if (parentMode == 0 && currentMode != 0)
          diff.setChangeType(ChangeType.ADD);
        else if (parentMode != 0 && currentMode == 0)
          diff.setChangeType(ChangeType.DELETE);
        else
          diff.setChangeType(ChangeType.MODIFY);
        diffs.add(diff);
      }
    }
    if (detectRenames) {
      renameDetector.reset();
      renameDetector.addAll(diffs);
      return include(walker, commit,
          renameDetector.compute(walker.getObjectReader(), INSTANCE)) ? true
          : include(false);
    } else
      return include(walker, commit, diffs) ? true : include(false);
  }

  /**
   * Is the given diff entry a file?
   *
   * @param diff
   * @return true if a regular or executable file, false otherwise
   */
  protected boolean isFileDiff(DiffEntry diff) {
    switch (diff.getChangeType()) {
    case DELETE:
      return TYPE_FILE == (diff.getOldMode().getBits() & TYPE_MASK);
    case ADD:
      return TYPE_FILE == (diff.getNewMode().getBits() & TYPE_MASK);
    default:
      return TYPE_FILE == (diff.getOldMode().getBits() & TYPE_MASK)
          && TYPE_FILE == (diff.getNewMode().getBits() & TYPE_MASK);
    }
  }

  /**
   * Handle the differences introduced by given commit.
   * <p>
   * Sub-classes should override this method. The default implementation calls
   * {@link #include(RevCommit, Collection)}.
   *
   * @param walker
   *            non-null
   * @param commit
   *            non-null
   * @param diffs
   *            non-null
   * @return true to continue, false to abort
   * @throws IOException
   */
  public boolean include(final RevWalk walker, final RevCommit commit,
      final Collection<DiffEntry> diffs) throws IOException {
    return include(commit, diffs);
  }

  /**
   * Handle the differences introduced by given commit.
   * <p>
   * Sub-classes should override this method. The default implementation
   * returns true in all cases.
   *
   * @param commit
   *            non-null
   * @param diffs
   *            non-null
   * @return true to continue, false to abort
   * @throws IOException
   */
  public boolean include(final RevCommit commit,
      final Collection<DiffEntry> diffs) throws IOException {
    return true;
  }
}
TOP

Related Classes of org.gitective.core.filter.commit.CommitDiffFilter$LocalDiffEntry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.