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 @Override
77 protected void run() throws Exception {
78 try (ObjectReader reader = db.newObjectReader();
79 RevWalk rw = new RevWalk(reader);
80 ObjectInserter inserter = db.newObjectInserter()) {
81 RefDatabase refDb = db.getRefDatabase();
82 if (refDb instanceof RefTreeDatabase) {
83 RefTreeDatabase d = (RefTreeDatabase) refDb;
84 refDb = d.getBootstrap();
85 txnNamespace = d.getTxnNamespace();
86 txnCommitted = d.getTxnCommitted();
87 } else {
88 RefTreeDatabase d = new RefTreeDatabase(db, refDb);
89 txnNamespace = d.getTxnNamespace();
90 txnCommitted = d.getTxnCommitted();
91 }
92
93 errw.format("Rebuilding %s from %s",
94 txnCommitted, refDb.getClass().getSimpleName());
95 errw.println();
96 errw.flush();
97
98 CommitBuilder b = new CommitBuilder();
99 Ref ref = refDb.exactRef(txnCommitted);
100 RefUpdate update = refDb.newUpdate(txnCommitted, true);
101 ObjectId oldTreeId;
102
103 if (ref != null && ref.getObjectId() != null) {
104 ObjectId oldId = ref.getObjectId();
105 update.setExpectedOldObjectId(oldId);
106 b.setParentId(oldId);
107 oldTreeId = rw.parseCommit(oldId).getTree();
108 } else {
109 update.setExpectedOldObjectId(ObjectId.zeroId());
110 oldTreeId = ObjectId.zeroId();
111 }
112
113 RefTree tree = rebuild(refDb);
114 b.setTreeId(tree.writeTree(inserter));
115 b.setAuthor(new PersonIdent(db));
116 b.setCommitter(b.getAuthor());
117 if (b.getTreeId().equals(oldTreeId)) {
118 return;
119 }
120
121 update.setNewObjectId(inserter.insert(b));
122 inserter.flush();
123
124 RefUpdate.Result result = update.update(rw);
125 switch (result) {
126 case NEW:
127 case FAST_FORWARD:
128 break;
129 default:
130 throw die(String.format("%s: %s", update.getName(), result));
131 }
132
133 if (enable && !(db.getRefDatabase() instanceof RefTreeDatabase)) {
134 StoredConfig cfg = db.getConfig();
135 cfg.setInt("core", null, "repositoryformatversion", 1);
136 cfg.setString("extensions", null, "refsStorage", "reftree");
137 cfg.save();
138 errw.println("Enabled reftree.");
139 errw.flush();
140 }
141 }
142 }
143
144 private RefTree rebuild(RefDatabase refdb) throws IOException {
145 RefTree tree = RefTree.newEmptyTree();
146 List<org.eclipse.jgit.internal.storage.reftree.Command> cmds
147 = new ArrayList<>();
148
149 Ref head = refdb.exactRef(HEAD);
150 if (head != null) {
151 cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command(
152 null,
153 head));
154 }
155
156 for (Ref r : refdb.getRefs(RefDatabase.ALL).values()) {
157 if (r.getName().equals(txnCommitted) || r.getName().equals(HEAD)
158 || r.getName().startsWith(txnNamespace)) {
159 continue;
160 }
161 cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command(
162 null,
163 db.peel(r)));
164 }
165 tree.apply(cmds);
166 return tree;
167 }
168 }