Mercurial > hg4j
comparison src/org/tmatesoft/hg/core/HgLogCommand.java @ 423:9c9c442b5f2e
Major refactoring of exception handling. Low-level API uses RuntimeExceptions, while checked are left for higher level
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Fri, 23 Mar 2012 22:51:18 +0100 |
| parents | 7f136a3fa671 |
| children | 6437d261048a |
comparison
equal
deleted
inserted
replaced
| 422:5d1cc7366d04 | 423:9c9c442b5f2e |
|---|---|
| 33 import org.tmatesoft.hg.internal.IntVector; | 33 import org.tmatesoft.hg.internal.IntVector; |
| 34 import org.tmatesoft.hg.repo.HgChangelog; | 34 import org.tmatesoft.hg.repo.HgChangelog; |
| 35 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; | 35 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; |
| 36 import org.tmatesoft.hg.repo.HgDataFile; | 36 import org.tmatesoft.hg.repo.HgDataFile; |
| 37 import org.tmatesoft.hg.repo.HgInternals; | 37 import org.tmatesoft.hg.repo.HgInternals; |
| 38 import org.tmatesoft.hg.repo.HgInvalidControlFileException; | |
| 39 import org.tmatesoft.hg.repo.HgInvalidRevisionException; | |
| 40 import org.tmatesoft.hg.repo.HgInvalidStateException; | |
| 38 import org.tmatesoft.hg.repo.HgRepository; | 41 import org.tmatesoft.hg.repo.HgRepository; |
| 42 import org.tmatesoft.hg.repo.HgRuntimeException; | |
| 39 import org.tmatesoft.hg.repo.HgStatusCollector; | 43 import org.tmatesoft.hg.repo.HgStatusCollector; |
| 40 import org.tmatesoft.hg.util.CancelSupport; | 44 import org.tmatesoft.hg.util.CancelSupport; |
| 41 import org.tmatesoft.hg.util.CancelledException; | 45 import org.tmatesoft.hg.util.CancelledException; |
| 42 import org.tmatesoft.hg.util.Pair; | 46 import org.tmatesoft.hg.util.Pair; |
| 43 import org.tmatesoft.hg.util.Path; | 47 import org.tmatesoft.hg.util.Path; |
| 183 return file(Path.create(repo.getToRepoPathHelper().rewrite(file)), followCopyRename); | 187 return file(Path.create(repo.getToRepoPathHelper().rewrite(file)), followCopyRename); |
| 184 } | 188 } |
| 185 | 189 |
| 186 /** | 190 /** |
| 187 * Similar to {@link #execute(HgChangesetHandler)}, collects and return result as a list. | 191 * Similar to {@link #execute(HgChangesetHandler)}, collects and return result as a list. |
| 192 * @throws HgException FIXME EXCEPTIONS | |
| 188 */ | 193 */ |
| 189 public List<HgChangeset> execute() throws HgException { | 194 public List<HgChangeset> execute() throws HgException { |
| 190 CollectHandler collector = new CollectHandler(); | 195 CollectHandler collector = new CollectHandler(); |
| 191 try { | 196 try { |
| 192 execute(collector); | 197 execute(collector); |
| 198 } catch (HgCallbackTargetException ex) { | |
| 199 // see below for CanceledException | |
| 200 HgInvalidStateException t = new HgInvalidStateException("Internal error"); | |
| 201 t.initCause(ex); | |
| 202 throw t; | |
| 193 } catch (CancelledException ex) { | 203 } catch (CancelledException ex) { |
| 194 // can't happen as long as our CollectHandler doesn't throw any exception | 204 // can't happen as long as our CollectHandler doesn't throw any exception |
| 195 throw new HgBadStateException(ex); | 205 HgInvalidStateException t = new HgInvalidStateException("Internal error"); |
| 206 t.initCause(ex); | |
| 207 throw t; | |
| 196 } | 208 } |
| 197 return collector.getChanges(); | 209 return collector.getChanges(); |
| 198 } | 210 } |
| 199 | 211 |
| 200 /** | 212 /** |
| 201 * Iterate over range of changesets configured in the command. | 213 * Iterate over range of changesets configured in the command. |
| 202 * | 214 * |
| 203 * @param handler callback to process changesets. | 215 * @param handler callback to process changesets. |
| 204 * @throws HgCallbackTargetException to re-throw exception from the handler | 216 * @throws HgCallbackTargetException wrapper for any exception user callback code may produce |
| 205 * @throws HgInvalidControlFileException if access to revlog index/data entry failed | 217 * @throws HgInvalidControlFileException if access to revlog index/data entry failed |
| 206 * @throws HgException in case of some other library issue | 218 * @throws HgException in case of some other library issue |
| 207 * @throws CancelledException if execution of the command was cancelled | 219 * @throws CancelledException if execution of the command was cancelled |
| 208 * @throws IllegalArgumentException when inspector argument is null | 220 * @throws IllegalArgumentException when inspector argument is null |
| 209 * @throws ConcurrentModificationException if this log command instance is already running | 221 * @throws ConcurrentModificationException if this log command instance is already running |
| 235 // even if we do not follow history, report file rename | 247 // even if we do not follow history, report file rename |
| 236 do { | 248 do { |
| 237 if (handler instanceof FileHistoryHandler) { | 249 if (handler instanceof FileHistoryHandler) { |
| 238 HgFileRevision src = new HgFileRevision(repo, fileNode.getCopySourceRevision(), null, fileNode.getCopySourceName()); | 250 HgFileRevision src = new HgFileRevision(repo, fileNode.getCopySourceRevision(), null, fileNode.getCopySourceName()); |
| 239 HgFileRevision dst = new HgFileRevision(repo, fileNode.getRevision(0), null, fileNode.getPath(), src.getPath()); | 251 HgFileRevision dst = new HgFileRevision(repo, fileNode.getRevision(0), null, fileNode.getPath(), src.getPath()); |
| 240 try { | 252 ((FileHistoryHandler) handler).copy(src, dst); |
| 241 ((FileHistoryHandler) handler).copy(src, dst); | |
| 242 } catch (HgCallbackTargetException.Wrap ex) { | |
| 243 throw new HgCallbackTargetException(ex).setRevision(fileNode.getCopySourceRevision()).setFileName(fileNode.getCopySourceName()); | |
| 244 } | |
| 245 } | 253 } |
| 246 if (limit > 0 && count >= limit) { | 254 if (limit > 0 && count >= limit) { |
| 247 // if limit reach, follow is useless. | 255 // if limit reach, follow is useless. |
| 248 break; | 256 break; |
| 249 } | 257 } |
| 329 progressHelper.worked(1); | 337 progressHelper.worked(1); |
| 330 ph2 = new ProgressSupport.Sub(progressHelper, 2); | 338 ph2 = new ProgressSupport.Sub(progressHelper, 2); |
| 331 } else { | 339 } else { |
| 332 ph2 = new ProgressSupport.Sub(progressHelper, 3); | 340 ph2 = new ProgressSupport.Sub(progressHelper, 3); |
| 333 } | 341 } |
| 334 try { | 342 ph2.start(completeHistory.length); |
| 335 ph2.start(completeHistory.length); | 343 // XXX shall sort completeHistory according to changeset numbers? |
| 336 // XXX shall sort completeHistory according to changeset numbers? | 344 for (int i = 0; i < completeHistory.length; i++ ) { |
| 337 for (int i = 0; i < completeHistory.length; i++ ) { | 345 final HistoryNode n = completeHistory[i]; |
| 338 final HistoryNode n = completeHistory[i]; | 346 handler.next(ei.init(n)); |
| 339 handler.next(ei.init(n)); | 347 ph2.worked(1); |
| 340 ph2.worked(1); | 348 cancelHelper.checkCancelled(); |
| 341 cancelHelper.checkCancelled(); | |
| 342 } | |
| 343 } catch (HgCallbackTargetException.Wrap ex) { | |
| 344 throw new HgCallbackTargetException(ex); | |
| 345 } | 349 } |
| 346 progressHelper.done(); | 350 progressHelper.done(); |
| 347 } | 351 } |
| 348 | 352 |
| 349 // | 353 // |
| 397 * @author TMate Software Ltd. | 401 * @author TMate Software Ltd. |
| 398 */ | 402 */ |
| 399 public interface FileHistoryHandler extends HgChangesetHandler { // FIXME move to stanalone class file, perhaps? | 403 public interface FileHistoryHandler extends HgChangesetHandler { // FIXME move to stanalone class file, perhaps? |
| 400 // XXX perhaps, should distinguish copy from rename? And what about merged revisions and following them? | 404 // XXX perhaps, should distinguish copy from rename? And what about merged revisions and following them? |
| 401 /** | 405 /** |
| 402 * @throws HgCallbackTargetException.Wrap wrapper object for any exception user code may produce. Wrapped exception would get re-thrown with {@link HgCallbackTargetException} | 406 * @throws HgCallbackTargetException wrapper object for any exception user code may produce |
| 403 */ | 407 */ |
| 404 void copy(HgFileRevision from, HgFileRevision to) throws HgCallbackTargetException.Wrap; | 408 void copy(HgFileRevision from, HgFileRevision to) throws HgCallbackTargetException; |
| 405 } | 409 } |
| 406 | 410 |
| 407 public static class CollectHandler implements HgChangesetHandler { | 411 public static class CollectHandler implements HgChangesetHandler { |
| 408 private final List<HgChangeset> result = new LinkedList<HgChangeset>(); | 412 private final List<HgChangeset> result = new LinkedList<HgChangeset>(); |
| 409 | 413 |
| 469 | 473 |
| 470 public Nodeid fileRevision() { | 474 public Nodeid fileRevision() { |
| 471 return historyNode.fileRevision; | 475 return historyNode.fileRevision; |
| 472 } | 476 } |
| 473 | 477 |
| 474 public HgChangeset changeset() throws HgException { | 478 public HgChangeset changeset() { |
| 475 return get(historyNode.changeset)[0]; | 479 return get(historyNode.changeset)[0]; |
| 476 } | 480 } |
| 477 | 481 |
| 478 public Pair<HgChangeset, HgChangeset> parents() throws HgException { | 482 public Pair<HgChangeset, HgChangeset> parents() { |
| 479 if (parents != null) { | 483 if (parents != null) { |
| 480 return parents; | 484 return parents; |
| 481 } | 485 } |
| 482 HistoryNode p; | 486 HistoryNode p; |
| 483 final int p1, p2; | 487 final int p1, p2; |
| 493 } | 497 } |
| 494 HgChangeset[] r = get(p1, p2); | 498 HgChangeset[] r = get(p1, p2); |
| 495 return parents = new Pair<HgChangeset, HgChangeset>(r[0], r[1]); | 499 return parents = new Pair<HgChangeset, HgChangeset>(r[0], r[1]); |
| 496 } | 500 } |
| 497 | 501 |
| 498 public Collection<HgChangeset> children() throws HgException { | 502 public Collection<HgChangeset> children() { |
| 499 if (children != null) { | 503 if (children != null) { |
| 500 return children; | 504 return children; |
| 501 } | 505 } |
| 502 if (historyNode.children == null) { | 506 if (historyNode.children == null) { |
| 503 children = Collections.emptyList(); | 507 children = Collections.emptyList(); |
| 514 | 518 |
| 515 void populate(HgChangeset cs) { | 519 void populate(HgChangeset cs) { |
| 516 cachedChangesets.put(cs.getRevisionIndex(), cs); | 520 cachedChangesets.put(cs.getRevisionIndex(), cs); |
| 517 } | 521 } |
| 518 | 522 |
| 519 private HgChangeset[] get(int... changelogRevisionIndex) throws HgException { | 523 private HgChangeset[] get(int... changelogRevisionIndex) { |
| 520 HgChangeset[] rv = new HgChangeset[changelogRevisionIndex.length]; | 524 HgChangeset[] rv = new HgChangeset[changelogRevisionIndex.length]; |
| 521 IntVector misses = new IntVector(changelogRevisionIndex.length, -1); | 525 IntVector misses = new IntVector(changelogRevisionIndex.length, -1); |
| 522 for (int i = 0; i < changelogRevisionIndex.length; i++) { | 526 for (int i = 0; i < changelogRevisionIndex.length; i++) { |
| 523 if (changelogRevisionIndex[i] == -1) { | 527 if (changelogRevisionIndex[i] == -1) { |
| 524 rv[i] = null; | 528 rv[i] = null; |
| 536 initTransform(); | 540 initTransform(); |
| 537 repo.getChangelog().range(this, changesets2read); | 541 repo.getChangelog().range(this, changesets2read); |
| 538 for (int changeset2read : changesets2read) { | 542 for (int changeset2read : changesets2read) { |
| 539 HgChangeset cs = cachedChangesets.get(changeset2read); | 543 HgChangeset cs = cachedChangesets.get(changeset2read); |
| 540 if (cs == null) { | 544 if (cs == null) { |
| 541 throw new HgException(String.format("Can't get changeset for revision %d", changeset2read)); | 545 HgInvalidStateException t = new HgInvalidStateException(String.format("Can't get changeset for revision %d", changeset2read)); |
| 546 throw t.setRevisionIndex(changeset2read); | |
| 542 } | 547 } |
| 543 // HgChangelog.range may reorder changesets according to their order in the changelog | 548 // HgChangelog.range may reorder changesets according to their order in the changelog |
| 544 // thus need to find original index | 549 // thus need to find original index |
| 545 boolean sanity = false; | 550 boolean sanity = false; |
| 546 for (int i = 0; i < changelogRevisionIndex.length; i++) { | 551 for (int i = 0; i < changelogRevisionIndex.length; i++) { |
| 558 } | 563 } |
| 559 return rv; | 564 return rv; |
| 560 } | 565 } |
| 561 | 566 |
| 562 // init only when needed | 567 // init only when needed |
| 563 void initTransform() throws HgInvalidControlFileException { | 568 void initTransform() throws HgRuntimeException { |
| 564 if (transform == null) { | 569 if (transform == null) { |
| 565 transform = new ChangesetTransformer.Transformation(new HgStatusCollector(repo)/*XXX try to reuse from context?*/, getParentHelper(false)); | 570 transform = new ChangesetTransformer.Transformation(new HgStatusCollector(repo)/*XXX try to reuse from context?*/, getParentHelper(false)); |
| 566 } | 571 } |
| 567 } | 572 } |
| 568 | 573 |
| 569 public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) { | 574 public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) { |
| 570 HgChangeset cs = transform.handle(revisionNumber, nodeid, cset); | 575 HgChangeset cs = transform.handle(revisionNumber, nodeid, cset); |
| 571 populate(cs.clone()); | 576 populate(cs.clone()); |
| 572 } | 577 } |
| 573 | 578 |
| 574 public Nodeid changesetRevision() throws HgException { | 579 public Nodeid changesetRevision() { |
| 575 if (changesetRevision == null) { | 580 if (changesetRevision == null) { |
| 576 changesetRevision = getRevision(historyNode.changeset); | 581 changesetRevision = getRevision(historyNode.changeset); |
| 577 } | 582 } |
| 578 return changesetRevision; | 583 return changesetRevision; |
| 579 } | 584 } |
| 580 | 585 |
| 581 public Pair<Nodeid, Nodeid> parentRevisions() throws HgException { | 586 public Pair<Nodeid, Nodeid> parentRevisions() { |
| 582 if (parentRevisions == null) { | 587 if (parentRevisions == null) { |
| 583 HistoryNode p; | 588 HistoryNode p; |
| 584 final Nodeid p1, p2; | 589 final Nodeid p1, p2; |
| 585 if ((p = historyNode.parent1) != null) { | 590 if ((p = historyNode.parent1) != null) { |
| 586 p1 = getRevision(p.changeset); | 591 p1 = getRevision(p.changeset); |
| 595 parentRevisions = new Pair<Nodeid, Nodeid>(p1, p2); | 600 parentRevisions = new Pair<Nodeid, Nodeid>(p1, p2); |
| 596 } | 601 } |
| 597 return parentRevisions; | 602 return parentRevisions; |
| 598 } | 603 } |
| 599 | 604 |
| 600 public Collection<Nodeid> childRevisions() throws HgException { | 605 public Collection<Nodeid> childRevisions() { |
| 601 if (childRevisions != null) { | 606 if (childRevisions != null) { |
| 602 return childRevisions; | 607 return childRevisions; |
| 603 } | 608 } |
| 604 if (historyNode.children == null) { | 609 if (historyNode.children == null) { |
| 605 childRevisions = Collections.emptyList(); | 610 childRevisions = Collections.emptyList(); |
| 612 } | 617 } |
| 613 return childRevisions; | 618 return childRevisions; |
| 614 } | 619 } |
| 615 | 620 |
| 616 // reading nodeid involves reading index only, guess, can afford not to optimize multiple reads | 621 // reading nodeid involves reading index only, guess, can afford not to optimize multiple reads |
| 617 private Nodeid getRevision(int changelogRevisionNumber) throws HgInvalidControlFileException { | 622 private Nodeid getRevision(int changelogRevisionNumber) { |
| 618 // TODO [post-1.0] pipe through pool | 623 // TODO post-1.0 pipe through pool |
| 619 HgChangeset cs = cachedChangesets.get(changelogRevisionNumber); | 624 HgChangeset cs = cachedChangesets.get(changelogRevisionNumber); |
| 620 if (cs != null) { | 625 if (cs != null) { |
| 621 return cs.getNodeid(); | 626 return cs.getNodeid(); |
| 622 } else { | 627 } else { |
| 623 return repo.getChangelog().getRevision(changelogRevisionNumber); | 628 return repo.getChangelog().getRevision(changelogRevisionNumber); |
