Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/HgBlameFacility.java @ 573:e49f9d9513fa
Partial blame when start/end revisions are in the middle of a single filename history
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Fri, 12 Apr 2013 19:50:21 +0200 |
| parents | 36853bb80a35 |
| children | 43cfa08ff3fd |
comparison
equal
deleted
inserted
replaced
| 572:becd2a1310a2 | 573:e49f9d9513fa |
|---|---|
| 77 */ | 77 */ |
| 78 public void annotate(int changelogRevIndexStart, int changelogRevIndexEnd, Inspector insp, HgIterateDirection iterateOrder) throws HgCallbackTargetException { | 78 public void annotate(int changelogRevIndexStart, int changelogRevIndexEnd, Inspector insp, HgIterateDirection iterateOrder) throws HgCallbackTargetException { |
| 79 if (wrongRevisionIndex(changelogRevIndexStart) || wrongRevisionIndex(changelogRevIndexEnd)) { | 79 if (wrongRevisionIndex(changelogRevIndexStart) || wrongRevisionIndex(changelogRevIndexEnd)) { |
| 80 throw new IllegalArgumentException(); | 80 throw new IllegalArgumentException(); |
| 81 } | 81 } |
| 82 // Note, changelogRevisionIndex may be TIP, while the code below doesn't tolerate constants | 82 // Note, changelogRevIndexEnd may be TIP, while the code below doesn't tolerate constants |
| 83 // | 83 // |
| 84 int lastRevision = df.getRepo().getChangelog().getLastRevision(); | 84 int lastRevision = df.getRepo().getChangelog().getLastRevision(); |
| 85 if (changelogRevIndexEnd == TIP) { | 85 if (changelogRevIndexEnd == TIP) { |
| 86 changelogRevIndexEnd = lastRevision; | 86 changelogRevIndexEnd = lastRevision; |
| 87 } | 87 } |
| 99 fileHistory.init(fileLastClogRevIndex); | 99 fileHistory.init(fileLastClogRevIndex); |
| 100 fileHistory.linkTo(nextChunk); | 100 fileHistory.linkTo(nextChunk); |
| 101 fileCompleteHistory.addFirst(fileHistory); // to get the list in old-to-new order | 101 fileCompleteHistory.addFirst(fileHistory); // to get the list in old-to-new order |
| 102 nextChunk = fileHistory; | 102 nextChunk = fileHistory; |
| 103 bh.useFileUpTo(currentFile, fileLastClogRevIndex); | 103 bh.useFileUpTo(currentFile, fileLastClogRevIndex); |
| 104 if (currentFile.isCopy()) { | 104 if (fileHistory.changeset(0) > changelogRevIndexStart && currentFile.isCopy()) { |
| 105 // TODO SessionContext.getPathFactory() and replace all Path.create | 105 // fileHistory.changeset(0) is the earliest revision we know about so far, |
| 106 // once we get to revisions earlier than the requested start, stop digging. | |
| 107 // The reason there's NO == (i.e. not >=) because: | |
| 108 // (easy): once it's equal, we've reached our intended start | |
| 109 // (hard): if changelogRevIndexStart happens to be exact start of one of renames in the | |
| 110 // chain of renames (test-annotate2 repository, file1->file1a->file1b, i.e. points | |
| 111 // to the very start of file1a or file1 history), presence of == would get us to the next | |
| 112 // chunk and hence changed parents of present chunk's first element. Our annotate alg | |
| 113 // relies on parents only (i.e. knows nothing about 'last iteration element') to find out | |
| 114 // what to compare, and hence won't report all lines of 'last iteration element' (which is the | |
| 115 // first revision of the renamed file) as "added in this revision", leaving gaps in annotate | |
| 106 HgRepository repo = currentFile.getRepo(); | 116 HgRepository repo = currentFile.getRepo(); |
| 107 Nodeid originLastRev = currentFile.getCopySourceRevision(); | 117 Nodeid originLastRev = currentFile.getCopySourceRevision(); |
| 108 currentFile = repo.getFileNode(currentFile.getCopySourceName()); | 118 currentFile = repo.getFileNode(currentFile.getCopySourceName()); |
| 109 fileLastClogRevIndex = currentFile.getChangesetRevisionIndex(currentFile.getRevisionIndex(originLastRev)); | 119 fileLastClogRevIndex = currentFile.getChangesetRevisionIndex(currentFile.getRevisionIndex(originLastRev)); |
| 110 // XXX perhaps, shall fail with meaningful exception if new file doesn't exist (.i/.d not found for whatever reason) | 120 // XXX perhaps, shall fail with meaningful exception if new file doesn't exist (.i/.d not found for whatever reason) |
| 111 // or source revision is missing? | 121 // or source revision is missing? |
| 112 } else { | 122 } else { |
| 123 fileHistory.chopAtChangeset(changelogRevIndexStart); | |
| 113 currentFile = null; // stop iterating | 124 currentFile = null; // stop iterating |
| 114 } | 125 } |
| 115 } while (currentFile != null && fileLastClogRevIndex >= changelogRevIndexStart); | 126 } while (currentFile != null && fileLastClogRevIndex > changelogRevIndexStart); |
| 116 // fileCompleteHistory is in (origin, intermediate target, ultimate target) order | 127 // fileCompleteHistory is in (origin, intermediate target, ultimate target) order |
| 117 | 128 |
| 118 int[] fileClogParentRevs = new int[2]; | 129 int[] fileClogParentRevs = new int[2]; |
| 119 int[] fileParentRevs = new int[2]; | 130 int[] fileParentRevs = new int[2]; |
| 120 if (iterateOrder == NewToOld) { | 131 if (iterateOrder == NewToOld) { |
| 404 return; | 415 return; |
| 405 } | 416 } |
| 406 target.originFileRev = fileRevsToVisit.get(0); // files to visit are new to old | 417 target.originFileRev = fileRevsToVisit.get(0); // files to visit are new to old |
| 407 target.originChangelogRev = changeset(target.originFileRev); | 418 target.originChangelogRev = changeset(target.originFileRev); |
| 408 } | 419 } |
| 409 | 420 |
| 421 /** | |
| 422 * Mark revision closest(ceil) to specified as the very first one (no parents) | |
| 423 */ | |
| 424 public void chopAtChangeset(int firstChangelogRevOfInterest) { | |
| 425 if (firstChangelogRevOfInterest == 0) { | |
| 426 return; // nothing to do | |
| 427 } | |
| 428 int i = 0, x = fileRevsToVisit.size(), fileRev = BAD_REVISION; | |
| 429 // fileRevsToVisit is new to old, greater numbers to smaller | |
| 430 while (i < x && changeset(fileRev = fileRevsToVisit.get(i)) >= firstChangelogRevOfInterest) { | |
| 431 i++; | |
| 432 } | |
| 433 assert fileRev != BAD_REVISION; // there's at least 1 revision in fileRevsToVisit | |
| 434 if (i == x && changeset(fileRev) != firstChangelogRevOfInterest) { | |
| 435 assert false : "Requested changeset shall belong to the chunk"; | |
| 436 return; | |
| 437 } | |
| 438 fileRevsToVisit.trimTo(i); // no need to iterate more | |
| 439 // pretend fileRev got no parents | |
| 440 fileParentRevs.set(fileRev * 2, NO_REVISION); | |
| 441 fileParentRevs.set(fileRev, NO_REVISION); | |
| 442 } | |
| 443 | |
| 410 public int[] fileRevisions(HgIterateDirection iterateOrder) { | 444 public int[] fileRevisions(HgIterateDirection iterateOrder) { |
| 411 // fileRevsToVisit is { r10, r7, r6, r5, r0 }, new to old | 445 // fileRevsToVisit is { r10, r7, r6, r5, r0 }, new to old |
| 412 int[] rv = fileRevsToVisit.toArray(); | 446 int[] rv = fileRevsToVisit.toArray(); |
| 413 if (iterateOrder == OldToNew) { | 447 if (iterateOrder == OldToNew) { |
| 414 // reverse return value | 448 // reverse return value |
