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.

RewriteTreeFilter.java 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.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. package org.eclipse.jgit.revwalk;
  44. import java.io.IOException;
  45. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  46. import org.eclipse.jgit.errors.MissingObjectException;
  47. import org.eclipse.jgit.errors.StopWalkException;
  48. import org.eclipse.jgit.lib.ObjectId;
  49. import org.eclipse.jgit.revwalk.filter.RevFilter;
  50. import org.eclipse.jgit.treewalk.TreeWalk;
  51. import org.eclipse.jgit.treewalk.filter.TreeFilter;
  52. /**
  53. * First phase of a path limited revision walk.
  54. * <p>
  55. * This filter is ANDed to evaluate after all other filters and ties the
  56. * configured {@link TreeFilter} into the revision walking process.
  57. * <p>
  58. * Each commit is differenced concurrently against all of its parents to look
  59. * for tree entries that are interesting to the TreeFilter. If none are found
  60. * the commit is colored with {@link RevWalk#REWRITE}, allowing a later pass
  61. * implemented by {@link RewriteGenerator} to remove those colored commits from
  62. * the DAG.
  63. *
  64. * @see RewriteGenerator
  65. */
  66. class RewriteTreeFilter extends RevFilter {
  67. private static final int PARSED = RevWalk.PARSED;
  68. private static final int UNINTERESTING = RevWalk.UNINTERESTING;
  69. private static final int REWRITE = RevWalk.REWRITE;
  70. private final TreeWalk pathFilter;
  71. RewriteTreeFilter(final RevWalk walker, final TreeFilter t) {
  72. pathFilter = new TreeWalk(walker.db);
  73. pathFilter.setFilter(t);
  74. pathFilter.setRecursive(t.shouldBeRecursive());
  75. }
  76. @Override
  77. public RevFilter clone() {
  78. throw new UnsupportedOperationException();
  79. }
  80. @Override
  81. public boolean include(final RevWalk walker, final RevCommit c)
  82. throws StopWalkException, MissingObjectException,
  83. IncorrectObjectTypeException, IOException {
  84. // Reset the tree filter to scan this commit and parents.
  85. //
  86. final RevCommit[] pList = c.parents;
  87. final int nParents = pList.length;
  88. final TreeWalk tw = pathFilter;
  89. final ObjectId[] trees = new ObjectId[nParents + 1];
  90. for (int i = 0; i < nParents; i++) {
  91. final RevCommit p = c.parents[i];
  92. if ((p.flags & PARSED) == 0)
  93. p.parseHeaders(walker);
  94. trees[i] = p.getTree();
  95. }
  96. trees[nParents] = c.getTree();
  97. tw.reset(trees);
  98. if (nParents == 1) {
  99. // We have exactly one parent. This is a very common case.
  100. //
  101. int chgs = 0, adds = 0;
  102. while (tw.next()) {
  103. chgs++;
  104. if (tw.getRawMode(0) == 0 && tw.getRawMode(1) != 0)
  105. adds++;
  106. else
  107. break; // no point in looking at this further.
  108. }
  109. if (chgs == 0) {
  110. // No changes, so our tree is effectively the same as
  111. // our parent tree. We pass the buck to our parent.
  112. //
  113. c.flags |= REWRITE;
  114. return false;
  115. } else {
  116. // We have interesting items, but neither of the special
  117. // cases denoted above.
  118. //
  119. return true;
  120. }
  121. } else if (nParents == 0) {
  122. // We have no parents to compare against. Consider us to be
  123. // REWRITE only if we have no paths matching our filter.
  124. //
  125. if (tw.next())
  126. return true;
  127. c.flags |= REWRITE;
  128. return false;
  129. }
  130. // We are a merge commit. We can only be REWRITE if we are same
  131. // to _all_ parents. We may also be able to eliminate a parent if
  132. // it does not contribute changes to us. Such a parent may be an
  133. // uninteresting side branch.
  134. //
  135. final int[] chgs = new int[nParents];
  136. final int[] adds = new int[nParents];
  137. while (tw.next()) {
  138. final int myMode = tw.getRawMode(nParents);
  139. for (int i = 0; i < nParents; i++) {
  140. final int pMode = tw.getRawMode(i);
  141. if (myMode == pMode && tw.idEqual(i, nParents))
  142. continue;
  143. chgs[i]++;
  144. if (pMode == 0 && myMode != 0)
  145. adds[i]++;
  146. }
  147. }
  148. boolean same = false;
  149. boolean diff = false;
  150. for (int i = 0; i < nParents; i++) {
  151. if (chgs[i] == 0) {
  152. // No changes, so our tree is effectively the same as
  153. // this parent tree. We pass the buck to only this one
  154. // parent commit.
  155. //
  156. final RevCommit p = pList[i];
  157. if ((p.flags & UNINTERESTING) != 0) {
  158. // This parent was marked as not interesting by the
  159. // application. We should look for another parent
  160. // that is interesting.
  161. //
  162. same = true;
  163. continue;
  164. }
  165. c.flags |= REWRITE;
  166. c.parents = new RevCommit[] { p };
  167. return false;
  168. }
  169. if (chgs[i] == adds[i]) {
  170. // All of the differences from this parent were because we
  171. // added files that they did not have. This parent is our
  172. // "empty tree root" and thus their history is not relevant.
  173. // Cut our grandparents to be an empty list.
  174. //
  175. pList[i].parents = RevCommit.NO_PARENTS;
  176. }
  177. // We have an interesting difference relative to this parent.
  178. //
  179. diff = true;
  180. }
  181. if (diff && !same) {
  182. // We did not abort above, so we are different in at least one
  183. // way from all of our parents. We have to take the blame for
  184. // that difference.
  185. //
  186. return true;
  187. }
  188. // We are the same as all of our parents. We must keep them
  189. // as they are and allow those parents to flow into pending
  190. // for further scanning.
  191. //
  192. c.flags |= REWRITE;
  193. return false;
  194. }
  195. }