1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.diff;
12
13 import java.io.BufferedInputStream;
14 import java.io.FileNotFoundException;
15 import java.io.IOException;
16 import java.io.InputStream;
17
18 import org.eclipse.jgit.errors.LargeObjectException;
19 import org.eclipse.jgit.errors.MissingObjectException;
20 import org.eclipse.jgit.lib.Constants;
21 import org.eclipse.jgit.lib.ObjectId;
22 import org.eclipse.jgit.lib.ObjectLoader;
23 import org.eclipse.jgit.lib.ObjectReader;
24 import org.eclipse.jgit.lib.ObjectStream;
25 import org.eclipse.jgit.treewalk.TreeWalk;
26 import org.eclipse.jgit.treewalk.WorkingTreeIterator;
27 import org.eclipse.jgit.treewalk.filter.PathFilter;
28
29
30
31
32
33
34
35
36
37
38 public abstract class ContentSource {
39
40
41
42
43
44
45
46 public static ContentSource create(ObjectReader reader) {
47 return new ObjectReaderSource(reader);
48 }
49
50
51
52
53
54
55
56
57
58
59
60
61 public static ContentSource create(WorkingTreeIterator iterator) {
62 return new WorkingTreeSource(iterator);
63 }
64
65
66
67
68
69
70
71
72
73
74
75
76 public abstract long size(String path, ObjectId id) throws IOException;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 public abstract ObjectLoader open(String path, ObjectId id)
92 throws IOException;
93
94
95
96
97
98
99
100 public void close() {
101
102 }
103
104
105
106
107
108
109
110
111
112
113 public boolean isWorkingTreeSource() {
114 return false;
115 }
116
117 private static class ObjectReaderSource extends ContentSource {
118 private final ObjectReader reader;
119
120 ObjectReaderSource(ObjectReader reader) {
121 this.reader = reader;
122 }
123
124 @Override
125 public long size(String path, ObjectId id) throws IOException {
126 try {
127 return reader.getObjectSize(id, Constants.OBJ_BLOB);
128 } catch (MissingObjectException ignore) {
129 return 0;
130 }
131 }
132
133 @Override
134 public ObjectLoader open(String path, ObjectId id) throws IOException {
135 return reader.open(id, Constants.OBJ_BLOB);
136 }
137
138 @Override
139 public void close() {
140 reader.close();
141 }
142
143 @Override
144 public boolean isWorkingTreeSource() {
145 return false;
146 }
147 }
148
149 private static class WorkingTreeSource extends ContentSource {
150 private final TreeWalk tw;
151
152 private final WorkingTreeIterator iterator;
153
154 private String current;
155
156 WorkingTreeIterator ptr;
157
158 WorkingTreeSource(WorkingTreeIterator iterator) {
159 this.tw = new TreeWalk(iterator.getRepository(),
160 (ObjectReader) null);
161 this.tw.setRecursive(true);
162 this.iterator = iterator;
163 }
164
165 @Override
166 public long size(String path, ObjectId id) throws IOException {
167 seek(path);
168 return ptr.getEntryLength();
169 }
170
171 @Override
172 public ObjectLoader open(String path, ObjectId id) throws IOException {
173 seek(path);
174 long entrySize = ptr.getEntryContentLength();
175 return new ObjectLoader() {
176 @Override
177 public long getSize() {
178 return entrySize;
179 }
180
181 @Override
182 public int getType() {
183 return ptr.getEntryFileMode().getObjectType();
184 }
185
186 @Override
187 public ObjectStream openStream() throws MissingObjectException,
188 IOException {
189 long contentLength = entrySize;
190 InputStream in = ptr.openEntryStream();
191 in = new BufferedInputStream(in);
192 return new ObjectStream.Filter(getType(), contentLength, in);
193 }
194
195 @Override
196 public boolean isLarge() {
197 return true;
198 }
199
200 @Override
201 public byte[] getCachedBytes() throws LargeObjectException {
202 throw new LargeObjectException();
203 }
204 };
205 }
206
207 private void seek(String path) throws IOException {
208 if (!path.equals(current)) {
209 iterator.reset();
210
211
212
213
214
215
216
217 iterator.setWalkIgnoredDirectories(true);
218 iterator.setDirCacheIterator(null, -1);
219 tw.reset();
220 tw.addTree(iterator);
221 tw.setFilter(PathFilter.create(path));
222 current = path;
223 if (!tw.next())
224 throw new FileNotFoundException(path);
225 ptr = tw.getTree(0, WorkingTreeIterator.class);
226 if (ptr == null)
227 throw new FileNotFoundException(path);
228 }
229 }
230
231 @Override
232 public void close() {
233 tw.close();
234 }
235
236 @Override
237 public boolean isWorkingTreeSource() {
238 return true;
239 }
240 }
241
242
243 public static final class Pair {
244 private final ContentSource oldSource;
245
246 private final ContentSource newSource;
247
248
249
250
251
252
253
254
255
256 public Pair(ContentSource oldSource, ContentSource newSource) {
257 this.oldSource = oldSource;
258 this.newSource = newSource;
259 }
260
261
262
263
264
265
266
267
268
269
270
271
272 public long size(DiffEntry.Side side, DiffEntry ent) throws IOException {
273 switch (side) {
274 case OLD:
275 return oldSource.size(ent.oldPath, ent.oldId.toObjectId());
276 case NEW:
277 return newSource.size(ent.newPath, ent.newId.toObjectId());
278 default:
279 throw new IllegalArgumentException();
280 }
281 }
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296 public ObjectLoader open(DiffEntry.Side side, DiffEntry ent)
297 throws IOException {
298 switch (side) {
299 case OLD:
300 return oldSource.open(ent.oldPath, ent.oldId.toObjectId());
301 case NEW:
302 return newSource.open(ent.newPath, ent.newId.toObjectId());
303 default:
304 throw new IllegalArgumentException();
305 }
306 }
307
308
309
310
311
312
313 public void close() {
314 oldSource.close();
315 newSource.close();
316 }
317
318
319
320
321
322
323
324
325
326
327
328 public boolean isWorkingTreeSource(DiffEntry.Side side) {
329 switch (side) {
330 case OLD:
331 return oldSource.isWorkingTreeSource();
332 case NEW:
333 return newSource.isWorkingTreeSource();
334 default:
335 throw new IllegalArgumentException();
336 }
337 }
338
339 }
340 }