changeset 322:d68dcb3b5f49

Propagate command's CancelSupport to low-level API. CancelSupport from context got priority over one from command
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 30 Sep 2011 08:00:04 +0200
parents ac38e75c9e8e
children 4c7e3ba67213
files src/org/tmatesoft/hg/core/HgAbstractCommand.java src/org/tmatesoft/hg/core/HgCatCommand.java src/org/tmatesoft/hg/core/HgIncomingCommand.java src/org/tmatesoft/hg/core/HgLogCommand.java src/org/tmatesoft/hg/core/HgOutgoingCommand.java src/org/tmatesoft/hg/repo/HgDataFile.java test/org/tmatesoft/hg/test/TestAuxUtilities.java
diffstat 7 files changed, 101 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/core/HgAbstractCommand.java	Fri Sep 30 07:59:22 2011 +0200
+++ b/src/org/tmatesoft/hg/core/HgAbstractCommand.java	Fri Sep 30 08:00:04 2011 +0200
@@ -49,12 +49,20 @@
 		return ProgressSupport.Factory.get(context);
 	}
 
-	// shall not return null
-	protected CancelSupport getCancelSupport(Object context) {
+	// shall not return null if create is true
+	// CancelSupport from context, if any, takes precedence
+	protected CancelSupport getCancelSupport(Object context, boolean create) {
+		CancelSupport rv = CancelSupport.Factory.get(context, null);
+		if (rv != null) {
+			return rv;
+		}
 		if (cancelHelper != null) {
 			return cancelHelper;
 		}
-		return CancelSupport.Factory.get(context);
+		if (create) {
+			return CancelSupport.Factory.get(null);
+		}
+		return null;
 	}
 
 }
--- a/src/org/tmatesoft/hg/core/HgCatCommand.java	Fri Sep 30 07:59:22 2011 +0200
+++ b/src/org/tmatesoft/hg/core/HgCatCommand.java	Fri Sep 30 08:00:04 2011 +0200
@@ -21,10 +21,14 @@
 import static org.tmatesoft.hg.repo.HgRepository.TIP;
 
 import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 
 import org.tmatesoft.hg.repo.HgDataFile;
 import org.tmatesoft.hg.repo.HgRepository;
+import org.tmatesoft.hg.util.Adaptable;
 import org.tmatesoft.hg.util.ByteChannel;
+import org.tmatesoft.hg.util.CancelSupport;
 import org.tmatesoft.hg.util.CancelledException;
 import org.tmatesoft.hg.util.Path;
 
@@ -170,6 +174,44 @@
 		} else {
 			revToExtract = localRevision;
 		}
-		dataFile.contentWithFilters(revToExtract, sink);
+		ByteChannel sinkWrap;
+		if (getCancelSupport(null, false) == null) {
+			// no command-specific cancel helper, no need for extra proxy
+			// sink itself still may supply CS
+			sinkWrap = sink;
+		} else {
+			// try CS from sink, if any. at least there is CS from command 
+			CancelSupport cancelHelper = getCancelSupport(sink, true);
+			cancelHelper.checkCancelled();
+			sinkWrap = new ByteChannelProxy(sink, cancelHelper);
+		}
+		dataFile.contentWithFilters(revToExtract, sinkWrap);
+	}
+
+	private static class ByteChannelProxy implements ByteChannel, Adaptable {
+		private final ByteChannel delegate;
+		private final CancelSupport cancelHelper;
+
+		public ByteChannelProxy(ByteChannel _delegate, CancelSupport cs) {
+			assert _delegate != null;
+			delegate = _delegate;
+			cancelHelper = cs;
+		}
+		public int write(ByteBuffer buffer) throws IOException, CancelledException {
+			return delegate.write(buffer);
+		}
+
+		public <T> T getAdapter(Class<T> adapterClass) {
+			if (CancelSupport.class == adapterClass) {
+				return adapterClass.cast(cancelHelper);
+			}
+			if (delegate instanceof Adaptable) {
+				return ((Adaptable) delegate).getAdapter(adapterClass);
+			}
+			if (adapterClass.isInstance(delegate)) {
+				return adapterClass.cast(delegate);
+			}
+			return null;
+		}
 	}
 }
