Mercurial > hg4j
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 { |