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