1 /* 2 * Copyright (C) 2011-2012, Robin Stocker <robin@nibor.org> 3 * and other copyright owners as documented in the project's IP log. 4 * 5 * This program and the accompanying materials are made available 6 * under the terms of the Eclipse Distribution License v1.0 which 7 * accompanies this distribution, is reproduced below, and is 8 * available at http://www.eclipse.org/org/documents/edl-v10.php 9 * 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials provided 22 * with the distribution. 23 * 24 * - Neither the name of the Eclipse Foundation, Inc. nor the 25 * names of its contributors may be used to endorse or promote 26 * products derived from this software without specific prior 27 * written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 30 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 34 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 package org.eclipse.jgit.revwalk; 45 46 import java.io.IOException; 47 import java.util.ArrayList; 48 import java.util.Collection; 49 import java.util.List; 50 51 import org.eclipse.jgit.errors.IncorrectObjectTypeException; 52 import org.eclipse.jgit.errors.MissingObjectException; 53 import org.eclipse.jgit.lib.Ref; 54 55 /** 56 * Utility methods for {@link org.eclipse.jgit.revwalk.RevWalk}. 57 */ 58 public final class RevWalkUtils { 59 60 private RevWalkUtils() { 61 // Utility class 62 } 63 64 /** 65 * Count the number of commits that are reachable from <code>start</code> 66 * until a commit that is reachable from <code>end</code> is encountered. In 67 * other words, count the number of commits that are in <code>start</code>, 68 * but not in <code>end</code>. 69 * <p> 70 * Note that this method calls 71 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. Also 72 * note that the existing rev filter on the walk is left as-is, so be sure 73 * to set the right rev filter before calling this method. 74 * 75 * @param walk 76 * the rev walk to use 77 * @param start 78 * the commit to start counting from 79 * @param end 80 * the commit where counting should end, or null if counting 81 * should be done until there are no more commits 82 * @return the number of commits 83 * @throws org.eclipse.jgit.errors.MissingObjectException 84 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException 85 * @throws java.io.IOException 86 */ 87 public static int count(final RevWalk walk, final RevCommit start, 88 final RevCommit end) throws MissingObjectException, 89 IncorrectObjectTypeException, IOException { 90 return find(walk, start, end).size(); 91 } 92 93 /** 94 * Find commits that are reachable from <code>start</code> until a commit 95 * that is reachable from <code>end</code> is encountered. In other words, 96 * Find of commits that are in <code>start</code>, but not in 97 * <code>end</code>. 98 * <p> 99 * Note that this method calls 100 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. Also 101 * note that the existing rev filter on the walk is left as-is, so be sure 102 * to set the right rev filter before calling this method. 103 * 104 * @param walk 105 * the rev walk to use 106 * @param start 107 * the commit to start counting from 108 * @param end 109 * the commit where counting should end, or null if counting 110 * should be done until there are no more commits 111 * @return the commits found 112 * @throws org.eclipse.jgit.errors.MissingObjectException 113 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException 114 * @throws java.io.IOException 115 */ 116 public static List<RevCommit> find(final RevWalk walk, 117 final RevCommit start, final RevCommit end) 118 throws MissingObjectException, IncorrectObjectTypeException, 119 IOException { 120 walk.reset(); 121 walk.markStart(start); 122 if (end != null) 123 walk.markUninteresting(end); 124 125 List<RevCommit> commits = new ArrayList<>(); 126 for (RevCommit c : walk) 127 commits.add(c); 128 return commits; 129 } 130 131 /** 132 * Find the list of branches a given commit is reachable from when following 133 * parent.s 134 * <p> 135 * Note that this method calls 136 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. 137 * <p> 138 * In order to improve performance this method assumes clock skew among 139 * committers is never larger than 24 hours. 140 * 141 * @param commit 142 * the commit we are looking at 143 * @param revWalk 144 * The RevWalk to be used. 145 * @param refs 146 * the set of branches we want to see reachability from 147 * @return the list of branches a given commit is reachable from 148 * @throws org.eclipse.jgit.errors.MissingObjectException 149 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException 150 * @throws java.io.IOException 151 */ 152 public static List<Ref> findBranchesReachableFrom(RevCommit commit, 153 RevWalk revWalk, Collection<Ref> refs) 154 throws MissingObjectException, IncorrectObjectTypeException, 155 IOException { 156 157 // Make sure commit is from the same RevWalk 158 commit = revWalk.parseCommit(commit.getId()); 159 revWalk.reset(); 160 List<Ref> result = new ArrayList<>(); 161 162 final int SKEW = 24*3600; // one day clock skew 163 164 for (Ref ref : refs) { 165 RevObject maybehead = revWalk.parseAny(ref.getObjectId()); 166 if (!(maybehead instanceof RevCommit)) 167 continue; 168 RevCommit headCommit = (RevCommit) maybehead; 169 170 // if commit is in the ref branch, then the tip of ref should be 171 // newer than the commit we are looking for. Allow for a large 172 // clock skew. 173 if (headCommit.getCommitTime() + SKEW < commit.getCommitTime()) 174 continue; 175 176 if (revWalk.isMergedInto(commit, headCommit)) 177 result.add(ref); 178 } 179 return result; 180 } 181 182 }