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.internal.JGitText; 54 import org.eclipse.jgit.lib.NullProgressMonitor; 55 import org.eclipse.jgit.lib.ProgressMonitor; 56 import org.eclipse.jgit.lib.Ref; 57 58 /** 59 * Utility methods for {@link org.eclipse.jgit.revwalk.RevWalk}. 60 */ 61 public final class RevWalkUtils { 62 63 private RevWalkUtils() { 64 // Utility class 65 } 66 67 /** 68 * Count the number of commits that are reachable from <code>start</code> 69 * until a commit that is reachable from <code>end</code> is encountered. In 70 * other words, count the number of commits that are in <code>start</code>, 71 * but not in <code>end</code>. 72 * <p> 73 * Note that this method calls 74 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. Also 75 * note that the existing rev filter on the walk is left as-is, so be sure 76 * to set the right rev filter before calling this method. 77 * 78 * @param walk 79 * the rev walk to use 80 * @param start 81 * the commit to start counting from 82 * @param end 83 * the commit where counting should end, or null if counting 84 * should be done until there are no more commits 85 * @return the number of commits 86 * @throws org.eclipse.jgit.errors.MissingObjectException 87 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException 88 * @throws java.io.IOException 89 */ 90 public static int count(final RevWalk walk, final RevCommit start, 91 final RevCommit end) throws MissingObjectException, 92 IncorrectObjectTypeException, IOException { 93 return find(walk, start, end).size(); 94 } 95 96 /** 97 * Find commits that are reachable from <code>start</code> until a commit 98 * that is reachable from <code>end</code> is encountered. In other words, 99 * Find of commits that are in <code>start</code>, but not in 100 * <code>end</code>. 101 * <p> 102 * Note that this method calls 103 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. Also 104 * note that the existing rev filter on the walk is left as-is, so be sure 105 * to set the right rev filter before calling this method. 106 * 107 * @param walk 108 * the rev walk to use 109 * @param start 110 * the commit to start counting from 111 * @param end 112 * the commit where counting should end, or null if counting 113 * should be done until there are no more commits 114 * @return the commits found 115 * @throws org.eclipse.jgit.errors.MissingObjectException 116 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException 117 * @throws java.io.IOException 118 */ 119 public static List<RevCommit> find(final RevWalk walk, 120 final RevCommitmit.html#RevCommit">RevCommit start, final RevCommit end) 121 throws MissingObjectException, IncorrectObjectTypeException, 122 IOException { 123 walk.reset(); 124 walk.markStart(start); 125 if (end != null) 126 walk.markUninteresting(end); 127 128 List<RevCommit> commits = new ArrayList<>(); 129 for (RevCommit c : walk) 130 commits.add(c); 131 return commits; 132 } 133 134 /** 135 * Find the list of branches a given commit is reachable from when following 136 * parents. 137 * <p> 138 * Note that this method calls 139 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. 140 * <p> 141 * In order to improve performance this method assumes clock skew among 142 * committers is never larger than 24 hours. 143 * 144 * @param commit 145 * the commit we are looking at 146 * @param revWalk 147 * The RevWalk to be used. 148 * @param refs 149 * the set of branches we want to see reachability from 150 * @return the list of branches a given commit is reachable from 151 * @throws org.eclipse.jgit.errors.MissingObjectException 152 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException 153 * @throws java.io.IOException 154 */ 155 public static List<Ref> findBranchesReachableFrom(RevCommit commit, 156 RevWalk revWalk, Collection<Ref> refs) 157 throws MissingObjectException, IncorrectObjectTypeException, 158 IOException { 159 return findBranchesReachableFrom(commit, revWalk, refs, 160 NullProgressMonitor.INSTANCE); 161 } 162 163 /** 164 * Find the list of branches a given commit is reachable from when following 165 * parents. 166 * <p> 167 * Note that this method calls 168 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. 169 * <p> 170 * In order to improve performance this method assumes clock skew among 171 * committers is never larger than 24 hours. 172 * 173 * @param commit 174 * the commit we are looking at 175 * @param revWalk 176 * The RevWalk to be used. 177 * @param refs 178 * the set of branches we want to see reachability from 179 * @param monitor 180 * the callback for progress and cancellation 181 * @return the list of branches a given commit is reachable from 182 * @throws org.eclipse.jgit.errors.MissingObjectException 183 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException 184 * @throws java.io.IOException 185 * @since 5.4 186 */ 187 public static List<Ref> findBranchesReachableFrom(RevCommit commit, 188 RevWalk revWalk, Collection<Ref> refs, ProgressMonitor monitor) 189 throws MissingObjectException, IncorrectObjectTypeException, 190 IOException { 191 192 // Make sure commit is from the same RevWalk 193 commit = revWalk.parseCommit(commit.getId()); 194 revWalk.reset(); 195 List<Ref> result = new ArrayList<>(); 196 monitor.beginTask(JGitText.get().searchForReachableBranches, 197 refs.size()); 198 final int SKEW = 24*3600; // one day clock skew 199 200 for (Ref ref : refs) { 201 if (monitor.isCancelled()) 202 return result; 203 monitor.update(1); 204 RevObject maybehead = revWalk.parseAny(ref.getObjectId()); 205 if (!(maybehead instanceof RevCommit)) 206 continue; 207 RevCommit headCommit = (RevCommit) maybehead; 208 209 // if commit is in the ref branch, then the tip of ref should be 210 // newer than the commit we are looking for. Allow for a large 211 // clock skew. 212 if (headCommit.getCommitTime() + SKEW < commit.getCommitTime()) 213 continue; 214 215 if (revWalk.isMergedInto(commit, headCommit)) 216 result.add(ref); 217 } 218 monitor.endTask(); 219 return result; 220 } 221 222 }