1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.pgm.debug;
12
13 import static org.eclipse.jgit.lib.Constants.HEAD;
14
15 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.List;
18
19 import org.eclipse.jgit.internal.storage.reftree.RefTree;
20 import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase;
21 import org.eclipse.jgit.lib.CommitBuilder;
22 import org.eclipse.jgit.lib.ConfigConstants;
23 import org.eclipse.jgit.lib.ObjectId;
24 import org.eclipse.jgit.lib.ObjectInserter;
25 import org.eclipse.jgit.lib.ObjectReader;
26 import org.eclipse.jgit.lib.PersonIdent;
27 import org.eclipse.jgit.lib.Ref;
28 import org.eclipse.jgit.lib.RefDatabase;
29 import org.eclipse.jgit.lib.RefUpdate;
30 import org.eclipse.jgit.lib.StoredConfig;
31 import org.eclipse.jgit.pgm.Command;
32 import org.eclipse.jgit.pgm.TextBuiltin;
33 import org.eclipse.jgit.revwalk.RevWalk;
34 import org.kohsuke.args4j.Option;
35
36 @Command(usage = "usage_RebuildRefTree")
37 class RebuildRefTree extends TextBuiltin {
38 @Option(name = "--enable", usage = "usage_RebuildRefTreeEnable")
39 boolean enable;
40
41 private String txnNamespace;
42 private String txnCommitted;
43
44
45 @Override
46 protected void run() throws Exception {
47 try (ObjectReader reader = db.newObjectReader();
48 RevWalk rw = new RevWalk(reader);
49 ObjectInserter inserter = db.newObjectInserter()) {
50 RefDatabase refDb = db.getRefDatabase();
51 if (refDb instanceof RefTreeDatabase) {
52 RefTreeDatabase d = (RefTreeDatabase) refDb;
53 refDb = d.getBootstrap();
54 txnNamespace = d.getTxnNamespace();
55 txnCommitted = d.getTxnCommitted();
56 } else {
57 RefTreeDatabase d = new RefTreeDatabase(db, refDb);
58 txnNamespace = d.getTxnNamespace();
59 txnCommitted = d.getTxnCommitted();
60 }
61
62 errw.format("Rebuilding %s from %s",
63 txnCommitted, refDb.getClass().getSimpleName());
64 errw.println();
65 errw.flush();
66
67 CommitBuilder b = new CommitBuilder();
68 Ref ref = refDb.exactRef(txnCommitted);
69 RefUpdate update = refDb.newUpdate(txnCommitted, true);
70 ObjectId oldTreeId;
71
72 if (ref != null && ref.getObjectId() != null) {
73 ObjectId oldId = ref.getObjectId();
74 update.setExpectedOldObjectId(oldId);
75 b.setParentId(oldId);
76 oldTreeId = rw.parseCommit(oldId).getTree();
77 } else {
78 update.setExpectedOldObjectId(ObjectId.zeroId());
79 oldTreeId = ObjectId.zeroId();
80 }
81
82 RefTree tree = rebuild(refDb);
83 b.setTreeId(tree.writeTree(inserter));
84 b.setAuthor(new PersonIdent(db));
85 b.setCommitter(b.getAuthor());
86 if (b.getTreeId().equals(oldTreeId)) {
87 return;
88 }
89
90 update.setNewObjectId(inserter.insert(b));
91 inserter.flush();
92
93 RefUpdate.Result result = update.update(rw);
94 switch (result) {
95 case NEW:
96 case FAST_FORWARD:
97 break;
98 default:
99 throw die(String.format("%s: %s", update.getName(), result));
100 }
101
102 if (enable && !(db.getRefDatabase() instanceof RefTreeDatabase)) {
103 StoredConfig cfg = db.getConfig();
104 cfg.setInt(ConfigConstants.CONFIG_CORE_SECTION, null,
105 ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 1);
106 cfg.setString(ConfigConstants.CONFIG_EXTENSIONS_SECTION, null,
107 ConfigConstants.CONFIG_KEY_REFSTORAGE,
108 ConfigConstants.CONFIG_REFSTORAGE_REFTREE);
109 cfg.save();
110 errw.println("Enabled reftree.");
111 errw.flush();
112 }
113 }
114 }
115
116 private RefTree rebuild(RefDatabase refdb) throws IOException {
117 RefTree tree = RefTree.newEmptyTree();
118 List<org.eclipse.jgit.internal.storage.reftree.Command> cmds
119 = new ArrayList<>();
120
121 Ref head = refdb.exactRef(HEAD);
122 if (head != null) {
123 cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command(
124 null,
125 head));
126 }
127
128 for (Ref r : refdb.getRefs()) {
129 if (r.getName().equals(txnCommitted) || r.getName().equals(HEAD)
130 || r.getName().startsWith(txnNamespace)) {
131 continue;
132 }
133 cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command(
134 null,
135 db.getRefDatabase().peel(r)));
136 }
137 tree.apply(cmds);
138 return tree;
139 }
140 }