1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.revwalk;
12
13 import java.io.IOException;
14 import java.util.List;
15
16 import org.eclipse.jgit.diff.DiffConfig;
17 import org.eclipse.jgit.diff.DiffEntry;
18 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
19 import org.eclipse.jgit.diff.RenameDetector;
20 import org.eclipse.jgit.errors.CorruptObjectException;
21 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
22 import org.eclipse.jgit.errors.MissingObjectException;
23 import org.eclipse.jgit.errors.StopWalkException;
24 import org.eclipse.jgit.lib.ObjectId;
25 import org.eclipse.jgit.revwalk.filter.RevFilter;
26 import org.eclipse.jgit.treewalk.TreeWalk;
27 import org.eclipse.jgit.treewalk.filter.TreeFilter;
28
29
30
31
32
33
34
35
36
37
38
39 public class TreeRevFilter extends RevFilter {
40 private static final int PARSED = RevWalk.PARSED;
41
42 private static final int UNINTERESTING = RevWalk.UNINTERESTING;
43
44 private final int rewriteFlag;
45 private final TreeWalk pathFilter;
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public TreeRevFilter(RevWalk walker, TreeFilter t) {
60 this(walker, t, 0);
61 }
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 TreeRevFilter(RevWalk walker, TreeFilter t, int rewriteFlag) {
87 pathFilter = new TreeWalk(walker.reader);
88 pathFilter.setFilter(t);
89 pathFilter.setRecursive(t.shouldBeRecursive());
90 this.rewriteFlag = rewriteFlag;
91 }
92
93
94 @Override
95 public RevFilter clone() {
96 throw new UnsupportedOperationException();
97 }
98
99
100 @Override
101 public boolean include(RevWalk walker, RevCommit c)
102 throws StopWalkException, MissingObjectException,
103 IncorrectObjectTypeException, IOException {
104
105
106 RevCommit[] pList = c.parents;
107 int nParents = pList.length;
108 TreeWalk tw = pathFilter;
109 ObjectId[] trees = new ObjectId[nParents + 1];
110 for (int i = 0; i < nParents; i++) {
111 RevCommit p = c.parents[i];
112 if ((p.flags & PARSED) == 0) {
113 p.parseHeaders(walker);
114 }
115 trees[i] = p.getTree();
116 }
117 trees[nParents] = c.getTree();
118 tw.reset(trees);
119
120 if (nParents == 1) {
121
122
123 int chgs = 0, adds = 0;
124 while (tw.next()) {
125 chgs++;
126 if (tw.getRawMode(0) == 0 && tw.getRawMode(1) != 0) {
127 adds++;
128 } else {
129 break;
130 }
131 }
132
133 if (chgs == 0) {
134
135
136
137 c.flags |= rewriteFlag;
138 return false;
139 }
140
141
142
143
144 if (adds > 0 && tw.getFilter() instanceof FollowFilter) {
145
146
147
148
149 updateFollowFilter(trees, ((FollowFilter) tw.getFilter()).cfg);
150 }
151 return true;
152 } else if (nParents == 0) {
153
154
155
156 if (tw.next()) {
157 return true;
158 }
159 c.flags |= rewriteFlag;
160 return false;
161 }
162
163
164
165
166
167
168 int[] chgs = new int[nParents];
169 int[] adds = new int[nParents];
170 while (tw.next()) {
171 int myMode = tw.getRawMode(nParents);
172 for (int i = 0; i < nParents; i++) {
173 int pMode = tw.getRawMode(i);
174 if (myMode == pMode && tw.idEqual(i, nParents)) {
175 continue;
176 }
177 chgs[i]++;
178 if (pMode == 0 && myMode != 0) {
179 adds[i]++;
180 }
181 }
182 }
183
184 boolean same = false;
185 boolean diff = false;
186 for (int i = 0; i < nParents; i++) {
187 if (chgs[i] == 0) {
188
189
190
191
192
193 RevCommit p = pList[i];
194 if ((p.flags & UNINTERESTING) != 0) {
195
196
197
198
199 same = true;
200 continue;
201 }
202
203 c.flags |= rewriteFlag;
204 c.parents = new RevCommit[] { p };
205 return false;
206 }
207
208 if (chgs[i] == adds[i]) {
209
210
211
212
213
214 pList[i].parents = RevCommit.NO_PARENTS;
215 }
216
217
218
219 diff = true;
220 }
221
222 if (diff && !same) {
223
224
225
226
227 return true;
228 }
229
230
231
232
233
234 c.flags |= rewriteFlag;
235 return false;
236 }
237
238
239 @Override
240 public boolean requiresCommitBody() {
241 return false;
242 }
243
244 private void updateFollowFilter(ObjectId[] trees, DiffConfig cfg)
245 throws MissingObjectException, IncorrectObjectTypeException,
246 CorruptObjectException, IOException {
247 TreeWalk tw = pathFilter;
248 FollowFilter oldFilter = (FollowFilter) tw.getFilter();
249 tw.setFilter(TreeFilter.ANY_DIFF);
250 tw.reset(trees);
251
252 List<DiffEntry> files = DiffEntry.scan(tw);
253 RenameDetector rd = new RenameDetector(tw.getObjectReader(), cfg);
254 rd.addAll(files);
255 files = rd.compute();
256
257 TreeFilter newFilter = oldFilter;
258 for (DiffEntry ent : files) {
259 if (isRename(ent) && ent.getNewPath().equals(oldFilter.getPath())) {
260 newFilter = FollowFilter.create(ent.getOldPath(), cfg);
261 RenameCallback callback = oldFilter.getRenameCallback();
262 if (callback != null) {
263 callback.renamed(ent);
264
265 ((FollowFilter) newFilter).setRenameCallback(callback);
266 }
267 break;
268 }
269 }
270 tw.setFilter(newFilter);
271 }
272
273 private static boolean isRename(DiffEntry ent) {
274 return ent.getChangeType() == ChangeType.RENAME
275 || ent.getChangeType() == ChangeType.COPY;
276 }
277 }