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.junit;
45
46 import static java.nio.charset.StandardCharsets.UTF_8;
47 import static org.junit.Assert.assertEquals;
48 import static org.junit.Assert.fail;
49
50 import java.io.BufferedOutputStream;
51 import java.io.File;
52 import java.io.FileOutputStream;
53 import java.io.IOException;
54 import java.io.OutputStream;
55 import java.security.MessageDigest;
56 import java.util.ArrayList;
57 import java.util.Arrays;
58 import java.util.Collections;
59 import java.util.Date;
60 import java.util.HashSet;
61 import java.util.List;
62 import java.util.Set;
63 import java.util.TimeZone;
64
65 import org.eclipse.jgit.api.Git;
66 import org.eclipse.jgit.dircache.DirCache;
67 import org.eclipse.jgit.dircache.DirCacheBuilder;
68 import org.eclipse.jgit.dircache.DirCacheEditor;
69 import org.eclipse.jgit.dircache.DirCacheEditor.DeletePath;
70 import org.eclipse.jgit.dircache.DirCacheEditor.DeleteTree;
71 import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
72 import org.eclipse.jgit.dircache.DirCacheEntry;
73 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
74 import org.eclipse.jgit.errors.MissingObjectException;
75 import org.eclipse.jgit.errors.ObjectWritingException;
76 import org.eclipse.jgit.internal.storage.file.FileRepository;
77 import org.eclipse.jgit.internal.storage.file.LockFile;
78 import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
79 import org.eclipse.jgit.internal.storage.file.PackFile;
80 import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
81 import org.eclipse.jgit.internal.storage.pack.PackWriter;
82 import org.eclipse.jgit.lib.AnyObjectId;
83 import org.eclipse.jgit.lib.Constants;
84 import org.eclipse.jgit.lib.FileMode;
85 import org.eclipse.jgit.lib.NullProgressMonitor;
86 import org.eclipse.jgit.lib.ObjectChecker;
87 import org.eclipse.jgit.lib.ObjectId;
88 import org.eclipse.jgit.lib.ObjectInserter;
89 import org.eclipse.jgit.lib.PersonIdent;
90 import org.eclipse.jgit.lib.Ref;
91 import org.eclipse.jgit.lib.RefUpdate;
92 import org.eclipse.jgit.lib.RefWriter;
93 import org.eclipse.jgit.lib.Repository;
94 import org.eclipse.jgit.lib.TagBuilder;
95 import org.eclipse.jgit.merge.MergeStrategy;
96 import org.eclipse.jgit.merge.ThreeWayMerger;
97 import org.eclipse.jgit.revwalk.ObjectWalk;
98 import org.eclipse.jgit.revwalk.RevBlob;
99 import org.eclipse.jgit.revwalk.RevCommit;
100 import org.eclipse.jgit.revwalk.RevObject;
101 import org.eclipse.jgit.revwalk.RevTag;
102 import org.eclipse.jgit.revwalk.RevTree;
103 import org.eclipse.jgit.revwalk.RevWalk;
104 import org.eclipse.jgit.treewalk.TreeWalk;
105 import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
106 import org.eclipse.jgit.util.ChangeIdUtil;
107 import org.eclipse.jgit.util.FileUtils;
108
109
110
111
112
113
114
115 public class TestRepository<R extends Repository> implements AutoCloseable {
116
117
118 public static final String AUTHOR = "J. Author";
119
120
121 public static final String AUTHOR_EMAIL = "jauthor@example.com";
122
123
124 public static final String COMMITTER = "J. Committer";
125
126
127 public static final String COMMITTER_EMAIL = "jcommitter@example.com";
128
129 private final PersonIdent defaultAuthor;
130
131 private final PersonIdent defaultCommitter;
132
133 private final R db;
134
135 private final Git git;
136
137 private final RevWalk pool;
138
139 private final ObjectInserter inserter;
140
141 private final MockSystemReader mockSystemReader;
142
143
144
145
146
147
148
149
150 public TestRepository(R db) throws IOException {
151 this(db, new RevWalk(db), new MockSystemReader());
152 }
153
154
155
156
157
158
159
160
161
162
163 public TestRepository(R db, RevWalk rw) throws IOException {
164 this(db, rw, new MockSystemReader());
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180 public TestRepository(R db, RevWalk rw, MockSystemReader reader)
181 throws IOException {
182 this.db = db;
183 this.git = Git.wrap(db);
184 this.pool = rw;
185 this.inserter = db.newObjectInserter();
186 this.mockSystemReader = reader;
187 long now = mockSystemReader.getCurrentTime();
188 int tz = mockSystemReader.getTimezone(now);
189 defaultAuthor = new PersonIdent(AUTHOR, AUTHOR_EMAIL, now, tz);
190 defaultCommitter = new PersonIdent(COMMITTER, COMMITTER_EMAIL, now, tz);
191 }
192
193
194
195
196
197
198 public R getRepository() {
199 return db;
200 }
201
202
203
204
205
206
207 public RevWalk getRevWalk() {
208 return pool;
209 }
210
211
212
213
214
215
216
217
218 public Git git() {
219 return git;
220 }
221
222
223
224
225
226
227
228 public Date getDate() {
229 return new Date(mockSystemReader.getCurrentTime());
230 }
231
232
233
234
235
236
237 public TimeZone getTimeZone() {
238 return mockSystemReader.getTimeZone();
239 }
240
241
242
243
244
245
246
247 public void tick(int secDelta) {
248 mockSystemReader.tick(secDelta);
249 }
250
251
252
253
254
255
256
257 public void setAuthorAndCommitter(org.eclipse.jgit.lib.CommitBuilder c) {
258 c.setAuthor(new PersonIdent(defaultAuthor, getDate()));
259 c.setCommitter(new PersonIdent(defaultCommitter, getDate()));
260 }
261
262
263
264
265
266
267
268
269
270 public RevBlob blob(String content) throws Exception {
271 return blob(content.getBytes(UTF_8));
272 }
273
274
275
276
277
278
279
280
281
282 public RevBlob blob(byte[] content) throws Exception {
283 ObjectId id;
284 try (ObjectInserter ins = inserter) {
285 id = ins.insert(Constants.OBJ_BLOB, content);
286 ins.flush();
287 }
288 return (RevBlob) pool.parseAny(id);
289 }
290
291
292
293
294
295
296
297
298
299
300
301 public DirCacheEntry file(String path, RevBlob blob)
302 throws Exception {
303 final DirCacheEntryacheEntry.html#DirCacheEntry">DirCacheEntry e = new DirCacheEntry(path);
304 e.setFileMode(FileMode.REGULAR_FILE);
305 e.setObjectId(blob);
306 return e;
307 }
308
309
310
311
312
313
314
315
316
317
318 public RevTree tree(DirCacheEntry... entries) throws Exception {
319 final DirCache dc = DirCache.newInCore();
320 final DirCacheBuilder b = dc.builder();
321 for (DirCacheEntry e : entries) {
322 b.add(e);
323 }
324 b.finish();
325 ObjectId root;
326 try (ObjectInserter ins = inserter) {
327 root = dc.writeTree(ins);
328 ins.flush();
329 }
330 return pool.parseTree(root);
331 }
332
333
334
335
336
337
338
339
340
341
342
343 public RevObject get(RevTree tree, String path)
344 throws Exception {
345 try (TreeWalkTreeWalk.html#TreeWalk">TreeWalk tw = new TreeWalk(pool.getObjectReader())) {
346 tw.setFilter(PathFilterGroup.createFromStrings(Collections
347 .singleton(path)));
348 tw.reset(tree);
349 while (tw.next()) {
350 if (tw.isSubtree() && !path.equals(tw.getPathString())) {
351 tw.enterSubtree();
352 continue;
353 }
354 final ObjectId entid = tw.getObjectId(0);
355 final FileMode entmode = tw.getFileMode(0);
356 return pool.lookupAny(entid, entmode.getObjectType());
357 }
358 }
359 fail("Can't find " + path + " in tree " + tree.name());
360 return null;
361 }
362
363
364
365
366
367
368
369
370
371
372
373
374 public RevCommit commit(RevCommit... parents) throws Exception {
375 return commit(1, tree(), parents);
376 }
377
378
379
380
381
382
383
384
385
386
387
388
389
390 public RevCommit commit(RevTree tree, RevCommit... parents)
391 throws Exception {
392 return commit(1, tree, parents);
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408 public RevCommit commit(int secDelta, RevCommit... parents)
409 throws Exception {
410 return commit(secDelta, tree(), parents);
411 }
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429 public RevCommit commit(final int secDelta, final RevTree tree,
430 final RevCommit... parents) throws Exception {
431 tick(secDelta);
432
433 final org.eclipse.jgit.lib.CommitBuilder c;
434
435 c = new org.eclipse.jgit.lib.CommitBuilder();
436 c.setTreeId(tree);
437 c.setParentIds(parents);
438 c.setAuthor(new PersonIdent(defaultAuthor, getDate()));
439 c.setCommitter(new PersonIdent(defaultCommitter, getDate()));
440 c.setMessage("");
441 ObjectId id;
442 try (ObjectInserter ins = inserter) {
443 id = ins.insert(c);
444 ins.flush();
445 }
446 return pool.parseCommit(id);
447 }
448
449
450
451
452
453
454 public CommitBuilder commit() {
455 return new CommitBuilder();
456 }
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474 public RevTag tag(String name, RevObject dst) throws Exception {
475 final TagBuilderlder.html#TagBuilder">TagBuilder t = new TagBuilder();
476 t.setObjectId(dst);
477 t.setTag(name);
478 t.setTagger(new PersonIdent(defaultCommitter, getDate()));
479 t.setMessage("");
480 ObjectId id;
481 try (ObjectInserter ins = inserter) {
482 id = ins.insert(t);
483 ins.flush();
484 }
485 return pool.parseTag(id);
486 }
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502 public RevCommit update(String ref, CommitBuilder to) throws Exception {
503 return update(ref, to.create());
504 }
505
506
507
508
509
510
511
512
513
514
515
516
517
518 public CommitBuilder amendRef(String ref) throws Exception {
519 String name = normalizeRef(ref);
520 Ref r = db.exactRef(name);
521 if (r == null)
522 throw new IOException("Not a ref: " + ref);
523 return amend(pool.parseCommit(r.getObjectId()), branch(name).commit());
524 }
525
526
527
528
529
530
531
532
533
534 public CommitBuilder amend(AnyObjectId id) throws Exception {
535 return amend(pool.parseCommit(id), commit());
536 }
537
538 private CommitBuilderlipse/jgit/lib/CommitBuilder.html#CommitBuilder">CommitBuilder amend(RevCommit old, CommitBuilder b) throws Exception {
539 pool.parseBody(old);
540 b.author(old.getAuthorIdent());
541 b.committer(old.getCommitterIdent());
542 b.message(old.getFullMessage());
543
544
545 b.updateCommitterTime = true;
546
547
548 b.noParents();
549 for (int i = 0; i < old.getParentCount(); i++)
550 b.parent(old.getParent(i));
551
552
553
554 b.tree.clear();
555 try (TreeWalkTreeWalk.html#TreeWalk">TreeWalk tw = new TreeWalk(db)) {
556 tw.reset(old.getTree());
557 tw.setRecursive(true);
558 while (tw.next()) {
559 b.edit(new PathEdit(tw.getPathString()) {
560 @Override
561 public void apply(DirCacheEntry ent) {
562 ent.setFileMode(tw.getFileMode(0));
563 ent.setObjectId(tw.getObjectId(0));
564 }
565 });
566 }
567 }
568
569 return b;
570 }
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588 public <T extends AnyObjectId> T update(String ref, T obj) throws Exception {
589 ref = normalizeRef(ref);
590 RefUpdate u = db.updateRef(ref);
591 u.setNewObjectId(obj);
592 switch (u.forceUpdate()) {
593 case FAST_FORWARD:
594 case FORCED:
595 case NEW:
596 case NO_CHANGE:
597 updateServerInfo();
598 return obj;
599
600 default:
601 throw new IOException("Cannot write " + ref + " " + u.getResult());
602 }
603 }
604
605
606
607
608
609
610
611
612
613
614 public void delete(String ref) throws Exception {
615 ref = normalizeRef(ref);
616 RefUpdate u = db.updateRef(ref);
617 u.setForceUpdate(true);
618 switch (u.delete()) {
619 case FAST_FORWARD:
620 case FORCED:
621 case NEW:
622 case NO_CHANGE:
623 updateServerInfo();
624 return;
625
626 default:
627 throw new IOException("Cannot delete " + ref + " " + u.getResult());
628 }
629 }
630
631 private static String normalizeRef(String ref) {
632 if (Constants.HEAD.equals(ref)) {
633
634 } else if ("FETCH_HEAD".equals(ref)) {
635
636 } else if ("MERGE_HEAD".equals(ref)) {
637
638 } else if (ref.startsWith(Constants.R_REFS)) {
639
640 } else
641 ref = Constants.R_HEADS + ref;
642 return ref;
643 }
644
645
646
647
648
649
650
651
652
653 public void reset(AnyObjectId id) throws Exception {
654 RefUpdate ru = db.updateRef(Constants.HEAD, true);
655 ru.setNewObjectId(id);
656 RefUpdate.Result result = ru.forceUpdate();
657 switch (result) {
658 case FAST_FORWARD:
659 case FORCED:
660 case NEW:
661 case NO_CHANGE:
662 break;
663 default:
664 throw new IOException(String.format(
665 "Checkout \"%s\" failed: %s", id.name(), result));
666 }
667 }
668
669
670
671
672
673
674
675
676
677
678
679
680 public void reset(String name) throws Exception {
681 RefUpdate.Result result;
682 ObjectId id = db.resolve(name);
683 if (id == null)
684 throw new IOException("Not a revision: " + name);
685 RefUpdate ru = db.updateRef(Constants.HEAD, false);
686 ru.setNewObjectId(id);
687 result = ru.forceUpdate();
688 switch (result) {
689 case FAST_FORWARD:
690 case FORCED:
691 case NEW:
692 case NO_CHANGE:
693 break;
694 default:
695 throw new IOException(String.format(
696 "Checkout \"%s\" failed: %s", name, result));
697 }
698 }
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713 public RevCommit cherryPick(AnyObjectId id) throws Exception {
714 RevCommit commit = pool.parseCommit(id);
715 pool.parseBody(commit);
716 if (commit.getParentCount() != 1)
717 throw new IOException(String.format(
718 "Expected 1 parent for %s, found: %s",
719 id.name(), Arrays.asList(commit.getParents())));
720 RevCommit parent = commit.getParent(0);
721 pool.parseHeaders(parent);
722
723 Ref headRef = db.exactRef(Constants.HEAD);
724 if (headRef == null)
725 throw new IOException("Missing HEAD");
726 RevCommit head = pool.parseCommit(headRef.getObjectId());
727
728 ThreeWayMerger merger = MergeStrategy.RECURSIVE.newMerger(db, true);
729 merger.setBase(parent.getTree());
730 if (merger.merge(head, commit)) {
731 if (AnyObjectId.equals(head.getTree(), merger.getResultTreeId()))
732 return null;
733 tick(1);
734 org.eclipse.jgit.lib.CommitBuilder b =
735 new org.eclipse.jgit.lib.CommitBuilder();
736 b.setParentId(head);
737 b.setTreeId(merger.getResultTreeId());
738 b.setAuthor(commit.getAuthorIdent());
739 b.setCommitter(new PersonIdent(defaultCommitter, getDate()));
740 b.setMessage(commit.getFullMessage());
741 ObjectId result;
742 try (ObjectInserter ins = inserter) {
743 result = ins.insert(b);
744 ins.flush();
745 }
746 update(Constants.HEAD, result);
747 return pool.parseCommit(result);
748 } else {
749 throw new IOException("Merge conflict");
750 }
751 }
752
753
754
755
756
757
758 public void updateServerInfo() throws Exception {
759 if (db instanceof FileRepository) {
760 final FileRepository./../../org/eclipse/jgit/internal/storage/file/FileRepository.html#FileRepository">FileRepository fr = (FileRepository) db;
761 RefWriter rw = new RefWriter(fr.getRefDatabase().getRefs()) {
762 @Override
763 protected void writeFile(String name, byte[] bin)
764 throws IOException {
765 File path = new File(fr.getDirectory(), name);
766 TestRepository.this.writeFile(path, bin);
767 }
768 };
769 rw.writePackedRefs();
770 rw.writeInfoRefs();
771
772 final StringBuilder w = new StringBuilder();
773 for (PackFile p : fr.getObjectDatabase().getPacks()) {
774 w.append("P ");
775 w.append(p.getPackFile().getName());
776 w.append('\n');
777 }
778 writeFile(new File(new File(fr.getObjectDatabase().getDirectory(),
779 "info"), "packs"), Constants.encodeASCII(w.toString()));
780 }
781 }
782
783
784
785
786
787
788
789
790
791
792
793
794
795 public <T extends RevObject> T parseBody(T object) throws Exception {
796 pool.parseBody(object);
797 return object;
798 }
799
800
801
802
803
804
805
806
807
808
809 public BranchBuilder branch(String ref) {
810 if (Constants.HEAD.equals(ref)) {
811
812 } else if (ref.startsWith(Constants.R_REFS)) {
813
814 } else
815 ref = Constants.R_HEADS + ref;
816 return new BranchBuilder(ref);
817 }
818
819
820
821
822
823
824
825
826
827
828
829
830 public ObjectIdpse/jgit/lib/ObjectId.html#ObjectId">ObjectId lightweightTag(String name, ObjectId obj) throws Exception {
831 if (!name.startsWith(Constants.R_TAGS))
832 name = Constants.R_TAGS + name;
833 return update(name, obj);
834 }
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849 public void fsck(RevObject... tips) throws MissingObjectException,
850 IncorrectObjectTypeException, IOException {
851 try (ObjectWalkectWalk.html#ObjectWalk">ObjectWalk ow = new ObjectWalk(db)) {
852 if (tips.length != 0) {
853 for (RevObject o : tips)
854 ow.markStart(ow.parseAny(o));
855 } else {
856 for (Ref r : db.getRefDatabase().getRefs())
857 ow.markStart(ow.parseAny(r.getObjectId()));
858 }
859
860 ObjectChecker oc = new ObjectChecker();
861 for (;;) {
862 final RevCommit o = ow.next();
863 if (o == null)
864 break;
865
866 final byte[] bin = db.open(o, o.getType()).getCachedBytes();
867 oc.checkCommit(o, bin);
868 assertHash(o, bin);
869 }
870
871 for (;;) {
872 final RevObject o = ow.nextObject();
873 if (o == null)
874 break;
875
876 final byte[] bin = db.open(o, o.getType()).getCachedBytes();
877 oc.check(o, o.getType(), bin);
878 assertHash(o, bin);
879 }
880 }
881 }
882
883 private static void assertHash(RevObject id, byte[] bin) {
884 MessageDigest md = Constants.newMessageDigest();
885 md.update(Constants.encodedTypeString(id.getType()));
886 md.update((byte) ' ');
887 md.update(Constants.encodeASCII(bin.length));
888 md.update((byte) 0);
889 md.update(bin);
890 assertEquals(id, ObjectId.fromRaw(md.digest()));
891 }
892
893
894
895
896
897
898
899
900
901 public void packAndPrune() throws Exception {
902 if (db.getObjectDatabase() instanceof ObjectDirectory) {
903 ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase();
904 NullProgressMonitor m = NullProgressMonitor.INSTANCE;
905
906 final File pack, idx;
907 try (PackWriterorage/pack/PackWriter.html#PackWriter">PackWriter pw = new PackWriter(db)) {
908 Set<ObjectId> all = new HashSet<>();
909 for (Ref r : db.getRefDatabase().getRefs())
910 all.add(r.getObjectId());
911 pw.preparePack(m, all, PackWriter.NONE);
912
913 final ObjectId name = pw.computeName();
914
915 pack = nameFor(odb, name, ".pack");
916 try (OutputStream out =
917 new BufferedOutputStream(new FileOutputStream(pack))) {
918 pw.writePack(m, m, out);
919 }
920 pack.setReadOnly();
921
922 idx = nameFor(odb, name, ".idx");
923 try (OutputStream out =
924 new BufferedOutputStream(new FileOutputStream(idx))) {
925 pw.writeIndex(out);
926 }
927 idx.setReadOnly();
928 }
929
930 odb.openPack(pack);
931 updateServerInfo();
932 prunePacked(odb);
933 }
934 }
935
936
937
938
939
940
941
942
943
944 @Override
945 public void close() {
946 try {
947 inserter.close();
948 } finally {
949 db.close();
950 }
951 }
952
953 private static void prunePacked(ObjectDirectory odb) throws IOException {
954 for (PackFile p : odb.getPacks()) {
955 for (MutableEntry e : p)
956 FileUtils.delete(odb.fileFor(e.toObjectId()));
957 }
958 }
959
960 private static File nameFor(ObjectDirectory odb, ObjectId name, String t) {
961 File packdir = odb.getPackDirectory();
962 return new File(packdir, "pack-" + name.name() + t);
963 }
964
965 private void writeFile(File p, byte[] bin) throws IOException,
966 ObjectWritingException {
967 final LockFiletorage/file/LockFile.html#LockFile">LockFile lck = new LockFile(p);
968 if (!lck.lock())
969 throw new ObjectWritingException("Can't write " + p);
970 try {
971 lck.write(bin);
972 } catch (IOException ioe) {
973 throw new ObjectWritingException("Can't write " + p);
974 }
975 if (!lck.commit())
976 throw new ObjectWritingException("Can't write " + p);
977 }
978
979
980 public class BranchBuilder {
981 private final String ref;
982
983 BranchBuilder(String ref) {
984 this.ref = ref;
985 }
986
987
988
989
990
991
992
993
994
995 public CommitBuilder commit() throws Exception {
996 return new CommitBuilder(this);
997 }
998
999
1000
1001
1002
1003
1004
1005
1006
1007 public RevCommit update(CommitBuilder to) throws Exception {
1008 return update(to.create());
1009 }
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019 public RevCommit../../../../org/eclipse/jgit/revwalk/RevCommit.html#RevCommit">RevCommit update(RevCommit to) throws Exception {
1020 return TestRepository.this.update(ref, to);
1021 }
1022
1023
1024
1025
1026
1027
1028 public void delete() throws Exception {
1029 TestRepository.this.delete(ref);
1030 }
1031 }
1032
1033
1034 public class CommitBuilder {
1035 private final BranchBuilder branch;
1036
1037 private final DirCache tree = DirCache.newInCore();
1038
1039 private ObjectId topLevelTree;
1040
1041 private final List<RevCommit> parents = new ArrayList<>(2);
1042
1043 private int tick = 1;
1044
1045 private String message = "";
1046
1047 private RevCommit self;
1048
1049 private PersonIdent author;
1050 private PersonIdent committer;
1051
1052 private String changeId;
1053
1054 private boolean updateCommitterTime;
1055
1056 CommitBuilder() {
1057 branch = null;
1058 }
1059
1060 CommitBuilder(BranchBuilder b) throws Exception {
1061 branch = b;
1062
1063 Ref ref = db.exactRef(branch.ref);
1064 if (ref != null && ref.getObjectId() != null)
1065 parent(pool.parseCommit(ref.getObjectId()));
1066 }
1067
1068 CommitBuilder(CommitBuilder prior) throws Exception {
1069 branch = prior.branch;
1070
1071 DirCacheBuilder b = tree.builder();
1072 for (int i = 0; i < prior.tree.getEntryCount(); i++)
1073 b.add(prior.tree.getEntry(i));
1074 b.finish();
1075
1076 parents.add(prior.create());
1077 }
1078
1079 public CommitBuilder parent(RevCommit p) throws Exception {
1080 if (parents.isEmpty()) {
1081 DirCacheBuilder b = tree.builder();
1082 parseBody(p);
1083 b.addTree(new byte[0], DirCacheEntry.STAGE_0, pool
1084 .getObjectReader(), p.getTree());
1085 b.finish();
1086 }
1087 parents.add(p);
1088 return this;
1089 }
1090
1091 public List<RevCommit> parents() {
1092 return Collections.unmodifiableList(parents);
1093 }
1094
1095 public CommitBuilder noParents() {
1096 parents.clear();
1097 return this;
1098 }
1099
1100 public CommitBuilder noFiles() {
1101 tree.clear();
1102 return this;
1103 }
1104
1105 public CommitBuilder setTopLevelTree(ObjectId treeId) {
1106 topLevelTree = treeId;
1107 return this;
1108 }
1109
1110 public CommitBuilder add(String path, String content) throws Exception {
1111 return add(path, blob(content));
1112 }
1113
1114 public CommitBuilder add(String path, RevBlob id)
1115 throws Exception {
1116 return edit(new PathEdit(path) {
1117 @Override
1118 public void apply(DirCacheEntry ent) {
1119 ent.setFileMode(FileMode.REGULAR_FILE);
1120 ent.setObjectId(id);
1121 }
1122 });
1123 }
1124
1125 public CommitBuilder edit(PathEdit edit) {
1126 DirCacheEditor e = tree.editor();
1127 e.add(edit);
1128 e.finish();
1129 return this;
1130 }
1131
1132 public CommitBuilder rm(String path) {
1133 DirCacheEditor e = tree.editor();
1134 e.add(new DeletePath(path));
1135 e.add(new DeleteTree(path));
1136 e.finish();
1137 return this;
1138 }
1139
1140 public CommitBuilder message(String m) {
1141 message = m;
1142 return this;
1143 }
1144
1145 public String message() {
1146 return message;
1147 }
1148
1149 public CommitBuilder tick(int secs) {
1150 tick = secs;
1151 return this;
1152 }
1153
1154 public CommitBuilder ident(PersonIdent ident) {
1155 author = ident;
1156 committer = ident;
1157 return this;
1158 }
1159
1160 public CommitBuilder author(PersonIdent a) {
1161 author = a;
1162 return this;
1163 }
1164
1165 public PersonIdent author() {
1166 return author;
1167 }
1168
1169 public CommitBuilder committer(PersonIdent c) {
1170 committer = c;
1171 return this;
1172 }
1173
1174 public PersonIdent committer() {
1175 return committer;
1176 }
1177
1178 public CommitBuilder insertChangeId() {
1179 changeId = "";
1180 return this;
1181 }
1182
1183 public CommitBuilder insertChangeId(String c) {
1184
1185 ObjectId.fromString(c);
1186 changeId = c;
1187 return this;
1188 }
1189
1190 public RevCommit create() throws Exception {
1191 if (self == null) {
1192 TestRepository.this.tick(tick);
1193
1194 final org.eclipse.jgit.lib.CommitBuilder c;
1195
1196 c = new org.eclipse.jgit.lib.CommitBuilder();
1197 c.setParentIds(parents);
1198 setAuthorAndCommitter(c);
1199 if (author != null)
1200 c.setAuthor(author);
1201 if (committer != null) {
1202 if (updateCommitterTime)
1203 committer = new PersonIdent(committer, getDate());
1204 c.setCommitter(committer);
1205 }
1206
1207 ObjectId commitId;
1208 try (ObjectInserter ins = inserter) {
1209 if (topLevelTree != null)
1210 c.setTreeId(topLevelTree);
1211 else
1212 c.setTreeId(tree.writeTree(ins));
1213 insertChangeId(c);
1214 c.setMessage(message);
1215 commitId = ins.insert(c);
1216 ins.flush();
1217 }
1218 self = pool.parseCommit(commitId);
1219
1220 if (branch != null)
1221 branch.update(self);
1222 }
1223 return self;
1224 }
1225
1226 private void insertChangeId(org.eclipse.jgit.lib.CommitBuilder c) {
1227 if (changeId == null)
1228 return;
1229 int idx = ChangeIdUtil.indexOfChangeId(message, "\n");
1230 if (idx >= 0)
1231 return;
1232
1233 ObjectId firstParentId = null;
1234 if (!parents.isEmpty())
1235 firstParentId = parents.get(0);
1236
1237 ObjectId cid;
1238 if (changeId.isEmpty())
1239 cid = ChangeIdUtil.computeChangeId(c.getTreeId(), firstParentId,
1240 c.getAuthor(), c.getCommitter(), message);
1241 else
1242 cid = ObjectId.fromString(changeId);
1243 message = ChangeIdUtil.insertId(message, cid);
1244 if (cid != null)
1245 message = message.replaceAll("\nChange-Id: I"
1246 + ObjectId.zeroId().getName() + "\n", "\nChange-Id: I"
1247 + cid.getName() + "\n");
1248 }
1249
1250 public CommitBuilder child() throws Exception {
1251 return new CommitBuilder(this);
1252 }
1253 }
1254 }