comparison src/org/tmatesoft/hg/repo/HgChangelog.java @ 366:189dc6dc1c3e

Use exceptions to expose errors reading mercurial data
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 16 Dec 2011 04:43:18 +0100
parents 3572fcb06473
children 2fadf8695f8a
comparison
equal deleted inserted replaced
365:3572fcb06473 366:189dc6dc1c3e
29 import java.util.List; 29 import java.util.List;
30 import java.util.Locale; 30 import java.util.Locale;
31 import java.util.Map; 31 import java.util.Map;
32 import java.util.TimeZone; 32 import java.util.TimeZone;
33 33
34 import org.tmatesoft.hg.core.HgBadStateException; 34 import org.tmatesoft.hg.core.HgBadArgumentException;
35 import org.tmatesoft.hg.core.HgException;
35 import org.tmatesoft.hg.core.HgInvalidControlFileException; 36 import org.tmatesoft.hg.core.HgInvalidControlFileException;
36 import org.tmatesoft.hg.core.HgInvalidRevisionException; 37 import org.tmatesoft.hg.core.HgInvalidRevisionException;
37 import org.tmatesoft.hg.core.Nodeid; 38 import org.tmatesoft.hg.core.Nodeid;
38 import org.tmatesoft.hg.internal.DataAccess; 39 import org.tmatesoft.hg.internal.DataAccess;
39 import org.tmatesoft.hg.internal.IterateControlMediator; 40 import org.tmatesoft.hg.internal.IterateControlMediator;
54 55
55 /* package-local */HgChangelog(HgRepository hgRepo, RevlogStream content) { 56 /* package-local */HgChangelog(HgRepository hgRepo, RevlogStream content) {
56 super(hgRepo, content); 57 super(hgRepo, content);
57 } 58 }
58 59
59 public void all(final HgChangelog.Inspector inspector) throws HgInvalidRevisionException { 60 public void all(final HgChangelog.Inspector inspector) throws HgInvalidRevisionException, HgInvalidControlFileException {
60 range(0, getLastRevision(), inspector); 61 range(0, getLastRevision(), inspector);
61 } 62 }
62 63
63 public void range(int start, int end, final HgChangelog.Inspector inspector) throws HgInvalidRevisionException { 64 public void range(int start, int end, final HgChangelog.Inspector inspector) throws HgInvalidRevisionException, HgInvalidControlFileException {
64 if (inspector == null) { 65 if (inspector == null) {
65 throw new IllegalArgumentException(); 66 throw new IllegalArgumentException();
66 } 67 }
67 content.iterate(start, end, true, new RawCsetParser(inspector)); 68 content.iterate(start, end, true, new RawCsetParser(inspector));
68 } 69 }
69 70
70 public List<RawChangeset> range(int start, int end) throws HgInvalidRevisionException { 71 public List<RawChangeset> range(int start, int end) throws HgInvalidRevisionException, HgInvalidControlFileException {
71 final RawCsetCollector c = new RawCsetCollector(end - start + 1); 72 final RawCsetCollector c = new RawCsetCollector(end - start + 1);
72 range(start, end, c); 73 range(start, end, c);
73 return c.result; 74 return c.result;
74 } 75 }
75 76
77 * Access individual revisions. Note, regardless of supplied revision order, inspector gets 78 * Access individual revisions. Note, regardless of supplied revision order, inspector gets
78 * changesets strictly in the order they are in the changelog. 79 * changesets strictly in the order they are in the changelog.
79 * @param inspector callback to get changesets 80 * @param inspector callback to get changesets
80 * @param revisions revisions to read, unrestricted ordering. 81 * @param revisions revisions to read, unrestricted ordering.
81 */ 82 */
82 public void range(final HgChangelog.Inspector inspector, final int... revisions) throws HgInvalidRevisionException { 83 public void range(final HgChangelog.Inspector inspector, final int... revisions) throws HgInvalidRevisionException, HgInvalidControlFileException {
83 Arrays.sort(revisions); 84 Arrays.sort(revisions);
84 rangeInternal(inspector, revisions); 85 rangeInternal(inspector, revisions);
85 } 86 }
86 87
87 /** 88 /**
88 * Friends-only version of {@link #range(Inspector, int...)}, when callers know array is sorted 89 * Friends-only version of {@link #range(Inspector, int...)}, when callers know array is sorted
89 */ 90 */
90 /*package-local*/ void rangeInternal(HgChangelog.Inspector inspector, int[] sortedRevisions) throws HgInvalidRevisionException { 91 /*package-local*/ void rangeInternal(HgChangelog.Inspector inspector, int[] sortedRevisions) throws HgInvalidRevisionException, HgInvalidControlFileException {
91 if (sortedRevisions == null || sortedRevisions.length == 0) { 92 if (sortedRevisions == null || sortedRevisions.length == 0) {
92 return; 93 return;
93 } 94 }
94 if (inspector == null) { 95 if (inspector == null) {
95 throw new IllegalArgumentException(); 96 throw new IllegalArgumentException();
236 } catch (CloneNotSupportedException ex) { 237 } catch (CloneNotSupportedException ex) {
237 throw new InternalError(ex.toString()); 238 throw new InternalError(ex.toString());
238 } 239 }
239 } 240 }
240 241
241 /*package*/ static RawChangeset parse(DataAccess da) throws IOException { 242 /*package*/ static RawChangeset parse(DataAccess da) throws IOException, HgBadArgumentException {
242 byte[] data = da.byteArray(); 243 byte[] data = da.byteArray();
243 RawChangeset rv = new RawChangeset(); 244 RawChangeset rv = new RawChangeset();
244 rv.init(data, 0, data.length, null); 245 rv.init(data, 0, data.length, null);
245 return rv; 246 return rv;
246 } 247 }
247 248
248 // @param usersPool - it's likely user names get repeated again and again throughout repository. can be null 249 // @param usersPool - it's likely user names get repeated again and again throughout repository. can be null
249 // FIXME throws "Error reading changeset data" 250 // FIXME replace HgBadArgumentException with HgInvalidDataFormatException or HgInvalidControlFileException
250 /* package-local */void init(byte[] data, int offset, int length, Pool<String> usersPool) { 251 /* package-local */void init(byte[] data, int offset, int length, Pool<String> usersPool) throws HgBadArgumentException {
251 final int bufferEndIndex = offset + length; 252 final int bufferEndIndex = offset + length;
252 final byte lineBreak = (byte) '\n'; 253 final byte lineBreak = (byte) '\n';
253 int breakIndex1 = indexOf(data, lineBreak, offset, bufferEndIndex); 254 int breakIndex1 = indexOf(data, lineBreak, offset, bufferEndIndex);
254 if (breakIndex1 == -1) { 255 if (breakIndex1 == -1) {
255 throw new IllegalArgumentException("Bad Changeset data"); 256 throw new HgBadArgumentException("Bad Changeset data", null);
256 } 257 }
257 Nodeid _nodeid = Nodeid.fromAscii(data, 0, breakIndex1); 258 Nodeid _nodeid = Nodeid.fromAscii(data, 0, breakIndex1);
258 int breakIndex2 = indexOf(data, lineBreak, breakIndex1 + 1, bufferEndIndex); 259 int breakIndex2 = indexOf(data, lineBreak, breakIndex1 + 1, bufferEndIndex);
259 if (breakIndex2 == -1) { 260 if (breakIndex2 == -1) {
260 throw new IllegalArgumentException("Bad Changeset data"); 261 throw new HgBadArgumentException("Bad Changeset data", null);
261 } 262 }
262 String _user = new String(data, breakIndex1 + 1, breakIndex2 - breakIndex1 - 1); 263 String _user = new String(data, breakIndex1 + 1, breakIndex2 - breakIndex1 - 1);
263 if (usersPool != null) { 264 if (usersPool != null) {
264 _user = usersPool.unify(_user); 265 _user = usersPool.unify(_user);
265 } 266 }
266 int breakIndex3 = indexOf(data, lineBreak, breakIndex2 + 1, bufferEndIndex); 267 int breakIndex3 = indexOf(data, lineBreak, breakIndex2 + 1, bufferEndIndex);
267 if (breakIndex3 == -1) { 268 if (breakIndex3 == -1) {
268 throw new IllegalArgumentException("Bad Changeset data"); 269 throw new HgBadArgumentException("Bad Changeset data", null);
269 } 270 }
270 String _timeString = new String(data, breakIndex2 + 1, breakIndex3 - breakIndex2 - 1); 271 String _timeString = new String(data, breakIndex2 + 1, breakIndex3 - breakIndex2 - 1);
271 int space1 = _timeString.indexOf(' '); 272 int space1 = _timeString.indexOf(' ');
272 if (space1 == -1) { 273 if (space1 == -1) {
273 throw new IllegalArgumentException("Bad Changeset data"); 274 throw new HgBadArgumentException(String.format("Bad Changeset data: %s in [%d..%d]", "time string", breakIndex2+1, breakIndex3), null);
274 } 275 }
275 int space2 = _timeString.indexOf(' ', space1 + 1); 276 int space2 = _timeString.indexOf(' ', space1 + 1);
276 if (space2 == -1) { 277 if (space2 == -1) {
277 space2 = _timeString.length(); 278 space2 = _timeString.length();
278 } 279 }
314 } else { 315 } else {
315 breakIndex4 = indexOf(data, lineBreak, lastStart, bufferEndIndex); 316 breakIndex4 = indexOf(data, lineBreak, lastStart, bufferEndIndex);
316 } 317 }
317 } 318 }
318 if (breakIndex4 == -1 || breakIndex4 >= bufferEndIndex) { 319 if (breakIndex4 == -1 || breakIndex4 >= bufferEndIndex) {
319 throw new IllegalArgumentException("Bad Changeset data"); 320 throw new HgBadArgumentException("Bad Changeset data", null);
320 } 321 }
321 } else { 322 } else {
322 breakIndex4--; 323 breakIndex4--;
323 } 324 }
324 String _comment; 325 String _comment;
325 try { 326 try {
326 _comment = new String(data, breakIndex4 + 2, bufferEndIndex - breakIndex4 - 2, "UTF-8"); 327 _comment = new String(data, breakIndex4 + 2, bufferEndIndex - breakIndex4 - 2, "UTF-8");
327 // FIXME respect ui.fallbackencoding and try to decode if set 328 // FIXME respect ui.fallbackencoding and try to decode if set
328 } catch (UnsupportedEncodingException ex) { 329 } catch (UnsupportedEncodingException ex) {
329 _comment = ""; 330 _comment = "";
330 throw new IllegalStateException("Could hardly happen"); 331 // Could hardly happen
332 throw new HgBadArgumentException("Bad Changeset data", ex);
331 } 333 }
332 // change this instance at once, don't leave it partially changes in case of error 334 // change this instance at once, don't leave it partially changes in case of error
333 this.manifest = _nodeid; 335 this.manifest = _nodeid;
334 this.user = _user; 336 this.user = _user;
335 this.time = _time; 337 this.time = _time;
382 inspector = delegate; 384 inspector = delegate;
383 usersPool = new Pool<String>(); 385 usersPool = new Pool<String>();
384 progressHelper = ProgressSupport.Factory.get(delegate); 386 progressHelper = ProgressSupport.Factory.get(delegate);
385 } 387 }
386 388
387 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) { 389 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) throws HgException {
388 try { 390 try {
389 byte[] data = da.byteArray(); 391 byte[] data = da.byteArray();
390 cset.init(data, 0, data.length, usersPool); 392 cset.init(data, 0, data.length, usersPool);
391 // XXX there's no guarantee for Changeset.Callback that distinct instance comes each time, consider instance reuse 393 // XXX there's no guarantee for Changeset.Callback that distinct instance comes each time, consider instance reuse
392 inspector.next(revisionNumber, Nodeid.fromBinary(nodeid, 0), cset); 394 inspector.next(revisionNumber, Nodeid.fromBinary(nodeid, 0), cset);
393 progressHelper.worked(1); 395 progressHelper.worked(1);
394 } catch (Exception ex) { 396 } catch (IOException ex) {
395 throw new HgBadStateException(ex); // FIXME exception handling 397 throw new HgException(ex); // XXX need better exception, perhaps smth like HgChangelogException (extends HgInvalidControlFileException)
396 } 398 }
397 if (iterateControl != null) { 399 if (iterateControl != null) {
398 iterateControl.checkCancelled(); 400 iterateControl.checkCancelled();
399 } 401 }
400 } 402 }