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.pgm.debug;
45
46 import static org.eclipse.jgit.lib.Constants.HEAD;
47
48 import java.io.IOException;
49 import java.util.ArrayList;
50 import java.util.List;
51
52 import org.eclipse.jgit.internal.storage.reftree.RefTree;
53 import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase;
54 import org.eclipse.jgit.lib.CommitBuilder;
55 import org.eclipse.jgit.lib.ObjectId;
56 import org.eclipse.jgit.lib.ObjectInserter;
57 import org.eclipse.jgit.lib.ObjectReader;
58 import org.eclipse.jgit.lib.PersonIdent;
59 import org.eclipse.jgit.lib.Ref;
60 import org.eclipse.jgit.lib.RefDatabase;
61 import org.eclipse.jgit.lib.RefUpdate;
62 import org.eclipse.jgit.lib.StoredConfig;
63 import org.eclipse.jgit.pgm.Command;
64 import org.eclipse.jgit.pgm.TextBuiltin;
65 import org.eclipse.jgit.revwalk.RevWalk;
66 import org.kohsuke.args4j.Option;
67
68 @Command(usage = "usage_RebuildRefTree")
69 class RebuildRefTree extends TextBuiltin {
70 @Option(name = "--enable", usage = "usage_RebuildRefTreeEnable")
71 boolean enable;
72
73 private String txnNamespace;
74 private String txnCommitted;
75
76
77 @Override
78 protected void run() throws Exception {
79 try (ObjectReader reader = db.newObjectReader();
80 RevWalk rw = new RevWalk(reader);
81 ObjectInserter inserter = db.newObjectInserter()) {
82 RefDatabase refDb = db.getRefDatabase();
83 if (refDb instanceof RefTreeDatabase) {
84 RefTreeDatabase d = (RefTreeDatabase) refDb;
85 refDb = d.getBootstrap();
86 txnNamespace = d.getTxnNamespace();
87 txnCommitted = d.getTxnCommitted();
88 } else {
89 RefTreeDatabase d = new RefTreeDatabase(db, refDb);
90 txnNamespace = d.getTxnNamespace();
91 txnCommitted = d.getTxnCommitted();
92 }
93
94 errw.format("Rebuilding %s from %s",
95 txnCommitted, refDb.getClass().getSimpleName());
96 errw.println();
97 errw.flush();
98
99 CommitBuilder b = new CommitBuilder();
100 Ref ref = refDb.exactRef(txnCommitted);
101 RefUpdate update = refDb.newUpdate(txnCommitted, true);
102 ObjectId oldTreeId;
103
104 if (ref != null && ref.getObjectId() != null) {
105 ObjectId oldId = ref.getObjectId();
106 update.setExpectedOldObjectId(oldId);
107 b.setParentId(oldId);
108 oldTreeId = rw.parseCommit(oldId).getTree();
109 } else {
110 update.setExpectedOldObjectId(ObjectId.zeroId());
111 oldTreeId = ObjectId.zeroId();
112 }
113
114 RefTree tree = rebuild(refDb);
115 b.setTreeId(tree.writeTree(inserter));
116 b.setAuthor(new PersonIdent(db));
117 b.setCommitter(b.getAuthor());
118 if (b.getTreeId().equals(oldTreeId)) {
119 return;
120 }
121
122 update.setNewObjectId(inserter.insert(b));
123 inserter.flush();
124
125 RefUpdate.Result result = update.update(rw);
126 switch (result) {
127 case NEW:
128 case FAST_FORWARD:
129 break;
130 default:
131 throw die(String.format("%s: %s", update.getName(), result));
132 }
133
134 if (enable && !(db.getRefDatabase() instanceof RefTreeDatabase)) {
135 StoredConfig cfg = db.getConfig();
136 cfg.setInt("core", null, "repositoryformatversion", 1);
137 cfg.setString("extensions", null, "refStorage", "reftree");
138 cfg.save();
139 errw.println("Enabled reftree.");
140 errw.flush();
141 }
142 }
143 }
144
145 private RefTree rebuild(RefDatabase refdb) throws IOException {
146 RefTree tree = RefTree.newEmptyTree();
147 List<org.eclipse.jgit.internal.storage.reftree.Command> cmds
148 = new ArrayList<>();
149
150 Ref head = refdb.exactRef(HEAD);
151 if (head != null) {
152 cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command(
153 null,
154 head));
155 }
156
157 for (Ref r : refdb.getRefs()) {
158 if (r.getName().equals(txnCommitted) || r.getName().equals(HEAD)
159 || r.getName().startsWith(txnNamespace)) {
160 continue;
161 }
162 cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command(
163 null,
164 db.getRefDatabase().peel(r)));
165 }
166 tree.apply(cmds);
167 return tree;
168 }
169 }