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