You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RevCommitList.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /*
  2. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.revwalk;
  11. import java.io.IOException;
  12. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  13. import org.eclipse.jgit.errors.MissingObjectException;
  14. import org.eclipse.jgit.revwalk.filter.RevFilter;
  15. /**
  16. * An ordered list of {@link org.eclipse.jgit.revwalk.RevCommit} subclasses.
  17. *
  18. * @param <E>
  19. * type of subclass of RevCommit the list is storing.
  20. */
  21. public class RevCommitList<E extends RevCommit> extends RevObjectList<E> {
  22. private RevWalk walker;
  23. /** {@inheritDoc} */
  24. @Override
  25. public void clear() {
  26. super.clear();
  27. walker = null;
  28. }
  29. /**
  30. * Apply a flag to all commits matching the specified filter.
  31. * <p>
  32. * Same as <code>applyFlag(matching, flag, 0, size())</code>, but without
  33. * the incremental behavior.
  34. *
  35. * @param matching
  36. * the filter to test commits with. If the filter includes a
  37. * commit it will have the flag set; if the filter does not
  38. * include the commit the flag will be unset.
  39. * @param flag
  40. * the flag to apply (or remove). Applications are responsible
  41. * for allocating this flag from the source RevWalk.
  42. * @throws java.io.IOException
  43. * revision filter needed to read additional objects, but an
  44. * error occurred while reading the pack files or loose objects
  45. * of the repository.
  46. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  47. * revision filter needed to read additional objects, but an
  48. * object was not of the correct type. Repository corruption may
  49. * have occurred.
  50. * @throws org.eclipse.jgit.errors.MissingObjectException
  51. * revision filter needed to read additional objects, but an
  52. * object that should be present was not found. Repository
  53. * corruption may have occurred.
  54. */
  55. public void applyFlag(RevFilter matching, RevFlag flag)
  56. throws MissingObjectException, IncorrectObjectTypeException,
  57. IOException {
  58. applyFlag(matching, flag, 0, size());
  59. }
  60. /**
  61. * Apply a flag to all commits matching the specified filter.
  62. * <p>
  63. * This version allows incremental testing and application, such as from a
  64. * background thread that needs to periodically halt processing and send
  65. * updates to the UI.
  66. *
  67. * @param matching
  68. * the filter to test commits with. If the filter includes a
  69. * commit it will have the flag set; if the filter does not
  70. * include the commit the flag will be unset.
  71. * @param flag
  72. * the flag to apply (or remove). Applications are responsible
  73. * for allocating this flag from the source RevWalk.
  74. * @param rangeBegin
  75. * first commit within the list to begin testing at, inclusive.
  76. * Must not be negative, but may be beyond the end of the list.
  77. * @param rangeEnd
  78. * last commit within the list to end testing at, exclusive. If
  79. * smaller than or equal to <code>rangeBegin</code> then no
  80. * commits will be tested.
  81. * @throws java.io.IOException
  82. * revision filter needed to read additional objects, but an
  83. * error occurred while reading the pack files or loose objects
  84. * of the repository.
  85. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  86. * revision filter needed to read additional objects, but an
  87. * object was not of the correct type. Repository corruption may
  88. * have occurred.
  89. * @throws org.eclipse.jgit.errors.MissingObjectException
  90. * revision filter needed to read additional objects, but an
  91. * object that should be present was not found. Repository
  92. * corruption may have occurred.
  93. */
  94. public void applyFlag(final RevFilter matching, final RevFlag flag,
  95. int rangeBegin, int rangeEnd) throws MissingObjectException,
  96. IncorrectObjectTypeException, IOException {
  97. final RevWalk w = flag.getRevWalk();
  98. rangeEnd = Math.min(rangeEnd, size());
  99. while (rangeBegin < rangeEnd) {
  100. int index = rangeBegin;
  101. Block s = contents;
  102. while (s.shift > 0) {
  103. final int i = index >> s.shift;
  104. index -= i << s.shift;
  105. s = (Block) s.contents[i];
  106. }
  107. while (rangeBegin++ < rangeEnd && index < BLOCK_SIZE) {
  108. final RevCommit c = (RevCommit) s.contents[index++];
  109. if (matching.include(w, c))
  110. c.add(flag);
  111. else
  112. c.remove(flag);
  113. }
  114. }
  115. }
  116. /**
  117. * Remove the given flag from all commits.
  118. * <p>
  119. * Same as <code>clearFlag(flag, 0, size())</code>, but without the
  120. * incremental behavior.
  121. *
  122. * @param flag
  123. * the flag to remove. Applications are responsible for
  124. * allocating this flag from the source RevWalk.
  125. */
  126. public void clearFlag(RevFlag flag) {
  127. clearFlag(flag, 0, size());
  128. }
  129. /**
  130. * Remove the given flag from all commits.
  131. * <p>
  132. * This method is actually implemented in terms of:
  133. * <code>applyFlag(RevFilter.NONE, flag, rangeBegin, rangeEnd)</code>.
  134. *
  135. * @param flag
  136. * the flag to remove. Applications are responsible for
  137. * allocating this flag from the source RevWalk.
  138. * @param rangeBegin
  139. * first commit within the list to begin testing at, inclusive.
  140. * Must not be negative, but may be beyond the end of the list.
  141. * @param rangeEnd
  142. * last commit within the list to end testing at, exclusive. If
  143. * smaller than or equal to <code>rangeBegin</code> then no
  144. * commits will be tested.
  145. */
  146. public void clearFlag(final RevFlag flag, final int rangeBegin,
  147. final int rangeEnd) {
  148. try {
  149. applyFlag(RevFilter.NONE, flag, rangeBegin, rangeEnd);
  150. } catch (IOException e) {
  151. // Never happen. The filter we use does not throw any
  152. // exceptions, for any reason.
  153. }
  154. }
  155. /**
  156. * Find the next commit that has the given flag set.
  157. *
  158. * @param flag
  159. * the flag to test commits against.
  160. * @param begin
  161. * first commit index to test at. Applications may wish to begin
  162. * at 0, to test the first commit in the list.
  163. * @return index of the first commit at or after index <code>begin</code>
  164. * that has the specified flag set on it; -1 if no match is found.
  165. */
  166. public int indexOf(RevFlag flag, int begin) {
  167. while (begin < size()) {
  168. int index = begin;
  169. Block s = contents;
  170. while (s.shift > 0) {
  171. final int i = index >> s.shift;
  172. index -= i << s.shift;
  173. s = (Block) s.contents[i];
  174. }
  175. while (begin++ < size() && index < BLOCK_SIZE) {
  176. final RevCommit c = (RevCommit) s.contents[index++];
  177. if (c.has(flag))
  178. return begin;
  179. }
  180. }
  181. return -1;
  182. }
  183. /**
  184. * Find the next commit that has the given flag set.
  185. *
  186. * @param flag
  187. * the flag to test commits against.
  188. * @param begin
  189. * first commit index to test at. Applications may wish to begin
  190. * at <code>size()-1</code>, to test the last commit in the
  191. * list.
  192. * @return index of the first commit at or before index <code>begin</code>
  193. * that has the specified flag set on it; -1 if no match is found.
  194. */
  195. public int lastIndexOf(RevFlag flag, int begin) {
  196. begin = Math.min(begin, size() - 1);
  197. while (begin >= 0) {
  198. int index = begin;
  199. Block s = contents;
  200. while (s.shift > 0) {
  201. final int i = index >> s.shift;
  202. index -= i << s.shift;
  203. s = (Block) s.contents[i];
  204. }
  205. while (begin-- >= 0 && index >= 0) {
  206. final RevCommit c = (RevCommit) s.contents[index--];
  207. if (c.has(flag))
  208. return begin;
  209. }
  210. }
  211. return -1;
  212. }
  213. /**
  214. * Set the revision walker this list populates itself from.
  215. *
  216. * @param w
  217. * the walker to populate from.
  218. * @see #fillTo(int)
  219. */
  220. public void source(RevWalk w) {
  221. walker = w;
  222. }
  223. /**
  224. * Is this list still pending more items?
  225. *
  226. * @return true if {@link #fillTo(int)} might be able to extend the list
  227. * size when called.
  228. */
  229. public boolean isPending() {
  230. return walker != null;
  231. }
  232. /**
  233. * Ensure this list contains at least a specified number of commits.
  234. * <p>
  235. * The revision walker specified by {@link #source(RevWalk)} is pumped until
  236. * the given number of commits are contained in this list. If there are
  237. * fewer total commits available from the walk then the method will return
  238. * early. Callers can test the final size of the list by {@link #size()} to
  239. * determine if the high water mark specified was met.
  240. *
  241. * @param highMark
  242. * number of commits the caller wants this list to contain when
  243. * the fill operation is complete.
  244. * @throws java.io.IOException
  245. * see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
  246. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  247. * see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
  248. * @throws org.eclipse.jgit.errors.MissingObjectException
  249. * see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
  250. */
  251. @SuppressWarnings("unchecked")
  252. public void fillTo(int highMark) throws MissingObjectException,
  253. IncorrectObjectTypeException, IOException {
  254. if (walker == null || size > highMark)
  255. return;
  256. RevCommit c = walker.next();
  257. if (c == null) {
  258. walker = null;
  259. return;
  260. }
  261. enter(size, (E) c);
  262. add((E) c);
  263. while (size <= highMark) {
  264. int index = size;
  265. Block s = contents;
  266. while (index >> s.shift >= BLOCK_SIZE) {
  267. s = new Block(s.shift + BLOCK_SHIFT);
  268. s.contents[0] = contents;
  269. contents = s;
  270. }
  271. while (s.shift > 0) {
  272. final int i = index >> s.shift;
  273. index -= i << s.shift;
  274. if (s.contents[i] == null)
  275. s.contents[i] = new Block(s.shift - BLOCK_SHIFT);
  276. s = (Block) s.contents[i];
  277. }
  278. final Object[] dst = s.contents;
  279. while (size <= highMark && index < BLOCK_SIZE) {
  280. c = walker.next();
  281. if (c == null) {
  282. walker = null;
  283. return;
  284. }
  285. enter(size++, (E) c);
  286. dst[index++] = c;
  287. }
  288. }
  289. }
  290. /**
  291. * Ensures all commits until the given commit are loaded. The revision
  292. * walker specified by {@link #source(RevWalk)} is pumped until the
  293. * specified commit is loaded. Callers can test the final size of the list
  294. * by {@link #size()} to determine if the high water mark specified was met.
  295. * <p>
  296. *
  297. * @param commitToLoad
  298. * commit the caller wants this list to contain when the fill
  299. * operation is complete.
  300. * @param highMark
  301. * maximum number of commits the caller wants this list to
  302. * contain when the fill operation is complete. If highMark is 0
  303. * the walk is pumped until the specified commit or the end of
  304. * the walk is reached.
  305. * @throws java.io.IOException
  306. * see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
  307. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  308. * see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
  309. * @throws org.eclipse.jgit.errors.MissingObjectException
  310. * see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
  311. */
  312. @SuppressWarnings("unchecked")
  313. public void fillTo(RevCommit commitToLoad, int highMark)
  314. throws MissingObjectException, IncorrectObjectTypeException,
  315. IOException {
  316. if (walker == null || commitToLoad == null
  317. || (highMark > 0 && size > highMark))
  318. return;
  319. RevCommit c = walker.next();
  320. if (c == null) {
  321. walker = null;
  322. return;
  323. }
  324. enter(size, (E) c);
  325. add((E) c);
  326. while ((highMark == 0 || size <= highMark) && !c.equals(commitToLoad)) {
  327. int index = size;
  328. Block s = contents;
  329. while (index >> s.shift >= BLOCK_SIZE) {
  330. s = new Block(s.shift + BLOCK_SHIFT);
  331. s.contents[0] = contents;
  332. contents = s;
  333. }
  334. while (s.shift > 0) {
  335. final int i = index >> s.shift;
  336. index -= i << s.shift;
  337. if (s.contents[i] == null)
  338. s.contents[i] = new Block(s.shift - BLOCK_SHIFT);
  339. s = (Block) s.contents[i];
  340. }
  341. final Object[] dst = s.contents;
  342. while ((highMark == 0 || size <= highMark) && index < BLOCK_SIZE
  343. && !c.equals(commitToLoad)) {
  344. c = walker.next();
  345. if (c == null) {
  346. walker = null;
  347. return;
  348. }
  349. enter(size++, (E) c);
  350. dst[index++] = c;
  351. }
  352. }
  353. }
  354. /**
  355. * Optional callback invoked when commits enter the list by fillTo.
  356. * <p>
  357. * This method is only called during {@link #fillTo(int)}.
  358. *
  359. * @param index
  360. * the list position this object will appear at.
  361. * @param e
  362. * the object being added (or set) into the list.
  363. */
  364. protected void enter(int index, E e) {
  365. // Do nothing by default.
  366. }
  367. }