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 }