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.lib;
45
46 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION;
47 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BARE;
48 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WORKTREE;
49 import static org.eclipse.jgit.lib.Constants.DOT_GIT;
50 import static org.eclipse.jgit.lib.Constants.GIT_ALTERNATE_OBJECT_DIRECTORIES_KEY;
51 import static org.eclipse.jgit.lib.Constants.GIT_CEILING_DIRECTORIES_KEY;
52 import static org.eclipse.jgit.lib.Constants.GIT_DIR_KEY;
53 import static org.eclipse.jgit.lib.Constants.GIT_INDEX_FILE_KEY;
54 import static org.eclipse.jgit.lib.Constants.GIT_OBJECT_DIRECTORY_KEY;
55 import static org.eclipse.jgit.lib.Constants.GIT_WORK_TREE_KEY;
56
57 import java.io.File;
58 import java.io.IOException;
59 import java.text.MessageFormat;
60 import java.util.Collection;
61 import java.util.LinkedList;
62 import java.util.List;
63
64 import org.eclipse.jgit.errors.ConfigInvalidException;
65 import org.eclipse.jgit.errors.RepositoryNotFoundException;
66 import org.eclipse.jgit.internal.JGitText;
67 import org.eclipse.jgit.internal.storage.file.FileRepository;
68 import org.eclipse.jgit.lib.RepositoryCache.FileKey;
69 import org.eclipse.jgit.storage.file.FileBasedConfig;
70 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
71 import org.eclipse.jgit.util.FS;
72 import org.eclipse.jgit.util.IO;
73 import org.eclipse.jgit.util.RawParseUtils;
74 import org.eclipse.jgit.util.SystemReader;
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Repository> {
90 private static boolean isSymRef(byte[] ref) {
91 if (ref.length < 9)
92 return false;
93 return ref[0] == 'g'
94 && ref[1] == 'i'
95 && ref[2] == 't'
96 && ref[3] == 'd'
97 && ref[4] == 'i'
98 && ref[5] == 'r'
99 && ref[6] == ':'
100 && ref[7] == ' ';
101 }
102
103 private static File getSymRef(File workTree, File dotGit, FS fs)
104 throws IOException {
105 byte[] content = IO.readFully(dotGit);
106 if (!isSymRef(content))
107 throw new IOException(MessageFormat.format(
108 JGitText.get().invalidGitdirRef, dotGit.getAbsolutePath()));
109
110 int pathStart = 8;
111 int lineEnd = RawParseUtils.nextLF(content, pathStart);
112 if (content[lineEnd - 1] == '\n')
113 lineEnd--;
114 if (lineEnd == pathStart)
115 throw new IOException(MessageFormat.format(
116 JGitText.get().invalidGitdirRef, dotGit.getAbsolutePath()));
117
118 String gitdirPath = RawParseUtils.decode(content, pathStart, lineEnd);
119 File gitdirFile = fs.resolve(workTree, gitdirPath);
120 if (gitdirFile.isAbsolute())
121 return gitdirFile;
122 else
123 return new File(workTree, gitdirPath).getCanonicalFile();
124 }
125
126 private FS fs;
127
128 private File gitDir;
129
130 private File objectDirectory;
131
132 private List<File> alternateObjectDirectories;
133
134 private File indexFile;
135
136 private File workTree;
137
138
139 private List<File> ceilingDirectories;
140
141
142 private boolean bare;
143
144
145 private boolean mustExist;
146
147
148 private Config config;
149
150
151
152
153
154
155
156
157 public B setFS(FS fs) {
158 this.fs = fs;
159 return self();
160 }
161
162
163 public FS getFS() {
164 return fs;
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178 public B setGitDir(File gitDir) {
179 this.gitDir = gitDir;
180 this.config = null;
181 return self();
182 }
183
184
185 public File getGitDir() {
186 return gitDir;
187 }
188
189
190
191
192
193
194
195
196
197 public B setObjectDirectory(File objectDirectory) {
198 this.objectDirectory = objectDirectory;
199 return self();
200 }
201
202
203 public File getObjectDirectory() {
204 return objectDirectory;
205 }
206
207
208
209
210
211
212
213
214
215
216
217 public B addAlternateObjectDirectory(File other) {
218 if (other != null) {
219 if (alternateObjectDirectories == null)
220 alternateObjectDirectories = new LinkedList<File>();
221 alternateObjectDirectories.add(other);
222 }
223 return self();
224 }
225
226
227
228
229
230
231
232
233
234
235
236
237 public B addAlternateObjectDirectories(Collection<File> inList) {
238 if (inList != null) {
239 for (File path : inList)
240 addAlternateObjectDirectory(path);
241 }
242 return self();
243 }
244
245
246
247
248
249
250
251
252
253
254
255
256 public B addAlternateObjectDirectories(File[] inList) {
257 if (inList != null) {
258 for (File path : inList)
259 addAlternateObjectDirectory(path);
260 }
261 return self();
262 }
263
264
265 public File[] getAlternateObjectDirectories() {
266 final List<File> alts = alternateObjectDirectories;
267 if (alts == null)
268 return null;
269 return alts.toArray(new File[alts.size()]);
270 }
271
272
273
274
275
276
277
278
279
280 public B setBare() {
281 setIndexFile(null);
282 setWorkTree(null);
283 bare = true;
284 return self();
285 }
286
287
288 public boolean isBare() {
289 return bare;
290 }
291
292
293
294
295
296
297
298
299
300 public B setMustExist(boolean mustExist) {
301 this.mustExist = mustExist;
302 return self();
303 }
304
305
306 public boolean isMustExist() {
307 return mustExist;
308 }
309
310
311
312
313
314
315
316
317 public B setWorkTree(File workTree) {
318 this.workTree = workTree;
319 return self();
320 }
321
322
323 public File getWorkTree() {
324 return workTree;
325 }
326
327
328
329
330
331
332
333
334
335
336
337
338 public B setIndexFile(File indexFile) {
339 this.indexFile = indexFile;
340 return self();
341 }
342
343
344 public File getIndexFile() {
345 return indexFile;
346 }
347
348
349
350
351
352
353
354
355
356
357
358 public B readEnvironment() {
359 return readEnvironment(SystemReader.getInstance());
360 }
361
362
363
364
365
366
367
368
369
370
371
372
373
374 public B readEnvironment(SystemReader sr) {
375 if (getGitDir() == null) {
376 String val = sr.getenv(GIT_DIR_KEY);
377 if (val != null)
378 setGitDir(new File(val));
379 }
380
381 if (getObjectDirectory() == null) {
382 String val = sr.getenv(GIT_OBJECT_DIRECTORY_KEY);
383 if (val != null)
384 setObjectDirectory(new File(val));
385 }
386
387 if (getAlternateObjectDirectories() == null) {
388 String val = sr.getenv(GIT_ALTERNATE_OBJECT_DIRECTORIES_KEY);
389 if (val != null) {
390 for (String path : val.split(File.pathSeparator))
391 addAlternateObjectDirectory(new File(path));
392 }
393 }
394
395 if (getWorkTree() == null) {
396 String val = sr.getenv(GIT_WORK_TREE_KEY);
397 if (val != null)
398 setWorkTree(new File(val));
399 }
400
401 if (getIndexFile() == null) {
402 String val = sr.getenv(GIT_INDEX_FILE_KEY);
403 if (val != null)
404 setIndexFile(new File(val));
405 }
406
407 if (ceilingDirectories == null) {
408 String val = sr.getenv(GIT_CEILING_DIRECTORIES_KEY);
409 if (val != null) {
410 for (String path : val.split(File.pathSeparator))
411 addCeilingDirectory(new File(path));
412 }
413 }
414
415 return self();
416 }
417
418
419
420
421
422
423
424
425
426
427
428 public B addCeilingDirectory(File root) {
429 if (root != null) {
430 if (ceilingDirectories == null)
431 ceilingDirectories = new LinkedList<File>();
432 ceilingDirectories.add(root);
433 }
434 return self();
435 }
436
437
438
439
440
441
442
443
444
445
446
447
448 public B addCeilingDirectories(Collection<File> inList) {
449 if (inList != null) {
450 for (File path : inList)
451 addCeilingDirectory(path);
452 }
453 return self();
454 }
455
456
457
458
459
460
461
462
463
464
465
466
467 public B addCeilingDirectories(File[] inList) {
468 if (inList != null) {
469 for (File path : inList)
470 addCeilingDirectory(path);
471 }
472 return self();
473 }
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488 public B findGitDir() {
489 if (getGitDir() == null)
490 findGitDir(new File("").getAbsoluteFile());
491 return self();
492 }
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509 public B findGitDir(File current) {
510 if (getGitDir() == null) {
511 FS tryFS = safeFS();
512 while (current != null) {
513 File dir = new File(current, DOT_GIT);
514 if (FileKey.isGitRepository(dir, tryFS)) {
515 setGitDir(dir);
516 break;
517 } else if (dir.isFile()) {
518 try {
519 setGitDir(getSymRef(current, dir, tryFS));
520 break;
521 } catch (IOException ignored) {
522
523 }
524 } else if (FileKey.isGitRepository(current, tryFS)) {
525 setGitDir(current);
526 break;
527 }
528
529 current = current.getParentFile();
530 if (current != null && ceilingDirectories != null
531 && ceilingDirectories.contains(current))
532 break;
533 }
534 }
535 return self();
536 }
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553 public B setup() throws IllegalArgumentException, IOException {
554 requireGitDirOrWorkTree();
555 setupGitDir();
556 setupWorkTree();
557 setupInternals();
558 return self();
559 }
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577 @SuppressWarnings({ "unchecked", "resource" })
578 public R build() throws IOException {
579 R repo = (R) new FileRepository(setup());
580 if (isMustExist() && !repo.getObjectDatabase().exists())
581 throw new RepositoryNotFoundException(getGitDir());
582 return repo;
583 }
584
585
586 protected void requireGitDirOrWorkTree() {
587 if (getGitDir() == null && getWorkTree() == null)
588 throw new IllegalArgumentException(
589 JGitText.get().eitherGitDirOrWorkTreeRequired);
590 }
591
592
593
594
595
596
597
598 protected void setupGitDir() throws IOException {
599
600
601 if (getGitDir() == null && getWorkTree() != null) {
602 File dotGit = new File(getWorkTree(), DOT_GIT);
603 if (!dotGit.isFile())
604 setGitDir(dotGit);
605 else
606 setGitDir(getSymRef(getWorkTree(), dotGit, safeFS()));
607 }
608 }
609
610
611
612
613
614
615
616
617
618
619
620 protected void setupWorkTree() throws IOException {
621 if (getFS() == null)
622 setFS(FS.DETECTED);
623
624
625
626 if (!isBare() && getWorkTree() == null)
627 setWorkTree(guessWorkTreeOrFail());
628
629 if (!isBare()) {
630
631
632
633
634 if (getGitDir() == null)
635 setGitDir(getWorkTree().getParentFile());
636 if (getIndexFile() == null)
637 setIndexFile(new File(getGitDir(), "index"));
638 }
639 }
640
641
642
643
644
645
646
647 protected void setupInternals() throws IOException {
648 if (getObjectDirectory() == null && getGitDir() != null)
649 setObjectDirectory(safeFS().resolve(getGitDir(), "objects"));
650 }
651
652
653
654
655
656
657
658
659 protected Config getConfig() throws IOException {
660 if (config == null)
661 config = loadConfig();
662 return config;
663 }
664
665
666
667
668
669
670
671
672
673
674
675 protected Config loadConfig() throws IOException {
676 if (getGitDir() != null) {
677
678
679
680
681 File path = safeFS().resolve(getGitDir(), Constants.CONFIG);
682 FileBasedConfig cfg = new FileBasedConfig(path, safeFS());
683 try {
684 cfg.load();
685 } catch (ConfigInvalidException err) {
686 throw new IllegalArgumentException(MessageFormat.format(
687 JGitText.get().repositoryConfigFileInvalid, path
688 .getAbsolutePath(), err.getMessage()));
689 }
690 return cfg;
691 } else {
692 return new Config();
693 }
694 }
695
696 private File guessWorkTreeOrFail() throws IOException {
697 final Config cfg = getConfig();
698
699
700
701 String path = cfg.getString(CONFIG_CORE_SECTION, null,
702 CONFIG_KEY_WORKTREE);
703 if (path != null)
704 return safeFS().resolve(getGitDir(), path).getCanonicalFile();
705
706
707
708
709 if (cfg.getString(CONFIG_CORE_SECTION, null, CONFIG_KEY_BARE) != null) {
710 if (cfg.getBoolean(CONFIG_CORE_SECTION, CONFIG_KEY_BARE, true)) {
711 setBare();
712 return null;
713 }
714 return getGitDir().getParentFile();
715 }
716
717 if (getGitDir().getName().equals(DOT_GIT)) {
718
719
720
721 return getGitDir().getParentFile();
722 }
723
724
725
726 setBare();
727 return null;
728 }
729
730
731 protected FS safeFS() {
732 return getFS() != null ? getFS() : FS.DETECTED;
733 }
734
735
736 @SuppressWarnings("unchecked")
737 protected final B self() {
738 return (B) this;
739 }
740 }