Mercurial > jhg
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 } |