Mercurial > hg4j
comparison src/org/tmatesoft/hg/core/HgLogCommand.java @ 215:41a778e3fd31
Issue 5: Facilities for progress and cancellation. More specific exceptions. Exceptions from callbacks as RuntimeException
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Tue, 17 May 2011 00:56:54 +0200 |
parents | ffc5f6d59f7e |
children | 1792b37650f2 |
comparison
equal
deleted
inserted
replaced
214:4252faa556cd | 215:41a778e3fd31 |
---|---|
25 import java.util.LinkedList; | 25 import java.util.LinkedList; |
26 import java.util.List; | 26 import java.util.List; |
27 import java.util.Set; | 27 import java.util.Set; |
28 import java.util.TreeSet; | 28 import java.util.TreeSet; |
29 | 29 |
30 import org.tmatesoft.hg.repo.HgChangelog; | |
30 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; | 31 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; |
31 import org.tmatesoft.hg.repo.HgChangelog; | |
32 import org.tmatesoft.hg.repo.HgDataFile; | 32 import org.tmatesoft.hg.repo.HgDataFile; |
33 import org.tmatesoft.hg.repo.HgRepository; | 33 import org.tmatesoft.hg.repo.HgRepository; |
34 import org.tmatesoft.hg.util.ByteChannel; | 34 import org.tmatesoft.hg.util.ByteChannel; |
35 import org.tmatesoft.hg.util.CancelledException; | 35 import org.tmatesoft.hg.util.CancelledException; |
36 import org.tmatesoft.hg.util.Path; | 36 import org.tmatesoft.hg.util.Path; |
37 import org.tmatesoft.hg.util.ProgressSupport; | |
37 | 38 |
38 | 39 |
39 /** | 40 /** |
40 * Access to changelog, 'hg log' command counterpart. | 41 * Access to changelog, 'hg log' command counterpart. |
41 * | 42 * |
46 * Not thread-safe (each thread has to use own {@link HgLogCommand} instance). | 47 * Not thread-safe (each thread has to use own {@link HgLogCommand} instance). |
47 * | 48 * |
48 * @author Artem Tikhomirov | 49 * @author Artem Tikhomirov |
49 * @author TMate Software Ltd. | 50 * @author TMate Software Ltd. |
50 */ | 51 */ |
51 public class HgLogCommand implements HgChangelog.Inspector { | 52 public class HgLogCommand extends HgAbstractCommand<HgLogCommand> implements HgChangelog.Inspector { |
52 | 53 |
53 private final HgRepository repo; | 54 private final HgRepository repo; |
54 private Set<String> users; | 55 private Set<String> users; |
55 private Set<String> branches; | 56 private Set<String> branches; |
56 private int limit = 0, count = 0; | 57 private int limit = 0, count = 0; |
162 } | 163 } |
163 | 164 |
164 /** | 165 /** |
165 * Similar to {@link #execute(org.tmatesoft.hg.repo.RawChangeset.Inspector)}, collects and return result as a list. | 166 * Similar to {@link #execute(org.tmatesoft.hg.repo.RawChangeset.Inspector)}, collects and return result as a list. |
166 */ | 167 */ |
167 public List<HgChangeset> execute() throws HgException { | 168 public List<HgChangeset> execute() throws HgDataStreamException { |
168 CollectHandler collector = new CollectHandler(); | 169 CollectHandler collector = new CollectHandler(); |
169 execute(collector); | 170 try { |
171 execute(collector); | |
172 } catch (HgCallbackTargetException ex) { | |
173 // can't happen as long as our CollectHandler doesn't throw any exception | |
174 throw new HgBadStateException(ex.getCause()); | |
175 } catch (CancelledException ex) { | |
176 // can't happen, see above | |
177 throw new HgBadStateException(ex); | |
178 } | |
170 return collector.getChanges(); | 179 return collector.getChanges(); |
171 } | 180 } |
172 | 181 |
173 /** | 182 /** |
174 * | 183 * |
175 * @param handler callback to process changesets. | 184 * @param handler callback to process changesets. |
176 * @throws IllegalArgumentException when inspector argument is null | 185 * @throws IllegalArgumentException when inspector argument is null |
177 * @throws ConcurrentModificationException if this log command instance is already running | 186 * @throws ConcurrentModificationException if this log command instance is already running |
178 */ | 187 */ |
179 public void execute(HgChangesetHandler handler) throws HgException { | 188 public void execute(HgChangesetHandler handler) throws HgDataStreamException, HgCallbackTargetException, CancelledException { |
180 if (handler == null) { | 189 if (handler == null) { |
181 throw new IllegalArgumentException(); | 190 throw new IllegalArgumentException(); |
182 } | 191 } |
183 if (csetTransform != null) { | 192 if (csetTransform != null) { |
184 throw new ConcurrentModificationException(); | 193 throw new ConcurrentModificationException(); |
185 } | 194 } |
195 final ProgressSupport progressHelper = getProgressSupport(handler); | |
186 try { | 196 try { |
187 count = 0; | 197 count = 0; |
188 HgChangelog.ParentWalker pw = parentHelper; // leave it uninitialized unless we iterate whole repo | 198 HgChangelog.ParentWalker pw = parentHelper; // leave it uninitialized unless we iterate whole repo |
189 if (file == null) { | 199 if (file == null) { |
190 pw = getParentHelper(); | 200 pw = getParentHelper(); |
191 } | 201 } |
192 // ChangesetTransfrom creates a blank PathPool, and #file(String, boolean) above | 202 // ChangesetTransfrom creates a blank PathPool, and #file(String, boolean) above |
193 // may utilize it as well. CommandContext? How about StatusCollector there as well? | 203 // may utilize it as well. CommandContext? How about StatusCollector there as well? |
194 csetTransform = new ChangesetTransformer(repo, handler, pw); | 204 csetTransform = new ChangesetTransformer(repo, handler, pw, progressHelper, getCancelSupport(handler)); |
195 if (file == null) { | 205 if (file == null) { |
206 progressHelper.start(endRev - startRev + 1); | |
196 repo.getChangelog().range(startRev, endRev, this); | 207 repo.getChangelog().range(startRev, endRev, this); |
208 csetTransform.checkFailure(); | |
197 } else { | 209 } else { |
210 progressHelper.start(-1/*XXX enum const, or a dedicated method startUnspecified(). How about startAtLeast(int)?*/); | |
198 HgDataFile fileNode = repo.getFileNode(file); | 211 HgDataFile fileNode = repo.getFileNode(file); |
199 fileNode.history(startRev, endRev, this); | 212 fileNode.history(startRev, endRev, this); |
213 csetTransform.checkFailure(); | |
200 if (fileNode.isCopy()) { | 214 if (fileNode.isCopy()) { |
201 // even if we do not follow history, report file rename | 215 // even if we do not follow history, report file rename |
202 do { | 216 do { |
203 if (handler instanceof FileHistoryHandler) { | 217 if (handler instanceof FileHistoryHandler) { |
204 FileRevision src = new FileRevision(repo, fileNode.getCopySourceRevision(), fileNode.getCopySourceName()); | 218 FileRevision src = new FileRevision(repo, fileNode.getCopySourceRevision(), fileNode.getCopySourceName()); |
205 FileRevision dst = new FileRevision(repo, fileNode.getRevision(0), fileNode.getPath()); | 219 FileRevision dst = new FileRevision(repo, fileNode.getRevision(0), fileNode.getPath()); |
206 ((FileHistoryHandler) handler).copy(src, dst); | 220 try { |
221 ((FileHistoryHandler) handler).copy(src, dst); | |
222 } catch (RuntimeException ex) { | |
223 throw new HgCallbackTargetException(ex).setRevision(fileNode.getCopySourceRevision()).setFileName(fileNode.getCopySourceName()); | |
224 } | |
207 } | 225 } |
208 if (limit > 0 && count >= limit) { | 226 if (limit > 0 && count >= limit) { |
209 // if limit reach, follow is useless. | 227 // if limit reach, follow is useless. |
210 break; | 228 break; |
211 } | 229 } |
212 if (followHistory) { | 230 if (followHistory) { |
213 fileNode = repo.getFileNode(fileNode.getCopySourceName()); | 231 fileNode = repo.getFileNode(fileNode.getCopySourceName()); |
214 fileNode.history(this); | 232 fileNode.history(this); |
233 csetTransform.checkFailure(); | |
215 } | 234 } |
216 } while (followHistory && fileNode.isCopy()); | 235 } while (followHistory && fileNode.isCopy()); |
217 } | 236 } |
218 } | 237 } |
219 } finally { | 238 } finally { |
220 csetTransform = null; | 239 csetTransform = null; |
240 progressHelper.done(); | |
221 } | 241 } |
222 } | 242 } |
223 | 243 |
224 // | 244 // |
225 | 245 |