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