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 } |