1
2
3
4
5
6
7
8
9
10
11
12 package org.eclipse.jgit.treewalk.filter;
13
14 import java.util.Collection;
15
16 import org.eclipse.jgit.errors.StopWalkException;
17 import org.eclipse.jgit.internal.JGitText;
18 import org.eclipse.jgit.treewalk.TreeWalk;
19 import org.eclipse.jgit.treewalk.filter.ByteArraySet.Hasher;
20 import org.eclipse.jgit.util.RawParseUtils;
21
22
23
24
25
26
27
28
29
30
31
32
33
34 public class PathFilterGroup {
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public static TreeFilter createFromStrings(Collection<String> paths) {
53 if (paths.isEmpty())
54 throw new IllegalArgumentException(
55 JGitText.get().atLeastOnePathIsRequired);
56 final PathFilterfilter/PathFilter.html#PathFilter">PathFilter[] p = new PathFilter[paths.size()];
57 int i = 0;
58 for (String s : paths)
59 p[i++] = PathFilter.create(s);
60 return create(p);
61 }
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 public static TreeFilter createFromStrings(String... paths) {
80 if (paths.length == 0)
81 throw new IllegalArgumentException(
82 JGitText.get().atLeastOnePathIsRequired);
83 final int length = paths.length;
84 final PathFilterfilter/PathFilter.html#PathFilter">PathFilter[] p = new PathFilter[length];
85 for (int i = 0; i < length; i++)
86 p[i] = PathFilter.create(paths[i]);
87 return create(p);
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101 public static TreeFilter create(Collection<PathFilter> paths) {
102 if (paths.isEmpty())
103 throw new IllegalArgumentException(
104 JGitText.get().atLeastOnePathIsRequired);
105 final PathFilterfilter/PathFilter.html#PathFilter">PathFilter[] p = new PathFilter[paths.size()];
106 paths.toArray(p);
107 return create(p);
108 }
109
110 private static TreeFilter create(PathFilter[] p) {
111 if (p.length == 1)
112 return new Single(p[0]);
113 return new Group(p);
114 }
115
116 static class Single extends TreeFilter {
117 private final PathFilter path;
118
119 private final byte[] raw;
120
121 private Single(PathFilter p) {
122 path = p;
123 raw = path.pathRaw;
124 }
125
126 @Override
127 public boolean include(TreeWalk walker) {
128 final int cmp = walker.isPathPrefix(raw, raw.length);
129 if (cmp > 0)
130 throw StopWalkException.INSTANCE;
131 return cmp == 0;
132 }
133
134 @Override
135 public boolean shouldBeRecursive() {
136 return path.shouldBeRecursive();
137 }
138
139 @Override
140 public TreeFilter clone() {
141 return this;
142 }
143
144 @Override
145 public String toString() {
146 return "FAST_" + path.toString();
147 }
148 }
149
150 static class Group extends TreeFilter {
151
152 private ByteArraySet fullpaths;
153
154 private ByteArraySet prefixes;
155
156 private byte[] max;
157
158 private Group(PathFilter[] pathFilters) {
159 fullpaths = new ByteArraySet(pathFilters.length);
160 prefixes = new ByteArraySet(pathFilters.length / 5);
161
162
163
164
165
166 max = pathFilters[0].pathRaw;
167 Hasher hasher = new Hasher(null, 0);
168 for (PathFilter pf : pathFilters) {
169 hasher.init(pf.pathRaw, pf.pathRaw.length);
170 while (hasher.hasNext()) {
171 int hash = hasher.nextHash();
172 if (hasher.hasNext())
173 prefixes.addIfAbsent(pf.pathRaw, hasher.length(), hash);
174 }
175 fullpaths.addIfAbsent(pf.pathRaw, pf.pathRaw.length,
176 hasher.getHash());
177 if (compare(max, pf.pathRaw) < 0)
178 max = pf.pathRaw;
179 }
180
181
182
183
184
185 byte[] newMax = new byte[max.length + 1];
186 for (int i = 0; i < max.length; ++i)
187 if ((max[i] & 0xFF) < '/')
188 newMax[i] = '/';
189 else
190 newMax[i] = max[i];
191 newMax[newMax.length - 1] = '/';
192 max = newMax;
193 }
194
195 private static int compare(byte[] a, byte[] b) {
196 int i = 0;
197 while (i < a.length && i < b.length) {
198 int ba = a[i] & 0xFF;
199 int bb = b[i] & 0xFF;
200 int cmp = ba - bb;
201 if (cmp != 0)
202 return cmp;
203 ++i;
204 }
205 return a.length - b.length;
206 }
207
208 @Override
209 public boolean include(TreeWalk walker) {
210
211 byte[] rp = walker.getRawPath();
212 Hasher hasher = new Hasher(rp, walker.getPathLength());
213 while (hasher.hasNext()) {
214 int hash = hasher.nextHash();
215 if (fullpaths.contains(rp, hasher.length(), hash))
216 return true;
217 if (!hasher.hasNext() && walker.isSubtree()
218 && prefixes.contains(rp, hasher.length(), hash))
219 return true;
220 }
221
222 final int cmp = walker.isPathPrefix(max, max.length);
223 if (cmp > 0)
224 throw StopWalkException.INSTANCE;
225
226 return false;
227 }
228
229 @Override
230 public boolean shouldBeRecursive() {
231 return !prefixes.isEmpty();
232 }
233
234 @Override
235 public TreeFilter clone() {
236 return this;
237 }
238
239 @Override
240 public String toString() {
241 final StringBuilder r = new StringBuilder();
242 r.append("FAST(");
243 boolean first = true;
244 for (byte[] p : fullpaths.toArray()) {
245 if (!first) {
246 r.append(" OR ");
247 }
248 r.append(RawParseUtils.decode(p));
249 first = false;
250 }
251 r.append(")");
252 return r.toString();
253 }
254 }
255
256 }