diff src/org/tmatesoft/hg/core/ChangesetTransformer.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 a674b8590362
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/core/ChangesetTransformer.java	Mon May 16 21:10:36 2011 +0200
+++ b/src/org/tmatesoft/hg/core/ChangesetTransformer.java	Tue May 17 00:56:54 2011 +0200
@@ -22,11 +22,15 @@
 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
 import org.tmatesoft.hg.repo.HgRepository;
 import org.tmatesoft.hg.repo.HgStatusCollector;
+import org.tmatesoft.hg.util.CancelSupport;
+import org.tmatesoft.hg.util.CancelledException;
 import org.tmatesoft.hg.util.PathPool;
 import org.tmatesoft.hg.util.PathRewrite;
+import org.tmatesoft.hg.util.ProgressSupport;
 
 /**
  * Bridges {@link HgChangelog.RawChangeset} with high-level {@link HgChangeset} API
+ * FIXME move to .internal
  * 
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
@@ -34,13 +38,21 @@
 /*package-local*/ class ChangesetTransformer implements HgChangelog.Inspector {
 	private final HgChangesetHandler handler;
 	private final HgChangeset changeset;
+	private final ProgressSupport progressHelper;
+	private final CancelSupport cancelHelper;
 	private Set<String> branches;
+	private HgCallbackTargetException failure;
+	private CancelledException cancellation;
 
 	// repo and delegate can't be null, parent walker can
-	public ChangesetTransformer(HgRepository hgRepo, HgChangesetHandler delegate, HgChangelog.ParentWalker pw) {
+	// ps and cs can't be null
+	public ChangesetTransformer(HgRepository hgRepo, HgChangesetHandler delegate, HgChangelog.ParentWalker pw, ProgressSupport ps, CancelSupport cs) {
 		if (hgRepo == null || delegate == null) {
 			throw new IllegalArgumentException();
 		}
+		if (ps == null || cs == null) {
+			throw new IllegalArgumentException();
+		}
 		HgStatusCollector statusCollector = new HgStatusCollector(hgRepo);
 		// files listed in a changeset don't need their names to be rewritten (they are normalized already)
 		PathPool pp = new PathPool(new PathRewrite.Empty());
@@ -48,15 +60,41 @@
 		changeset = new HgChangeset(statusCollector, pp);
 		changeset.setParentHelper(pw);
 		handler = delegate;
+		cancelHelper = cs;
+		progressHelper = ps;
 	}
 	
 	public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) {
+		if (failure != null || cancellation != null) {
+			return; // FIXME need a better way to stop iterating revlog 
+		}
 		if (branches != null && !branches.contains(cset.branch())) {
 			return;
 		}
 
 		changeset.init(revisionNumber, nodeid, cset);
-		handler.next(changeset);
+		try {
+			handler.next(changeset);
+			progressHelper.worked(1);
+			cancelHelper.checkCancelled();
+		} catch (RuntimeException ex) {
+			failure = new HgCallbackTargetException(ex).setRevision(nodeid).setRevisionNumber(revisionNumber);
+		} catch (CancelledException ex) {
+			cancellation = ex;
+		}
+	}
+	
+	public void checkFailure() throws HgCallbackTargetException, CancelledException {
+		if (failure != null) {
+			HgCallbackTargetException toThrow = failure;
+			failure = null; // just in (otherwise unexpected) case this instance would get reused
+			throw toThrow;
+		}
+		if (cancellation != null) {
+			CancelledException toThrow = cancellation;
+			cancellation = null;
+			throw toThrow;
+		}
 	}
 	
 	public void limitBranches(Set<String> branches) {