Mercurial > jhg
comparison src/org/tmatesoft/hg/core/HgLogCommand.java @ 628:6526d8adbc0f
Explicit HgRuntimeException to facilitate easy switch from runtime to checked exceptions
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Wed, 22 May 2013 15:52:31 +0200 |
| parents | 43cfa08ff3fd |
| children | 98ff1fb49abe |
comparison
equal
deleted
inserted
replaced
| 627:5153eb73b18d | 628:6526d8adbc0f |
|---|---|
| 43 import org.tmatesoft.hg.internal.LifecycleProxy; | 43 import org.tmatesoft.hg.internal.LifecycleProxy; |
| 44 import org.tmatesoft.hg.internal.ReverseIterator; | 44 import org.tmatesoft.hg.internal.ReverseIterator; |
| 45 import org.tmatesoft.hg.repo.HgChangelog; | 45 import org.tmatesoft.hg.repo.HgChangelog; |
| 46 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; | 46 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; |
| 47 import org.tmatesoft.hg.repo.HgDataFile; | 47 import org.tmatesoft.hg.repo.HgDataFile; |
| 48 import org.tmatesoft.hg.repo.HgInvalidControlFileException; | |
| 49 import org.tmatesoft.hg.repo.HgInvalidStateException; | 48 import org.tmatesoft.hg.repo.HgInvalidStateException; |
| 50 import org.tmatesoft.hg.repo.HgParentChildMap; | 49 import org.tmatesoft.hg.repo.HgParentChildMap; |
| 51 import org.tmatesoft.hg.repo.HgRepository; | 50 import org.tmatesoft.hg.repo.HgRepository; |
| 52 import org.tmatesoft.hg.repo.HgRuntimeException; | 51 import org.tmatesoft.hg.repo.HgRuntimeException; |
| 53 import org.tmatesoft.hg.repo.HgStatusCollector; | 52 import org.tmatesoft.hg.repo.HgStatusCollector; |
| 295 throw new IllegalArgumentException(); | 294 throw new IllegalArgumentException(); |
| 296 } | 295 } |
| 297 if (csetTransform != null) { | 296 if (csetTransform != null) { |
| 298 throw new ConcurrentModificationException(); | 297 throw new ConcurrentModificationException(); |
| 299 } | 298 } |
| 300 if (repo.getChangelog().getRevisionCount() == 0) { | |
| 301 return; | |
| 302 } | |
| 303 final int lastCset = endRev == TIP ? repo.getChangelog().getLastRevision() : endRev; | |
| 304 // XXX pretty much like HgInternals.checkRevlogRange | |
| 305 if (lastCset < 0 || lastCset > repo.getChangelog().getLastRevision()) { | |
| 306 throw new HgBadArgumentException(String.format("Bad value %d for end revision", lastCset), null); | |
| 307 } | |
| 308 if (startRev < 0 || startRev > lastCset) { | |
| 309 throw new HgBadArgumentException(String.format("Bad value %d for start revision for range [%1$d..%d]", startRev, lastCset), null); | |
| 310 } | |
| 311 final ProgressSupport progressHelper = getProgressSupport(handler); | 299 final ProgressSupport progressHelper = getProgressSupport(handler); |
| 312 final int BATCH_SIZE = 100; | |
| 313 try { | 300 try { |
| 301 if (repo.getChangelog().getRevisionCount() == 0) { | |
| 302 return; | |
| 303 } | |
| 304 final int lastCset = endRev == TIP ? repo.getChangelog().getLastRevision() : endRev; | |
| 305 // XXX pretty much like HgInternals.checkRevlogRange | |
| 306 if (lastCset < 0 || lastCset > repo.getChangelog().getLastRevision()) { | |
| 307 throw new HgBadArgumentException(String.format("Bad value %d for end revision", lastCset), null); | |
| 308 } | |
| 309 if (startRev < 0 || startRev > lastCset) { | |
| 310 throw new HgBadArgumentException(String.format("Bad value %d for start revision for range [%1$d..%d]", startRev, lastCset), null); | |
| 311 } | |
| 312 final int BATCH_SIZE = 100; | |
| 314 count = 0; | 313 count = 0; |
| 315 HgParentChildMap<HgChangelog> pw = getParentHelper(file == null); // leave it uninitialized unless we iterate whole repo | 314 HgParentChildMap<HgChangelog> pw = getParentHelper(file == null); // leave it uninitialized unless we iterate whole repo |
| 316 // ChangesetTransfrom creates a blank PathPool, and #file(String, boolean) above | 315 // ChangesetTransfrom creates a blank PathPool, and #file(String, boolean) above |
| 317 // may utilize it as well. CommandContext? How about StatusCollector there as well? | 316 // may utilize it as well. CommandContext? How about StatusCollector there as well? |
| 318 csetTransform = new ChangesetTransformer(repo, handler, pw, progressHelper, getCancelSupport(handler, true)); | 317 csetTransform = new ChangesetTransformer(repo, handler, pw, progressHelper, getCancelSupport(handler, true)); |
| 515 } | 514 } |
| 516 final ProgressSupport progressHelper = getProgressSupport(handler); | 515 final ProgressSupport progressHelper = getProgressSupport(handler); |
| 517 final CancelSupport cancelHelper = getCancelSupport(handler, true); | 516 final CancelSupport cancelHelper = getCancelSupport(handler, true); |
| 518 final HgFileRenameHandlerMixin renameHandler = Adaptable.Factory.getAdapter(handler, HgFileRenameHandlerMixin.class, null); | 517 final HgFileRenameHandlerMixin renameHandler = Adaptable.Factory.getAdapter(handler, HgFileRenameHandlerMixin.class, null); |
| 519 | 518 |
| 520 | 519 try { |
| 521 // XXX rename. dispatcher is not a proper name (most of the job done - managing history chunk interconnection) | 520 |
| 522 final HandlerDispatcher dispatcher = new HandlerDispatcher() { | 521 // XXX rename. dispatcher is not a proper name (most of the job done - managing history chunk interconnection) |
| 523 | 522 final HandlerDispatcher dispatcher = new HandlerDispatcher() { |
| 524 @Override | 523 |
| 525 protected void once(HistoryNode n) throws HgCallbackTargetException, CancelledException { | 524 @Override |
| 526 handler.treeElement(ei.init(n, currentFileNode)); | 525 protected void once(HistoryNode n) throws HgCallbackTargetException, CancelledException, HgRuntimeException { |
| 526 handler.treeElement(ei.init(n, currentFileNode)); | |
| 527 cancelHelper.checkCancelled(); | |
| 528 } | |
| 529 }; | |
| 530 | |
| 531 // renamed files in the queue are placed with respect to #iterateDirection | |
| 532 // i.e. if we iterate from new to old, recent filenames come first | |
| 533 FileRenameQueueBuilder frqBuilder = new FileRenameQueueBuilder(); | |
| 534 List<Pair<HgDataFile, Nodeid>> fileRenamesQueue = frqBuilder.buildFileRenamesQueue(); | |
| 535 // XXX perhaps, makes sense to look at selected file's revision when followAncestry is true | |
| 536 // to ensure file we attempt to trace is in the WC's parent. Native hg aborts if not. | |
| 537 progressHelper.start(4 * fileRenamesQueue.size()); | |
| 538 for (int namesIndex = 0, renamesQueueSize = fileRenamesQueue.size(); namesIndex < renamesQueueSize; namesIndex++) { | |
| 539 | |
| 540 final Pair<HgDataFile, Nodeid> renameInfo = fileRenamesQueue.get(namesIndex); | |
| 541 dispatcher.prepare(progressHelper, renameInfo); | |
| 527 cancelHelper.checkCancelled(); | 542 cancelHelper.checkCancelled(); |
| 528 } | 543 if (namesIndex > 0) { |
| 529 }; | 544 dispatcher.connectWithLastJunctionPoint(renameInfo, fileRenamesQueue.get(namesIndex - 1)); |
| 530 | 545 } |
| 531 // renamed files in the queue are placed with respect to #iterateDirection | 546 if (namesIndex + 1 < renamesQueueSize) { |
| 532 // i.e. if we iterate from new to old, recent filenames come first | 547 // there's at least one more name we are going to look at |
| 533 FileRenameQueueBuilder frqBuilder = new FileRenameQueueBuilder(); | 548 dispatcher.updateJunctionPoint(renameInfo, fileRenamesQueue.get(namesIndex+1), renameHandler != null); |
| 534 List<Pair<HgDataFile, Nodeid>> fileRenamesQueue = frqBuilder.buildFileRenamesQueue(); | 549 } else { |
| 535 // XXX perhaps, makes sense to look at selected file's revision when followAncestry is true | 550 dispatcher.clearJunctionPoint(); |
| 536 // to ensure file we attempt to trace is in the WC's parent. Native hg aborts if not. | 551 } |
| 537 progressHelper.start(4 * fileRenamesQueue.size()); | 552 dispatcher.dispatchAllChanges(); |
| 538 for (int namesIndex = 0, renamesQueueSize = fileRenamesQueue.size(); namesIndex < renamesQueueSize; namesIndex++) { | 553 if (renameHandler != null && namesIndex + 1 < renamesQueueSize) { |
| 539 | 554 dispatcher.reportRenames(renameHandler); |
| 540 final Pair<HgDataFile, Nodeid> renameInfo = fileRenamesQueue.get(namesIndex); | 555 } |
| 541 dispatcher.prepare(progressHelper, renameInfo); | 556 } // for fileRenamesQueue; |
| 542 cancelHelper.checkCancelled(); | 557 frqBuilder.reportRenameIfNotInQueue(fileRenamesQueue, renameHandler); |
| 543 if (namesIndex > 0) { | 558 } catch (HgRuntimeException ex) { |
| 544 dispatcher.connectWithLastJunctionPoint(renameInfo, fileRenamesQueue.get(namesIndex - 1)); | 559 throw new HgLibraryFailureException(ex); |
| 545 } | 560 } |
| 546 if (namesIndex + 1 < renamesQueueSize) { | |
| 547 // there's at least one more name we are going to look at | |
| 548 dispatcher.updateJunctionPoint(renameInfo, fileRenamesQueue.get(namesIndex+1), renameHandler != null); | |
| 549 } else { | |
| 550 dispatcher.clearJunctionPoint(); | |
| 551 } | |
| 552 dispatcher.dispatchAllChanges(); | |
| 553 if (renameHandler != null && namesIndex + 1 < renamesQueueSize) { | |
| 554 dispatcher.reportRenames(renameHandler); | |
| 555 } | |
| 556 } // for fileRenamesQueue; | |
| 557 frqBuilder.reportRenameIfNotInQueue(fileRenamesQueue, renameHandler); | |
| 558 progressHelper.done(); | 561 progressHelper.done(); |
| 559 } | 562 } |
| 560 | 563 |
| 561 /** | 564 /** |
| 562 * Utility to build sequence of file renames | 565 * Utility to build sequence of file renames |
| 576 * | 579 * |
| 577 * TODO may use HgFileRevision (after some refactoring to accept HgDataFile and Nodeid) instead of Pair | 580 * TODO may use HgFileRevision (after some refactoring to accept HgDataFile and Nodeid) instead of Pair |
| 578 * and possibly reuse this functionality | 581 * and possibly reuse this functionality |
| 579 * | 582 * |
| 580 * @return list of file renames, ordered with respect to {@link #iterateDirection} | 583 * @return list of file renames, ordered with respect to {@link #iterateDirection} |
| 584 * @throws HgRuntimeException | |
| 581 */ | 585 */ |
| 582 public List<Pair<HgDataFile, Nodeid>> buildFileRenamesQueue() throws HgPathNotFoundException { | 586 public List<Pair<HgDataFile, Nodeid>> buildFileRenamesQueue() throws HgPathNotFoundException, HgRuntimeException { |
| 583 LinkedList<Pair<HgDataFile, Nodeid>> rv = new LinkedList<Pair<HgDataFile, Nodeid>>(); | 587 LinkedList<Pair<HgDataFile, Nodeid>> rv = new LinkedList<Pair<HgDataFile, Nodeid>>(); |
| 584 Nodeid startRev = null; | 588 Nodeid startRev = null; |
| 585 HgDataFile fileNode = repo.getFileNode(file); | 589 HgDataFile fileNode = repo.getFileNode(file); |
| 586 if (!fileNode.exists()) { | 590 if (!fileNode.exists()) { |
| 587 throw new HgPathNotFoundException(String.format("File %s not found in the repository", file), file); | 591 throw new HgPathNotFoundException(String.format("File %s not found in the repository", file), file); |
| 611 } | 615 } |
| 612 }; | 616 }; |
| 613 return rv; | 617 return rv; |
| 614 } | 618 } |
| 615 | 619 |
| 616 public boolean hasOrigin(Pair<HgDataFile, Nodeid> p) { | 620 public boolean hasOrigin(Pair<HgDataFile, Nodeid> p) throws HgRuntimeException { |
| 617 return p.first().isCopy(); | 621 return p.first().isCopy(); |
| 618 } | 622 } |
| 619 | 623 |
| 620 public Pair<HgDataFile, Nodeid> origin(Pair<HgDataFile, Nodeid> p) { | 624 public Pair<HgDataFile, Nodeid> origin(Pair<HgDataFile, Nodeid> p) throws HgRuntimeException { |
| 621 HgDataFile fileNode = p.first(); | 625 HgDataFile fileNode = p.first(); |
| 622 assert fileNode.isCopy(); | 626 assert fileNode.isCopy(); |
| 623 Path fp = fileNode.getCopySourceName(); | 627 Path fp = fileNode.getCopySourceName(); |
| 624 Nodeid copyRev = fileNode.getCopySourceRevision(); | 628 Nodeid copyRev = fileNode.getCopySourceRevision(); |
| 625 fileNode = repo.getFileNode(fp); | 629 fileNode = repo.getFileNode(fp); |
| 631 * even if queue didn't get rename information due to followRenames == false | 635 * even if queue didn't get rename information due to followRenames == false |
| 632 * | 636 * |
| 633 * @param queue value from {@link #buildFileRenamesQueue()} | 637 * @param queue value from {@link #buildFileRenamesQueue()} |
| 634 * @param renameHandler may be <code>null</code> | 638 * @param renameHandler may be <code>null</code> |
| 635 */ | 639 */ |
| 636 public void reportRenameIfNotInQueue(List<Pair<HgDataFile, Nodeid>> queue, HgFileRenameHandlerMixin renameHandler) throws HgCallbackTargetException { | 640 public void reportRenameIfNotInQueue(List<Pair<HgDataFile, Nodeid>> queue, HgFileRenameHandlerMixin renameHandler) throws HgCallbackTargetException, HgRuntimeException { |
| 637 if (renameHandler != null && !followRenames) { | 641 if (renameHandler != null && !followRenames) { |
| 638 // If followRenames is true, all the historical names were in the queue and are processed already. | 642 // If followRenames is true, all the historical names were in the queue and are processed already. |
| 639 // Hence, shall process origin explicitly only when renameHandler is present but followRenames is not requested. | 643 // Hence, shall process origin explicitly only when renameHandler is present but followRenames is not requested. |
| 640 assert queue.size() == 1; // see the way queue is constructed above | 644 assert queue.size() == 1; // see the way queue is constructed above |
| 641 Pair<HgDataFile, Nodeid> curRename = queue.get(0); | 645 Pair<HgDataFile, Nodeid> curRename = queue.get(0); |
| 675 p2 = completeHistory[parent2]; | 679 p2 = completeHistory[parent2]; |
| 676 } | 680 } |
| 677 completeHistory[revisionNumber] = new HistoryNode(commitRevisions[revisionNumber], revision, p1, p2); | 681 completeHistory[revisionNumber] = new HistoryNode(commitRevisions[revisionNumber], revision, p1, p2); |
| 678 } | 682 } |
| 679 | 683 |
| 680 HistoryNode one(HgDataFile fileNode, Nodeid fileRevision) throws HgInvalidControlFileException { | 684 HistoryNode one(HgDataFile fileNode, Nodeid fileRevision) throws HgRuntimeException { |
| 681 int fileRevIndexToVisit = fileNode.getRevisionIndex(fileRevision); | 685 int fileRevIndexToVisit = fileNode.getRevisionIndex(fileRevision); |
| 682 return one(fileNode, fileRevIndexToVisit); | 686 return one(fileNode, fileRevIndexToVisit); |
| 683 } | 687 } |
| 684 | 688 |
| 685 HistoryNode one(HgDataFile fileNode, int fileRevIndexToVisit) throws HgInvalidControlFileException { | 689 HistoryNode one(HgDataFile fileNode, int fileRevIndexToVisit) throws HgRuntimeException { |
| 686 resultHistory = null; | 690 resultHistory = null; |
| 687 if (fileRevIndexToVisit == HgRepository.TIP) { | 691 if (fileRevIndexToVisit == HgRepository.TIP) { |
| 688 fileRevIndexToVisit = fileNode.getLastRevision(); | 692 fileRevIndexToVisit = fileNode.getLastRevision(); |
| 689 } | 693 } |
| 690 // still, allocate whole array, for #next to be able to get null parent values | 694 // still, allocate whole array, for #next to be able to get null parent values |
| 706 * lastRevisionIndex would be included. | 710 * lastRevisionIndex would be included. |
| 707 * | 711 * |
| 708 * @return list of history elements, from oldest to newest. In case {@link #followAncestry} is <code>true</code>, the list | 712 * @return list of history elements, from oldest to newest. In case {@link #followAncestry} is <code>true</code>, the list |
| 709 * is modifiable (to further augment with last/first elements of renamed file histories) | 713 * is modifiable (to further augment with last/first elements of renamed file histories) |
| 710 */ | 714 */ |
| 711 List<HistoryNode> go(HgDataFile fileNode, Nodeid fileLastRevisionToVisit) throws HgInvalidControlFileException { | 715 List<HistoryNode> go(HgDataFile fileNode, Nodeid fileLastRevisionToVisit) throws HgRuntimeException { |
| 712 resultHistory = null; | 716 resultHistory = null; |
| 713 int fileLastRevIndexToVisit = fileLastRevisionToVisit == null ? fileNode.getLastRevision() : fileNode.getRevisionIndex(fileLastRevisionToVisit); | 717 int fileLastRevIndexToVisit = fileLastRevisionToVisit == null ? fileNode.getLastRevision() : fileNode.getRevisionIndex(fileLastRevisionToVisit); |
| 714 completeHistory = new HistoryNode[fileLastRevIndexToVisit+1]; | 718 completeHistory = new HistoryNode[fileLastRevIndexToVisit+1]; |
| 715 commitRevisions = new int[completeHistory.length]; | 719 commitRevisions = new int[completeHistory.length]; |
| 716 fileNode.indexWalk(0, fileLastRevIndexToVisit, this); | 720 fileNode.indexWalk(0, fileLastRevIndexToVisit, this); |
| 803 private HistoryNode junctionNode; | 807 private HistoryNode junctionNode; |
| 804 // initialized when there's HgFileRenameHandlerMixin | 808 // initialized when there's HgFileRenameHandlerMixin |
| 805 private HgFileRevision copiedFrom, copiedTo; | 809 private HgFileRevision copiedFrom, copiedTo; |
| 806 | 810 |
| 807 // parentProgress shall be initialized with 4 XXX refactor all this stuff with parentProgress | 811 // parentProgress shall be initialized with 4 XXX refactor all this stuff with parentProgress |
| 808 public void prepare(ProgressSupport parentProgress, Pair<HgDataFile, Nodeid> renameInfo) { | 812 public void prepare(ProgressSupport parentProgress, Pair<HgDataFile, Nodeid> renameInfo) throws HgRuntimeException { |
| 809 // if we don't followAncestry, take complete history | 813 // if we don't followAncestry, take complete history |
| 810 // XXX treeBuildInspector knows followAncestry, perhaps the logic | 814 // XXX treeBuildInspector knows followAncestry, perhaps the logic |
| 811 // whether to take specific revision or the last one shall be there? | 815 // whether to take specific revision or the last one shall be there? |
| 812 changeHistory = treeBuildInspector.go(renameInfo.first(), followAncestry ? renameInfo.second() : null); | 816 changeHistory = treeBuildInspector.go(renameInfo.first(), followAncestry ? renameInfo.second() : null); |
| 813 assert changeHistory.size() > 0; | 817 assert changeHistory.size() > 0; |
| 832 progress.start(historyNodeCount); | 836 progress.start(historyNodeCount); |
| 833 // switch to present chunk's file node | 837 // switch to present chunk's file node |
| 834 switchTo(renameInfo.first()); | 838 switchTo(renameInfo.first()); |
| 835 } | 839 } |
| 836 | 840 |
| 837 public void updateJunctionPoint(Pair<HgDataFile, Nodeid> curRename, Pair<HgDataFile, Nodeid> nextRename, boolean needCopyFromTo) { | 841 public void updateJunctionPoint(Pair<HgDataFile, Nodeid> curRename, Pair<HgDataFile, Nodeid> nextRename, boolean needCopyFromTo) throws HgRuntimeException { |
| 838 copiedFrom = copiedTo = null; | 842 copiedFrom = copiedTo = null; |
| 839 // | 843 // |
| 840 // A (old) renamed to B(new). A(0..k..n) -> B(0..m). If followAncestry, k == n | 844 // A (old) renamed to B(new). A(0..k..n) -> B(0..m). If followAncestry, k == n |
| 841 // curRename.second() points to A(k) | 845 // curRename.second() points to A(k) |
| 842 if (iterateDirection == HgIterateDirection.OldToNew) { | 846 if (iterateDirection == HgIterateDirection.OldToNew) { |
| 874 copiedTo = new HgFileRevision(curRename.first(), junctionNode.fileRevision, copiedFrom.getPath()); // "B", B(0) | 878 copiedTo = new HgFileRevision(curRename.first(), junctionNode.fileRevision, copiedFrom.getPath()); // "B", B(0) |
| 875 } | 879 } |
| 876 } | 880 } |
| 877 } | 881 } |
| 878 | 882 |
| 879 public void reportRenames(HgFileRenameHandlerMixin renameHandler) throws HgCallbackTargetException { | 883 public void reportRenames(HgFileRenameHandlerMixin renameHandler) throws HgCallbackTargetException, HgRuntimeException { |
| 880 if (renameHandler != null) { // shall report renames | 884 if (renameHandler != null) { // shall report renames |
| 881 assert copiedFrom != null; | 885 assert copiedFrom != null; |
| 882 assert copiedTo != null; | 886 assert copiedTo != null; |
| 883 renameHandler.copy(copiedFrom, copiedTo); | 887 renameHandler.copy(copiedFrom, copiedTo); |
| 884 } | 888 } |
| 929 int csetStart = changeHistory.get(0).changeset; | 933 int csetStart = changeHistory.get(0).changeset; |
| 930 int csetEnd = changeHistory.get(changeHistory.size() - 1).changeset; | 934 int csetEnd = changeHistory.get(changeHistory.size() - 1).changeset; |
| 931 throw new HgInvalidStateException(String.format("For change history (cset[%d..%d]) could not find node for file change %s", csetStart, csetEnd, fileRevision.shortNotation())); | 935 throw new HgInvalidStateException(String.format("For change history (cset[%d..%d]) could not find node for file change %s", csetStart, csetEnd, fileRevision.shortNotation())); |
| 932 } | 936 } |
| 933 | 937 |
| 934 protected abstract void once(HistoryNode n) throws HgCallbackTargetException, CancelledException; | 938 protected abstract void once(HistoryNode n) throws HgCallbackTargetException, CancelledException, HgRuntimeException; |
| 935 | 939 |
| 936 public void dispatchAllChanges() throws HgCallbackTargetException, CancelledException { | 940 public void dispatchAllChanges() throws HgCallbackTargetException, CancelledException, HgRuntimeException { |
| 937 // XXX shall sort changeHistory according to changeset numbers? | 941 // XXX shall sort changeHistory according to changeset numbers? |
| 938 Iterator<HistoryNode> it; | 942 Iterator<HistoryNode> it; |
| 939 if (iterateDirection == HgIterateDirection.OldToNew) { | 943 if (iterateDirection == HgIterateDirection.OldToNew) { |
| 940 it = changeHistory.listIterator(); | 944 it = changeHistory.listIterator(); |
| 941 } else { | 945 } else { |
| 981 } else { | 985 } else { |
| 982 lifecycleProxy.init(inspector); | 986 lifecycleProxy.init(inspector); |
| 983 } | 987 } |
| 984 } | 988 } |
| 985 | 989 |
| 986 public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) { | 990 public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) throws HgRuntimeException { |
| 987 if (limit > 0 && count >= limit) { | 991 if (limit > 0 && count >= limit) { |
| 988 return; | 992 return; |
| 989 } | 993 } |
| 990 // XXX may benefit from optional interface with #isInterested(int csetRev) - to avoid | 994 // XXX may benefit from optional interface with #isInterested(int csetRev) - to avoid |
| 991 // RawChangeset instantiation | 995 // RawChangeset instantiation |
| 1020 lifecycleProxy.stop(); | 1024 lifecycleProxy.stop(); |
| 1021 } | 1025 } |
| 1022 } | 1026 } |
| 1023 } | 1027 } |
| 1024 | 1028 |
| 1025 private HgParentChildMap<HgChangelog> getParentHelper(boolean create) throws HgInvalidControlFileException { | 1029 private HgParentChildMap<HgChangelog> getParentHelper(boolean create) throws HgRuntimeException { |
| 1026 if (parentHelper == null && create) { | 1030 if (parentHelper == null && create) { |
| 1027 parentHelper = new HgParentChildMap<HgChangelog>(repo.getChangelog()); | 1031 parentHelper = new HgParentChildMap<HgChangelog>(repo.getChangelog()); |
| 1028 parentHelper.init(); | 1032 parentHelper.init(); |
| 1029 } | 1033 } |
| 1030 return parentHelper; | 1034 return parentHelper; |
| 1118 | 1122 |
| 1119 public HgDataFile file() { | 1123 public HgDataFile file() { |
| 1120 return fileNode; | 1124 return fileNode; |
| 1121 } | 1125 } |
| 1122 | 1126 |
| 1123 public HgChangeset changeset() { | 1127 public HgChangeset changeset() throws HgRuntimeException { |
| 1124 return get(historyNode.changeset)[0]; | 1128 return get(historyNode.changeset)[0]; |
| 1125 } | 1129 } |
| 1126 | 1130 |
| 1127 public Pair<HgChangeset, HgChangeset> parents() { | 1131 public Pair<HgChangeset, HgChangeset> parents() throws HgRuntimeException { |
| 1128 if (parents != null) { | 1132 if (parents != null) { |
| 1129 return parents; | 1133 return parents; |
| 1130 } | 1134 } |
| 1131 HistoryNode p; | 1135 HistoryNode p; |
| 1132 final int p1, p2; | 1136 final int p1, p2; |
| 1142 } | 1146 } |
| 1143 HgChangeset[] r = get(p1, p2); | 1147 HgChangeset[] r = get(p1, p2); |
| 1144 return parents = new Pair<HgChangeset, HgChangeset>(r[0], r[1]); | 1148 return parents = new Pair<HgChangeset, HgChangeset>(r[0], r[1]); |
| 1145 } | 1149 } |
| 1146 | 1150 |
| 1147 public Collection<HgChangeset> children() { | 1151 public Collection<HgChangeset> children() throws HgRuntimeException { |
| 1148 if (children != null) { | 1152 if (children != null) { |
| 1149 return children; | 1153 return children; |
| 1150 } | 1154 } |
| 1151 if (historyNode.children == null) { | 1155 if (historyNode.children == null) { |
| 1152 children = Collections.emptyList(); | 1156 children = Collections.emptyList(); |
| 1163 | 1167 |
| 1164 void populate(HgChangeset cs) { | 1168 void populate(HgChangeset cs) { |
| 1165 cachedChangesets.put(cs.getRevisionIndex(), cs); | 1169 cachedChangesets.put(cs.getRevisionIndex(), cs); |
| 1166 } | 1170 } |
| 1167 | 1171 |
| 1168 private HgChangeset[] get(int... changelogRevisionIndex) { | 1172 private HgChangeset[] get(int... changelogRevisionIndex) throws HgRuntimeException { |
| 1169 HgChangeset[] rv = new HgChangeset[changelogRevisionIndex.length]; | 1173 HgChangeset[] rv = new HgChangeset[changelogRevisionIndex.length]; |
| 1170 IntVector misses = new IntVector(changelogRevisionIndex.length, -1); | 1174 IntVector misses = new IntVector(changelogRevisionIndex.length, -1); |
| 1171 for (int i = 0; i < changelogRevisionIndex.length; i++) { | 1175 for (int i = 0; i < changelogRevisionIndex.length; i++) { |
| 1172 if (changelogRevisionIndex[i] == -1) { | 1176 if (changelogRevisionIndex[i] == -1) { |
| 1173 rv[i] = null; | 1177 rv[i] = null; |
| 1185 initTransform(); | 1189 initTransform(); |
| 1186 repo.getChangelog().range(this, changesets2read); | 1190 repo.getChangelog().range(this, changesets2read); |
| 1187 for (int changeset2read : changesets2read) { | 1191 for (int changeset2read : changesets2read) { |
| 1188 HgChangeset cs = cachedChangesets.get(changeset2read); | 1192 HgChangeset cs = cachedChangesets.get(changeset2read); |
| 1189 if (cs == null) { | 1193 if (cs == null) { |
| 1190 HgInvalidStateException t = new HgInvalidStateException(String.format("Can't get changeset for revision %d", changeset2read)); | 1194 throw new HgInvalidStateException(String.format("Can't get changeset for revision %d", changeset2read)); |
| 1191 throw t.setRevisionIndex(changeset2read); | |
| 1192 } | 1195 } |
| 1193 // HgChangelog.range may reorder changesets according to their order in the changelog | 1196 // HgChangelog.range may reorder changesets according to their order in the changelog |
| 1194 // thus need to find original index | 1197 // thus need to find original index |
| 1195 boolean sanity = false; | 1198 boolean sanity = false; |
| 1196 for (int i = 0; i < changelogRevisionIndex.length; i++) { | 1199 for (int i = 0; i < changelogRevisionIndex.length; i++) { |
| 1219 public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) { | 1222 public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) { |
| 1220 HgChangeset cs = transform.handle(revisionNumber, nodeid, cset); | 1223 HgChangeset cs = transform.handle(revisionNumber, nodeid, cset); |
| 1221 populate(cs.clone()); | 1224 populate(cs.clone()); |
| 1222 } | 1225 } |
| 1223 | 1226 |
| 1224 public Nodeid changesetRevision() { | 1227 public Nodeid changesetRevision() throws HgRuntimeException { |
| 1225 if (changesetRevision == null) { | 1228 if (changesetRevision == null) { |
| 1226 changesetRevision = getRevision(historyNode.changeset); | 1229 changesetRevision = getRevision(historyNode.changeset); |
| 1227 } | 1230 } |
| 1228 return changesetRevision; | 1231 return changesetRevision; |
| 1229 } | 1232 } |
| 1230 | 1233 |
| 1231 public Pair<Nodeid, Nodeid> parentRevisions() { | 1234 public Pair<Nodeid, Nodeid> parentRevisions() throws HgRuntimeException { |
| 1232 if (parentRevisions == null) { | 1235 if (parentRevisions == null) { |
| 1233 HistoryNode p; | 1236 HistoryNode p; |
| 1234 final Nodeid p1, p2; | 1237 final Nodeid p1, p2; |
| 1235 if ((p = historyNode.parent1) != null) { | 1238 if ((p = historyNode.parent1) != null) { |
| 1236 p1 = getRevision(p.changeset); | 1239 p1 = getRevision(p.changeset); |
| 1245 parentRevisions = new Pair<Nodeid, Nodeid>(p1, p2); | 1248 parentRevisions = new Pair<Nodeid, Nodeid>(p1, p2); |
| 1246 } | 1249 } |
| 1247 return parentRevisions; | 1250 return parentRevisions; |
| 1248 } | 1251 } |
| 1249 | 1252 |
| 1250 public Collection<Nodeid> childRevisions() { | 1253 public Collection<Nodeid> childRevisions() throws HgRuntimeException { |
| 1251 if (childRevisions != null) { | 1254 if (childRevisions != null) { |
| 1252 return childRevisions; | 1255 return childRevisions; |
| 1253 } | 1256 } |
| 1254 if (historyNode.children == null) { | 1257 if (historyNode.children == null) { |
| 1255 childRevisions = Collections.emptyList(); | 1258 childRevisions = Collections.emptyList(); |
| 1262 } | 1265 } |
| 1263 return childRevisions; | 1266 return childRevisions; |
| 1264 } | 1267 } |
| 1265 | 1268 |
| 1266 // reading nodeid involves reading index only, guess, can afford not to optimize multiple reads | 1269 // reading nodeid involves reading index only, guess, can afford not to optimize multiple reads |
| 1267 private Nodeid getRevision(int changelogRevisionNumber) { | 1270 private Nodeid getRevision(int changelogRevisionNumber) throws HgRuntimeException { |
| 1268 // TODO post-1.0 pipe through pool | 1271 // TODO post-1.0 pipe through pool |
| 1269 HgChangeset cs = cachedChangesets.get(changelogRevisionNumber); | 1272 HgChangeset cs = cachedChangesets.get(changelogRevisionNumber); |
| 1270 if (cs != null) { | 1273 if (cs != null) { |
| 1271 return cs.getNodeid(); | 1274 return cs.getNodeid(); |
| 1272 } else { | 1275 } else { |
