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