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 }