Mercurial > jhg
comparison src/org/tmatesoft/hg/core/HgDiffCommand.java @ 630:72c979555cb8
HgDiffCommand. Do not use deprecated code. Javadoc
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 23 May 2013 19:44:28 +0200 |
| parents | 5f52074707b2 |
| children | 54e16ab771ec |
comparison
equal
deleted
inserted
replaced
| 629:5f52074707b2 | 630:72c979555cb8 |
|---|---|
| 14 * the terms of a license other than GNU General Public License | 14 * the terms of a license other than GNU General Public License |
| 15 * contact TMate Software at support@hg4j.com | 15 * contact TMate Software at support@hg4j.com |
| 16 */ | 16 */ |
| 17 package org.tmatesoft.hg.core; | 17 package org.tmatesoft.hg.core; |
| 18 | 18 |
| 19 import static org.tmatesoft.hg.repo.HgInternals.wrongRevisionIndex; | |
| 20 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; | 19 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; |
| 21 import static org.tmatesoft.hg.repo.HgRepository.TIP; | 20 import static org.tmatesoft.hg.repo.HgRepository.TIP; |
| 22 | 21 |
| 23 import org.tmatesoft.hg.internal.BlameHelper; | 22 import org.tmatesoft.hg.internal.BlameHelper; |
| 23 import org.tmatesoft.hg.internal.CsetParamKeeper; | |
| 24 import org.tmatesoft.hg.internal.Experimental; | 24 import org.tmatesoft.hg.internal.Experimental; |
| 25 import org.tmatesoft.hg.internal.FileHistory; | 25 import org.tmatesoft.hg.internal.FileHistory; |
| 26 import org.tmatesoft.hg.internal.FileRevisionHistoryChunk; | 26 import org.tmatesoft.hg.internal.FileRevisionHistoryChunk; |
| 27 import org.tmatesoft.hg.repo.HgDataFile; | 27 import org.tmatesoft.hg.repo.HgDataFile; |
| 28 import org.tmatesoft.hg.repo.HgInternals; | |
| 29 import org.tmatesoft.hg.repo.HgRepository; | 28 import org.tmatesoft.hg.repo.HgRepository; |
| 30 import org.tmatesoft.hg.repo.HgRuntimeException; | 29 import org.tmatesoft.hg.repo.HgRuntimeException; |
| 31 import org.tmatesoft.hg.util.CancelledException; | 30 import org.tmatesoft.hg.util.CancelledException; |
| 32 import org.tmatesoft.hg.util.Path; | 31 import org.tmatesoft.hg.util.Path; |
| 33 | 32 |
| 41 @Experimental(reason="#execute* methods might get renamed") | 40 @Experimental(reason="#execute* methods might get renamed") |
| 42 public class HgDiffCommand extends HgAbstractCommand<HgDiffCommand> { | 41 public class HgDiffCommand extends HgAbstractCommand<HgDiffCommand> { |
| 43 | 42 |
| 44 private final HgRepository repo; | 43 private final HgRepository repo; |
| 45 private HgDataFile df; | 44 private HgDataFile df; |
| 46 private int clogRevIndexStart, clogRevIndexEnd; | 45 private final CsetParamKeeper clogRevIndexStart, clogRevIndexEnd; |
| 47 private int clogRevIndexToParents; | |
| 48 private HgIterateDirection iterateDirection = HgIterateDirection.NewToOld; | 46 private HgIterateDirection iterateDirection = HgIterateDirection.NewToOld; |
| 49 | 47 |
| 50 public HgDiffCommand(HgRepository hgRepo) { | 48 public HgDiffCommand(HgRepository hgRepo) { |
| 51 repo = hgRepo; | 49 repo = hgRepo; |
| 50 clogRevIndexStart = new CsetParamKeeper(hgRepo); | |
| 51 clogRevIndexEnd = new CsetParamKeeper(hgRepo); | |
| 52 } | 52 } |
| 53 | 53 |
| 54 public HgDiffCommand file(Path file) { | 54 public HgDiffCommand file(Path file) { |
| 55 df = repo.getFileNode(file); | 55 df = repo.getFileNode(file); |
| 56 return this; | 56 return this; |
| 57 } | 57 } |
| 58 | 58 |
| 59 /** | |
| 60 * Selects the file which history to blame, mandatory. | |
| 61 * | |
| 62 * @param file repository file | |
| 63 * @return <code>this</code> for convenience | |
| 64 */ | |
| 59 public HgDiffCommand file(HgDataFile file) { | 65 public HgDiffCommand file(HgDataFile file) { |
| 60 df = file; | 66 df = file; |
| 61 return this; | 67 return this; |
| 62 } | 68 } |
| 63 | 69 |
| 64 public HgDiffCommand range(int changelogRevIndexStart, int changelogRevIndexEnd) { | 70 /** |
| 65 clogRevIndexStart = changelogRevIndexStart; | 71 * Select range of file's history for {@link #executeDiff(HgBlameInspector)} |
| 66 clogRevIndexEnd = changelogRevIndexEnd; | 72 * and {@link #executeAnnotate(HgBlameInspector)}. |
| 67 return this; | 73 * <p> |
| 68 } | 74 * {@link #executeDiff(HgBlameInspector) diff} uses these as revisions to diff against each other, while |
| 69 | 75 * {@link #executeAnnotate(HgBlameInspector) annotate} walks the range. |
| 70 // FIXME javadoc when needed and difference with range | 76 * |
| 71 public HgDiffCommand changeset(int changelogRevIndex) { | 77 * @param changelogRevIndexStart index of changelog revision, left range boundary |
| 72 clogRevIndexToParents = changelogRevIndex; | 78 * @param changelogRevIndexEnd index of changelog revision, right range boundary |
| 73 return this; | 79 * @return <code>this</code> for convenience |
| 74 } | 80 * @throws HgBadArgumentException if failed to find any of supplied changeset |
| 75 | 81 */ |
| 76 // FIXME javadoc when needed | 82 public HgDiffCommand range(int changelogRevIndexStart, int changelogRevIndexEnd) throws HgBadArgumentException { |
| 83 clogRevIndexStart.set(changelogRevIndexStart); | |
| 84 clogRevIndexEnd.set(changelogRevIndexEnd); | |
| 85 return this; | |
| 86 } | |
| 87 | |
| 88 /** | |
| 89 * Selects revision for {@link #executeAnnotateSingleRevision(HgBlameInspector)}, the one | |
| 90 * to diff against its parents. | |
| 91 * | |
| 92 * Besides, it is handy when range of interest spans up to the very beginning of the file history | |
| 93 * (and thus is equivalent to <code>range(0, changelogRevIndex)</code>) | |
| 94 * | |
| 95 * @param changelogRevIndex index of changelog revision | |
| 96 * @return <code>this</code> for convenience | |
| 97 * @throws HgBadArgumentException if failed to find supplied changeset | |
| 98 */ | |
| 99 public HgDiffCommand changeset(int changelogRevIndex) throws HgBadArgumentException { | |
| 100 clogRevIndexStart.set(0); | |
| 101 clogRevIndexEnd.set(changelogRevIndex); | |
| 102 return this; | |
| 103 } | |
| 104 | |
| 105 /** | |
| 106 * Revision differences are reported in selected order when | |
| 107 * annotating {@link #range(int, int) range} of changesets with | |
| 108 * {@link #executeAnnotate(HgBlameInspector)}. | |
| 109 * <p> | |
| 110 * This method doesn't affect {@link #executeAnnotateSingleRevision(HgBlameInspector)} and | |
| 111 * {@link #executeDiff(HgBlameInspector)} | |
| 112 * | |
| 113 * @param order desired iteration order | |
| 114 * @return <code>this</code> for convenience | |
| 115 */ | |
| 77 public HgDiffCommand order(HgIterateDirection order) { | 116 public HgDiffCommand order(HgIterateDirection order) { |
| 78 iterateDirection = order; | 117 iterateDirection = order; |
| 79 return this; | 118 return this; |
| 80 } | 119 } |
| 81 | 120 |
| 82 // FIXME progress and cancellation | 121 // FIXME progress and cancellation |
| 83 | 122 |
| 84 /** | 123 /** |
| 85 * mimic 'hg diff -r clogRevIndex1 -r clogRevIndex2' | 124 * Diff two revisions selected with {@link #range(int, int)} against each other. |
| 125 * <p>mimics 'hg diff -r clogRevIndex1 -r clogRevIndex2' | |
| 126 * | |
| 127 * @throws HgCallbackTargetException propagated exception from the handler | |
| 128 * @throws CancelledException if execution of the command was cancelled | |
| 129 * @throws HgException subclass thereof to indicate specific issue with the command arguments or repository state | |
| 86 */ | 130 */ |
| 87 public void executeDiff(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { | 131 public void executeDiff(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { |
| 132 checkFile(); | |
| 88 try { | 133 try { |
| 89 int fileRevIndex1 = fileRevIndex(df, clogRevIndexStart); | 134 int fileRevIndex1 = fileRevIndex(df, clogRevIndexStart.get()); |
| 90 int fileRevIndex2 = fileRevIndex(df, clogRevIndexEnd); | 135 int fileRevIndex2 = fileRevIndex(df, clogRevIndexEnd.get()); |
| 91 BlameHelper bh = new BlameHelper(insp); | 136 BlameHelper bh = new BlameHelper(insp); |
| 92 bh.prepare(df, clogRevIndexStart, clogRevIndexEnd); | 137 bh.prepare(df, clogRevIndexStart.get(), clogRevIndexEnd.get()); |
| 93 bh.diff(fileRevIndex1, clogRevIndexStart, fileRevIndex2, clogRevIndexEnd); | 138 bh.diff(fileRevIndex1, clogRevIndexStart.get(), fileRevIndex2, clogRevIndexEnd.get()); |
| 94 } catch (HgRuntimeException ex) { | 139 } catch (HgRuntimeException ex) { |
| 95 throw new HgLibraryFailureException(ex); | 140 throw new HgLibraryFailureException(ex); |
| 96 } | 141 } |
| 97 } | 142 } |
| 98 | 143 |
| 99 /** | 144 /** |
| 100 * Walk file history range and report changes (diff) for each revision | 145 * Walk file history {@link #range(int, int) range} and report changes (diff) for each revision |
| 146 * | |
| 147 * @throws HgCallbackTargetException propagated exception from the handler | |
| 148 * @throws CancelledException if execution of the command was cancelled | |
| 149 * @throws HgException subclass thereof to indicate specific issue with the command arguments or repository state | |
| 101 */ | 150 */ |
| 102 public void executeAnnotate(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { | 151 public void executeAnnotate(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { |
| 103 if (wrongRevisionIndex(clogRevIndexStart) || wrongRevisionIndex(clogRevIndexEnd)) { | 152 checkFile(); |
| 104 throw new IllegalArgumentException(); | |
| 105 } | |
| 106 // FIXME check file and range are set | |
| 107 try { | 153 try { |
| 108 // Note, changelogRevIndexEnd may be TIP, while the code below doesn't tolerate constants | |
| 109 // | |
| 110 int lastRevision = repo.getChangelog().getLastRevision(); | |
| 111 if (clogRevIndexEnd == TIP) { | |
| 112 clogRevIndexEnd = lastRevision; | |
| 113 } | |
| 114 HgInternals.checkRevlogRange(clogRevIndexStart, clogRevIndexEnd, lastRevision); | |
| 115 if (!df.exists()) { | 154 if (!df.exists()) { |
| 116 return; | 155 return; |
| 117 } | 156 } |
| 118 BlameHelper bh = new BlameHelper(insp); | 157 BlameHelper bh = new BlameHelper(insp); |
| 119 FileHistory fileHistory = bh.prepare(df, clogRevIndexStart, clogRevIndexEnd); | 158 FileHistory fileHistory = bh.prepare(df, clogRevIndexStart.get(), clogRevIndexEnd.get()); |
| 120 | 159 |
| 121 int[] fileClogParentRevs = new int[2]; | 160 int[] fileClogParentRevs = new int[2]; |
| 122 int[] fileParentRevs = new int[2]; | 161 int[] fileParentRevs = new int[2]; |
| 123 for (FileRevisionHistoryChunk fhc : fileHistory.iterate(iterateDirection)) { | 162 for (FileRevisionHistoryChunk fhc : fileHistory.iterate(iterateDirection)) { |
| 124 for (int fri : fhc.fileRevisions(iterateDirection)) { | 163 for (int fri : fhc.fileRevisions(iterateDirection)) { |
| 125 int clogRevIndex = fhc.changeset(fri); | 164 int clogRevIndex = fhc.changeset(fri); |
| 126 // the way we built fileHistory ensures we won't walk past [changelogRevIndexStart..changelogRevIndexEnd] | 165 // the way we built fileHistory ensures we won't walk past [changelogRevIndexStart..changelogRevIndexEnd] |
| 127 assert clogRevIndex >= clogRevIndexStart; | 166 assert clogRevIndex >= clogRevIndexStart.get(); |
| 128 assert clogRevIndex <= clogRevIndexEnd; | 167 assert clogRevIndex <= clogRevIndexEnd.get(); |
| 129 fhc.fillFileParents(fri, fileParentRevs); | 168 fhc.fillFileParents(fri, fileParentRevs); |
| 130 fhc.fillCsetParents(fri, fileClogParentRevs); | 169 fhc.fillCsetParents(fri, fileClogParentRevs); |
| 131 bh.annotateChange(fri, clogRevIndex, fileParentRevs, fileClogParentRevs); | 170 bh.annotateChange(fri, clogRevIndex, fileParentRevs, fileClogParentRevs); |
| 132 } | 171 } |
| 133 } | 172 } |
| 138 | 177 |
| 139 /** | 178 /** |
| 140 * Annotates changes of the file against its parent(s). | 179 * Annotates changes of the file against its parent(s). |
| 141 * Unlike {@link #annotate(HgDataFile, int, Inspector, HgIterateDirection)}, doesn't | 180 * Unlike {@link #annotate(HgDataFile, int, Inspector, HgIterateDirection)}, doesn't |
| 142 * walk file history, looks at the specified revision only. Handles both parents (if merge revision). | 181 * walk file history, looks at the specified revision only. Handles both parents (if merge revision). |
| 182 * | |
| 183 * @throws HgCallbackTargetException propagated exception from the handler | |
| 184 * @throws CancelledException if execution of the command was cancelled | |
| 185 * @throws HgException subclass thereof to indicate specific issue with the command arguments or repository state | |
| 143 */ | 186 */ |
| 144 public void executeAnnotateSingleRevision(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { | 187 public void executeAnnotateSingleRevision(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { |
| 188 checkFile(); | |
| 145 try { | 189 try { |
| 146 int changelogRevisionIndex = clogRevIndexToParents; | 190 int changelogRevisionIndex = clogRevIndexEnd.get(); |
| 147 // TODO detect if file is text/binary (e.g. looking for chars < ' ' and not \t\r\n\f | 191 // TODO detect if file is text/binary (e.g. looking for chars < ' ' and not \t\r\n\f |
| 148 int fileRevIndex = fileRevIndex(df, changelogRevisionIndex); | 192 int fileRevIndex = fileRevIndex(df, changelogRevisionIndex); |
| 149 int[] fileRevParents = new int[2]; | 193 int[] fileRevParents = new int[2]; |
| 150 df.parents(fileRevIndex, fileRevParents, null, null); | 194 df.parents(fileRevIndex, fileRevParents, null, null); |
| 151 if (changelogRevisionIndex == TIP) { | 195 if (changelogRevisionIndex == TIP) { |
| 161 } catch (HgRuntimeException ex) { | 205 } catch (HgRuntimeException ex) { |
| 162 throw new HgLibraryFailureException(ex); | 206 throw new HgLibraryFailureException(ex); |
| 163 } | 207 } |
| 164 } | 208 } |
| 165 | 209 |
| 210 private void checkFile() { | |
| 211 if (df == null) { | |
| 212 throw new IllegalArgumentException("File is not set"); | |
| 213 } | |
| 214 } | |
| 166 | 215 |
| 167 private static int fileRevIndex(HgDataFile df, int csetRevIndex) throws HgRuntimeException { | 216 private static int fileRevIndex(HgDataFile df, int csetRevIndex) throws HgRuntimeException { |
| 168 Nodeid fileRev = df.getRepo().getManifest().getFileRevision(csetRevIndex, df.getPath()); | 217 Nodeid fileRev = df.getRepo().getManifest().getFileRevision(csetRevIndex, df.getPath()); |
| 169 return df.getRevisionIndex(fileRev); | 218 return df.getRevisionIndex(fileRev); |
| 170 } | 219 } |
