comparison src/org/tmatesoft/hg/repo/HgManifest.java @ 218:047b1dec7a04

Issue 7: Correctly handle manifest and changelog with different number of (or non-matching) revisions
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 17 May 2011 03:42:33 +0200
parents e2115da4cf6a
children 8de327242aa0
comparison
equal deleted inserted replaced
217:e39cf474ef94 218:047b1dec7a04
14 * the terms of a license other than GNU General Public License 14 * the terms of a license other than GNU General Public License
15 * contact TMate Software at support@hg4j.com 15 * contact TMate Software at support@hg4j.com
16 */ 16 */
17 package org.tmatesoft.hg.repo; 17 package org.tmatesoft.hg.repo;
18 18
19 import static org.tmatesoft.hg.repo.HgRepository.TIP;
20
19 import java.io.IOException; 21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Arrays;
20 24
21 import org.tmatesoft.hg.core.HgBadStateException; 25 import org.tmatesoft.hg.core.HgBadStateException;
22 import org.tmatesoft.hg.core.Nodeid; 26 import org.tmatesoft.hg.core.Nodeid;
23 import org.tmatesoft.hg.internal.DataAccess; 27 import org.tmatesoft.hg.internal.DataAccess;
28 import org.tmatesoft.hg.internal.Lifecycle;
24 import org.tmatesoft.hg.internal.Pool; 29 import org.tmatesoft.hg.internal.Pool;
25 import org.tmatesoft.hg.internal.RevlogStream; 30 import org.tmatesoft.hg.internal.RevlogStream;
26 31
27 32
28 /** 33 /**
29 * 34 *
30 * @author Artem Tikhomirov 35 * @author Artem Tikhomirov
31 * @author TMate Software Ltd. 36 * @author TMate Software Ltd.
32 */ 37 */
33 public class HgManifest extends Revlog { 38 public class HgManifest extends Revlog {
39 private RevisionMapper revisionMap;
34 40
35 /*package-local*/ HgManifest(HgRepository hgRepo, RevlogStream content) { 41 /*package-local*/ HgManifest(HgRepository hgRepo, RevlogStream content) {
36 super(hgRepo, content); 42 super(hgRepo, content);
37 } 43 }
38 44
45 /**
46 *
47 * @param start changelog (not manifest!) revision to begin with
48 * @param end changelog (not manifest!) revision to stop, inclusive.
49 * @param inspector can't be <code>null</code>
50 */
39 public void walk(int start, int end, final Inspector inspector) { 51 public void walk(int start, int end, final Inspector inspector) {
40 if (inspector == null) { 52 if (inspector == null) {
41 throw new IllegalArgumentException(); 53 throw new IllegalArgumentException();
42 } 54 }
43 content.iterate(start, end, true, new ManifestParser(inspector)); 55 int start0 = fromChangelog(start);
56 int end0 = fromChangelog(end);
57 content.iterate(start0, end0, true, new ManifestParser(inspector));
44 } 58 }
45 59
60 /*package-local*/ int fromChangelog(int revisionNumber) {
61 if (HgInternals.wrongLocalRevision(revisionNumber)) {
62 throw new IllegalArgumentException(String.valueOf(revisionNumber));
63 }
64 if (revisionMap == null) {
65 revisionMap = new RevisionMapper(getRepo());
66 content.iterate(0, TIP, false, revisionMap);
67 }
68 return revisionMap.at(revisionNumber);
69 }
70
46 public interface Inspector { 71 public interface Inspector {
47 boolean begin(int revision, Nodeid nid); 72 boolean begin(int revision, Nodeid nid);
48 boolean next(Nodeid nid, String fname, String flags); 73 boolean next(Nodeid nid, String fname, String flags);
49 boolean end(int revision); 74 boolean end(int revision);
50 } 75 }
101 } catch (IOException ex) { 126 } catch (IOException ex) {
102 throw new HgBadStateException(ex); 127 throw new HgBadStateException(ex);
103 } 128 }
104 } 129 }
105 } 130 }
131
132 private static class RevisionMapper implements RevlogStream.Inspector, Lifecycle {
133
134 private final int changelogRevisions;
135 private int[] changelog2manifest;
136 private final HgRepository repo;
137
138 public RevisionMapper(HgRepository hgRepo) {
139 repo = hgRepo;
140 changelogRevisions = repo.getChangelog().getRevisionCount();
141 }
142
143 public int at(int revisionNumber) {
144 if (changelog2manifest != null) {
145 return changelog2manifest[revisionNumber];
146 }
147 return revisionNumber;
148 }
149
150 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) {
151 if (changelog2manifest != null) {
152 changelog2manifest[linkRevision] = revisionNumber;
153 } else {
154 if (revisionNumber != linkRevision) {
155 changelog2manifest = new int[changelogRevisions];
156 Arrays.fill(changelog2manifest, -1);
157 for (int i = 0; i < revisionNumber; changelog2manifest[i] = i, i++)
158 ;
159 changelog2manifest[linkRevision] = revisionNumber;
160 }
161 }
162 }
163
164 public void start(int count, Callback callback, Object token) {
165 if (count != changelogRevisions) {
166 assert count < changelogRevisions; // no idea what to do if manifest has more revisions than changelog
167 // the way how manifest may contain more revisions than changelog, as I can imagine, is a result of
168 // some kind of an import tool (e.g. from SVN or CVS), that creates manifest and changelog independently.
169 // Note, it's pure guess, I didn't see such repository yet (although the way manifest revisions
170 // in cpython repo are numbered makes me think aforementioned way)
171 changelog2manifest = new int[changelogRevisions];
172 Arrays.fill(changelog2manifest, -1);
173 }
174 }
175
176 public void finish(Object token) {
177 if (changelog2manifest == null) {
178 return;
179 }
180 // I assume there'd be not too many revisions we don't know manifest of
181 ArrayList<Integer> undefinedChangelogRevision = new ArrayList<Integer>();
182 for (int i = 0; i < changelog2manifest.length; i++) {
183 if (changelog2manifest[i] == -1) {
184 undefinedChangelogRevision.add(i);
185 }
186 }
187 for (int u : undefinedChangelogRevision) {
188 Nodeid manifest = repo.getChangelog().range(u, u).get(0).manifest();
189 // FIXME calculate those missing effectively (e.g. cache and sort nodeids to spead lookup
190 // right away in the #next (may refactor ParentWalker's sequential and sorted into dedicated helper and reuse here)
191 changelog2manifest[u] = repo.getManifest().getLocalRevision(manifest);
192 }
193 }
194 }
106 } 195 }