1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jgit.treewalk;
15
16 import static java.nio.charset.StandardCharsets.UTF_8;
17
18 import java.io.ByteArrayInputStream;
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.time.Instant;
24
25 import org.eclipse.jgit.dircache.DirCacheIterator;
26 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
27 import org.eclipse.jgit.lib.Constants;
28 import org.eclipse.jgit.lib.FileMode;
29 import org.eclipse.jgit.lib.ObjectReader;
30 import org.eclipse.jgit.lib.Repository;
31 import org.eclipse.jgit.util.FS;
32
33
34
35
36
37
38
39
40 public class FileTreeIterator extends WorkingTreeIterator {
41
42
43
44
45
46 protected final File directory;
47
48
49
50
51
52 protected final FS fs;
53
54
55
56
57
58
59
60
61 protected final FileModeStrategy fileModeStrategy;
62
63
64
65
66
67
68
69 public FileTreeIterator(Repository repo) {
70 this(repo,
71 repo.getConfig().get(WorkingTreeOptions.KEY).isDirNoGitLinks() ?
72 NoGitlinksStrategy.INSTANCE :
73 DefaultFileModeStrategy.INSTANCE);
74 }
75
76
77
78
79
80
81
82
83
84
85
86 public FileTreeIterator(Repository repo, FileModeStrategy fileModeStrategy) {
87 this(repo.getWorkTree(), repo.getFS(),
88 repo.getConfig().get(WorkingTreeOptions.KEY),
89 fileModeStrategy);
90 initRootIterator(repo);
91 }
92
93
94
95
96
97
98
99
100
101
102
103
104
105 public FileTreeIterator(File root, FS fs, WorkingTreeOptions options) {
106 this(root, fs, options, DefaultFileModeStrategy.INSTANCE);
107 }
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 public FileTreeIterator(final File root, FS fs, WorkingTreeOptions options,
126 FileModeStrategy fileModeStrategy) {
127 super(options);
128 directory = root;
129 this.fs = fs;
130 this.fileModeStrategy = fileModeStrategy;
131 init(entries());
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 protected FileTreeIteratorreeIterator.html#FileTreeIterator">FileTreeIterator(final FileTreeIterator p, final File root,
148 FS fs) {
149 this(p, root, fs, p.fileModeStrategy);
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 protected FileTreeIterator(final WorkingTreeIterator p, final File root,
170 FS fs, FileModeStrategy fileModeStrategy) {
171 super(p);
172 directory = root;
173 this.fs = fs;
174 this.fileModeStrategy = fileModeStrategy;
175 init(entries());
176 }
177
178
179 @Override
180 public AbstractTreeIterator createSubtreeIterator(ObjectReader reader)
181 throws IncorrectObjectTypeException, IOException {
182 if (!walksIgnoredDirectories() && isEntryIgnored()) {
183 DirCacheIterator iterator = getDirCacheIterator();
184 if (iterator == null) {
185 return new EmptyTreeIterator(this);
186 }
187
188
189
190
191 }
192 return enterSubtree();
193 }
194
195
196
197
198
199
200
201
202
203
204
205
206 protected AbstractTreeIterator enterSubtree() {
207 return new FileTreeIterator(this, ((FileEntry) current()).getFile(), fs,
208 fileModeStrategy);
209 }
210
211 private Entry[] entries() {
212 return fs.list(directory, fileModeStrategy);
213 }
214
215
216
217
218
219
220
221 public interface FileModeStrategy {
222
223
224
225
226
227
228
229
230
231
232 FileMode getMode(File f, FS.Attributes attributes);
233 }
234
235
236
237
238
239
240
241 public static class DefaultFileModeStrategy implements FileModeStrategy {
242
243
244
245 public static final DefaultFileModeStrategy INSTANCE =
246 new DefaultFileModeStrategy();
247
248 @Override
249 public FileMode getMode(File f, FS.Attributes attributes) {
250 if (attributes.isSymbolicLink()) {
251 return FileMode.SYMLINK;
252 } else if (attributes.isDirectory()) {
253 if (new File(f, Constants.DOT_GIT).exists()) {
254 return FileMode.GITLINK;
255 }
256 return FileMode.TREE;
257 } else if (attributes.isExecutable()) {
258 return FileMode.EXECUTABLE_FILE;
259 } else {
260 return FileMode.REGULAR_FILE;
261 }
262 }
263 }
264
265
266
267
268
269
270
271
272
273 public static class NoGitlinksStrategy implements FileModeStrategy {
274
275
276
277
278 public static final NoGitlinksStrategy INSTANCE = new NoGitlinksStrategy();
279
280 @Override
281 public FileMode getMode(File f, FS.Attributes attributes) {
282 if (attributes.isSymbolicLink()) {
283 return FileMode.SYMLINK;
284 } else if (attributes.isDirectory()) {
285 return FileMode.TREE;
286 } else if (attributes.isExecutable()) {
287 return FileMode.EXECUTABLE_FILE;
288 } else {
289 return FileMode.REGULAR_FILE;
290 }
291 }
292 }
293
294
295
296
297
298 public static class FileEntry extends Entry {
299 private final FileMode mode;
300
301 private FS.Attributes attributes;
302
303 private FS fs;
304
305
306
307
308
309
310
311
312
313 public FileEntry(File f, FS fs) {
314 this(f, fs, DefaultFileModeStrategy.INSTANCE);
315 }
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330 public FileEntry(File f, FS fs, FileModeStrategy fileModeStrategy) {
331 this.fs = fs;
332 f = fs.normalize(f);
333 attributes = fs.getAttributes(f);
334 mode = fileModeStrategy.getMode(f, attributes);
335 }
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352 public FileEntry(File f, FS fs, FS.Attributes attributes,
353 FileModeStrategy fileModeStrategy) {
354 this.fs = fs;
355 this.attributes = attributes;
356 f = fs.normalize(f);
357 mode = fileModeStrategy.getMode(f, attributes);
358 }
359
360 @Override
361 public FileMode getMode() {
362 return mode;
363 }
364
365 @Override
366 public String getName() {
367 return attributes.getName();
368 }
369
370 @Override
371 public long getLength() {
372 return attributes.getLength();
373 }
374
375 @Override
376 @Deprecated
377 public long getLastModified() {
378 return attributes.getLastModifiedInstant().toEpochMilli();
379 }
380
381
382
383
384 @Override
385 public Instant getLastModifiedInstant() {
386 return attributes.getLastModifiedInstant();
387 }
388
389 @Override
390 public InputStream openInputStream() throws IOException {
391 if (attributes.isSymbolicLink()) {
392 return new ByteArrayInputStream(fs.readSymLink(getFile())
393 .getBytes(UTF_8));
394 }
395 return new FileInputStream(getFile());
396 }
397
398
399
400
401
402
403 public File getFile() {
404 return attributes.getFile();
405 }
406 }
407
408
409
410
411
412
413 public File getDirectory() {
414 return directory;
415 }
416
417
418
419
420
421
422
423
424 public File getEntryFile() {
425 return ((FileEntry) current()).getFile();
426 }
427
428
429 @Override
430 protected byte[] idSubmodule(Entry e) {
431 return idSubmodule(getDirectory(), e);
432 }
433
434
435 @Override
436 protected String readSymlinkTarget(Entry entry) throws IOException {
437 return fs.readSymLink(getEntryFile());
438 }
439 }