Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/HgManifest.java @ 326:d42a45a2c9d6
Alternative tag collection approach for a file history
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Tue, 04 Oct 2011 06:28:01 +0200 |
parents | 283b294d1079 |
children | 5f9073eabf06 |
comparison
equal
deleted
inserted
replaced
325:f05c8b1f08c4 | 326:d42a45a2c9d6 |
---|---|
20 | 20 |
21 import java.io.ByteArrayOutputStream; | 21 import java.io.ByteArrayOutputStream; |
22 import java.io.IOException; | 22 import java.io.IOException; |
23 import java.util.ArrayList; | 23 import java.util.ArrayList; |
24 import java.util.Arrays; | 24 import java.util.Arrays; |
25 import java.util.HashMap; | |
26 import java.util.Map; | |
25 | 27 |
26 import org.tmatesoft.hg.core.HgBadStateException; | 28 import org.tmatesoft.hg.core.HgBadStateException; |
27 import org.tmatesoft.hg.core.Nodeid; | 29 import org.tmatesoft.hg.core.Nodeid; |
28 import org.tmatesoft.hg.internal.DataAccess; | 30 import org.tmatesoft.hg.internal.DataAccess; |
29 import org.tmatesoft.hg.internal.DigestHelper; | 31 import org.tmatesoft.hg.internal.DigestHelper; |
122 */ | 124 */ |
123 public void walk(final Inspector inspector, int... localRevisions) { | 125 public void walk(final Inspector inspector, int... localRevisions) { |
124 if (inspector == null || localRevisions == null) { | 126 if (inspector == null || localRevisions == null) { |
125 throw new IllegalArgumentException(); | 127 throw new IllegalArgumentException(); |
126 } | 128 } |
127 int[] manifestLocalRevs = new int[localRevisions.length]; | 129 int[] localManifestRevs = toLocalManifestRevisions(localRevisions); |
128 boolean needsSort = false; | 130 content.iterate(localManifestRevs, true, new ManifestParser(inspector)); |
129 for (int i = 0; i < localRevisions.length; i++) { | |
130 final int manifestLocalRev = fromChangelog(localRevisions[i]); | |
131 manifestLocalRevs[i] = manifestLocalRev; | |
132 if (i > 0 && manifestLocalRevs[i-1] > manifestLocalRev) { | |
133 needsSort = true; | |
134 } | |
135 } | |
136 if (needsSort) { | |
137 Arrays.sort(manifestLocalRevs); | |
138 } | |
139 content.iterate(manifestLocalRevs, true, new ManifestParser(inspector)); | |
140 } | 131 } |
141 | 132 |
142 // manifest revision number that corresponds to the given changeset | 133 // manifest revision number that corresponds to the given changeset |
143 /*package-local*/ int fromChangelog(int revisionNumber) { | 134 /*package-local*/ int fromChangelog(int revisionNumber) { |
144 if (HgInternals.wrongLocalRevision(revisionNumber)) { | 135 if (HgInternals.wrongLocalRevision(revisionNumber)) { |
156 } | 147 } |
157 | 148 |
158 /** | 149 /** |
159 * Extracts file revision as it was known at the time of given changeset. | 150 * Extracts file revision as it was known at the time of given changeset. |
160 * | 151 * |
161 * @param revisionNumber local changeset index | 152 * @param localChangelogRevision local changeset index |
162 * @param file path to file in question | 153 * @param file path to file in question |
163 * @return file revision or <code>null</code> if manifest at specified revision doesn't list such file | 154 * @return file revision or <code>null</code> if manifest at specified revision doesn't list such file |
164 */ | 155 */ |
165 @Experimental(reason="Perhaps, HgDataFile shall own this method") | 156 @Experimental(reason="Perhaps, HgDataFile shall own this method, or get a delegate?") |
166 public Nodeid getFileRevision(int revisionNumber, final Path file) { | 157 public Nodeid getFileRevision(int localChangelogRevision, final Path file) { |
167 int rev = fromChangelog(revisionNumber); | 158 return getFileRevisions(file, localChangelogRevision).get(localChangelogRevision); |
168 final Nodeid[] rv = new Nodeid[] { null }; | 159 } |
169 content.iterate(rev, rev, true, new RevlogStream.Inspector() { | 160 |
161 // XXX package-local, IntMap, and HgDataFile getFileRevisionAt(int... localChangelogRevisions) | |
162 @Experimental(reason="@see #getFileRevision") | |
163 public Map<Integer, Nodeid> getFileRevisions(final Path file, int... localChangelogRevisions) { | |
164 // FIXME need tests | |
165 int[] localManifestRevisions = toLocalManifestRevisions(localChangelogRevisions); | |
166 final HashMap<Integer,Nodeid> rv = new HashMap<Integer, Nodeid>(localChangelogRevisions.length); | |
167 content.iterate(localManifestRevisions, true, new RevlogStream.Inspector() { | |
170 | 168 |
171 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { | 169 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { |
172 ByteArrayOutputStream bos = new ByteArrayOutputStream(); | 170 ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
173 try { | 171 try { |
174 byte b; | 172 byte b; |
179 String fname = new String(bos.toByteArray()); | 177 String fname = new String(bos.toByteArray()); |
180 bos.reset(); | 178 bos.reset(); |
181 if (file.toString().equals(fname)) { | 179 if (file.toString().equals(fname)) { |
182 byte[] nid = new byte[40]; | 180 byte[] nid = new byte[40]; |
183 data.readBytes(nid, 0, 40); | 181 data.readBytes(nid, 0, 40); |
184 rv[0] = Nodeid.fromAscii(nid, 0, 40); | 182 rv.put(linkRevision, Nodeid.fromAscii(nid, 0, 40)); |
185 break; | 183 break; |
184 } else { | |
185 data.skip(40); | |
186 } | 186 } |
187 // else skip to the end of line | 187 // else skip to the end of line |
188 while (!data.isEmpty() && (b = data.readByte()) != '\n') | 188 while (!data.isEmpty() && (b = data.readByte()) != '\n') |
189 ; | 189 ; |
190 } | 190 } |
192 } catch (IOException ex) { | 192 } catch (IOException ex) { |
193 throw new HgBadStateException(ex); | 193 throw new HgBadStateException(ex); |
194 } | 194 } |
195 } | 195 } |
196 }); | 196 }); |
197 return rv[0]; | 197 return rv; |
198 } | 198 } |
199 | 199 |
200 | |
201 private int[] toLocalManifestRevisions(int[] localChangelogRevisions) { | |
202 int[] localManifestRevs = new int[localChangelogRevisions.length]; | |
203 boolean needsSort = false; | |
204 for (int i = 0; i < localChangelogRevisions.length; i++) { | |
205 final int manifestLocalRev = fromChangelog(localChangelogRevisions[i]); | |
206 localManifestRevs[i] = manifestLocalRev; | |
207 if (i > 0 && localManifestRevs[i-1] > manifestLocalRev) { | |
208 needsSort = true; | |
209 } | |
210 } | |
211 if (needsSort) { | |
212 Arrays.sort(localManifestRevs); | |
213 } | |
214 return localManifestRevs; | |
215 } | |
216 | |
200 public interface Inspector { | 217 public interface Inspector { |
201 boolean begin(int mainfestRevision, Nodeid nid, int changelogRevision); | 218 boolean begin(int mainfestRevision, Nodeid nid, int changelogRevision); |
202 /** | 219 /** |
203 * @deprecated switch to {@link Inspector2#next(Nodeid, Path, Flags)} | 220 * @deprecated switch to {@link Inspector2#next(Nodeid, Path, Flags)} |
204 */ | 221 */ |
209 | 226 |
210 @Experimental(reason="Explore Path alternative for filenames and enum for flags") | 227 @Experimental(reason="Explore Path alternative for filenames and enum for flags") |
211 public interface Inspector2 extends Inspector { | 228 public interface Inspector2 extends Inspector { |
212 boolean next(Nodeid nid, Path fname, Flags flags); | 229 boolean next(Nodeid nid, Path fname, Flags flags); |
213 } | 230 } |
214 | 231 |
215 /** | 232 /** |
216 * When Pool uses Strings directly, | 233 * When Pool uses Strings directly, |
217 * ManifestParser creates new String instance with new char[] value, and does byte->char conversion. | 234 * ManifestParser creates new String instance with new char[] value, and does byte->char conversion. |
218 * For cpython repo, walk(0..10k), there are over 16 million filenames, of them only 3020 unique. | 235 * For cpython repo, walk(0..10k), there are over 16 million filenames, of them only 3020 unique. |
219 * This means there are 15.9 million useless char[] instances and byte->char conversions | 236 * This means there are 15.9 million useless char[] instances and byte->char conversions |