--- a/src/org/tmatesoft/hg/core/HgIncomingCommand.java	Fri Sep 30 07:59:22 2011 +0200
+++ b/src/org/tmatesoft/hg/core/HgIncomingCommand.java	Fri Sep 30 08:00:04 2011 +0200
@@ -133,7 +133,7 @@
 		HgBundle changegroup = remoteRepo.getChanges(common);
 		final ProgressSupport ps = getProgressSupport(handler);
 		try {
-			final ChangesetTransformer transformer = new ChangesetTransformer(localRepo, handler, getParentHelper(), ps, getCancelSupport(handler));
+			final ChangesetTransformer transformer = new ChangesetTransformer(localRepo, handler, getParentHelper(), ps, getCancelSupport(handler, true));
 			transformer.limitBranches(branches);
 			changegroup.changes(localRepo, new HgChangelog.Inspector() {
 				private int localIndex;
--- a/src/org/tmatesoft/hg/core/HgLogCommand.java	Fri Sep 30 07:59:22 2011 +0200
+++ b/src/org/tmatesoft/hg/core/HgLogCommand.java	Fri Sep 30 08:00:04 2011 +0200
@@ -211,7 +211,7 @@
 			}
 			// ChangesetTransfrom creates a blank PathPool, and #file(String, boolean) above 
 			// may utilize it as well. CommandContext? How about StatusCollector there as well?
-			csetTransform = new ChangesetTransformer(repo, handler, pw, progressHelper, getCancelSupport(handler));
+			csetTransform = new ChangesetTransformer(repo, handler, pw, progressHelper, getCancelSupport(handler, true));
 			if (file == null) {
 				progressHelper.start(endRev - startRev + 1);
 				repo.getChangelog().range(startRev, endRev, this);
--- a/src/org/tmatesoft/hg/core/HgOutgoingCommand.java	Fri Sep 30 07:59:22 2011 +0200
+++ b/src/org/tmatesoft/hg/core/HgOutgoingCommand.java	Fri Sep 30 08:00:04 2011 +0200
@@ -98,7 +98,7 @@
 		final ProgressSupport ps = getProgressSupport(null);
 		try {
 			ps.start(10);
-			return getComparator(new ProgressSupport.Sub(ps, 5), getCancelSupport(null)).getLocalOnlyRevisions();
+			return getComparator(new ProgressSupport.Sub(ps, 5), getCancelSupport(null, true)).getLocalOnlyRevisions();
 		} finally {
 			ps.done();
 		}
@@ -114,7 +114,7 @@
 			throw new IllegalArgumentException("Delegate can't be null");
 		}
 		final ProgressSupport ps = getProgressSupport(handler);
-		final CancelSupport cs = getCancelSupport(handler);
+		final CancelSupport cs = getCancelSupport(handler, true);
 		try {
 			ps.start(-1);
 			ChangesetTransformer inspector = new ChangesetTransformer(localRepo, handler, getParentHelper(), ps, cs);
--- a/src/org/tmatesoft/hg/repo/HgDataFile.java	Fri Sep 30 07:59:22 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgDataFile.java	Fri Sep 30 08:00:04 2011 +0200
@@ -615,5 +615,15 @@
 			}
 			return lastEntryStart;
 		}
+
+		@Override
+		public void checkFailed() throws HgException, IOException, CancelledException {
+			super.checkFailed();
+			if (delegate instanceof ErrorHandlingInspector) {
+				// XXX need to add ErrorDestination and pass it around (much like CancelSupport get passed)
+				// so that delegate would be able report its failures directly to caller without this hack
+				((ErrorHandlingInspector) delegate).checkFailed();
+			}
+		}
 	}
 }
--- a/test/org/tmatesoft/hg/test/TestAuxUtilities.java	Fri Sep 30 07:59:22 2011 +0200
+++ b/test/org/tmatesoft/hg/test/TestAuxUtilities.java	Fri Sep 30 08:00:04 2011 +0200
@@ -18,8 +18,12 @@
 
 import static org.tmatesoft.hg.repo.HgRepository.TIP;
 
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
 import org.junit.Assert;
 import org.junit.Test;
+import org.tmatesoft.hg.core.HgCatCommand;
 import org.tmatesoft.hg.core.Nodeid;
 import org.tmatesoft.hg.internal.ArrayHelper;
 import org.tmatesoft.hg.repo.HgChangelog;
@@ -28,6 +32,7 @@
 import org.tmatesoft.hg.repo.HgManifest.Flags;
 import org.tmatesoft.hg.repo.HgRepository;
 import org.tmatesoft.hg.util.Adaptable;
+import org.tmatesoft.hg.util.ByteChannel;
 import org.tmatesoft.hg.util.CancelSupport;
 import org.tmatesoft.hg.util.CancelledException;
 import org.tmatesoft.hg.util.Path;
@@ -115,10 +120,9 @@
 					cancelImpl.stop();
 				}
 			}
-			@SuppressWarnings("unchecked")
 			public <T> T getAdapter(Class<T> adapterClass) {
 				if (CancelSupport.class == adapterClass) {
-					return (T) cancelImpl;
+					return adapterClass.cast(cancelImpl);
 				}
 				return null;
 			}
@@ -165,10 +169,9 @@
 				return true;
 			}
 
-			@SuppressWarnings("unchecked")
 			public <T> T getAdapter(Class<T> adapterClass) {
 				if (CancelSupport.class == adapterClass) {
-					return (T) cancelImpl;
+					return adapterClass.cast(cancelImpl);
 				}
 				return null;
 			}
@@ -184,4 +187,30 @@
 		Assert.assertEquals(insp1.when2stop, insp1.lastVisitet);
 	}
 	
+	@Test
+	public void testCatCommandCancelSupport() throws Exception {
+		HgRepository repository = Configuration.get().find("branches-1"); // any repo
+		final HgCatCommand cmd = new HgCatCommand(repository);
+		cmd.file(Path.create("file1"));
+		cmd.set(new CancelSupport() {
+			int i = 0;
+			public void checkCancelled() throws CancelledException {
+				if (i++ == 2) {
+					throw new CancelledException();
+				}
+			}
+		});
+		try {
+			cmd.execute(new ByteChannel() {
+				
+				public int write(ByteBuffer buffer) throws IOException, CancelledException {
+					Assert.fail("Shall not get that far provided cancellation from command's CancelSupport is functional");
+					return 0;
+				}
+			});
+			Assert.fail("Command execution shall not fail silently, exception shall propagate");
+		} catch (CancelledException ex) {
+			// good!
+		}
+	}
 }