# HG changeset patch # User Artem Tikhomirov # Date 1317362404 -7200 # Node ID d68dcb3b5f4903816807101d75631ee77099060d # Parent ac38e75c9e8ed850461db60a97e921404446f3c8 Propagate command's CancelSupport to low-level API. CancelSupport from context got priority over one from command diff -r ac38e75c9e8e -r d68dcb3b5f49 src/org/tmatesoft/hg/core/HgAbstractCommand.java --- 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; } } diff -r ac38e75c9e8e -r d68dcb3b5f49 src/org/tmatesoft/hg/core/HgCatCommand.java --- 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 getAdapter(Class 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; + } } } diff -r ac38e75c9e8e -r d68dcb3b5f49 src/org/tmatesoft/hg/core/HgIncomingCommand.java --- 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; diff -r ac38e75c9e8e -r d68dcb3b5f49 src/org/tmatesoft/hg/core/HgLogCommand.java --- 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); diff -r ac38e75c9e8e -r d68dcb3b5f49 src/org/tmatesoft/hg/core/HgOutgoingCommand.java --- 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); diff -r ac38e75c9e8e -r d68dcb3b5f49 src/org/tmatesoft/hg/repo/HgDataFile.java --- 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(); + } + } } } diff -r ac38e75c9e8e -r d68dcb3b5f49 test/org/tmatesoft/hg/test/TestAuxUtilities.java --- 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 getAdapter(Class adapterClass) { if (CancelSupport.class == adapterClass) { - return (T) cancelImpl; + return adapterClass.cast(cancelImpl); } return null; } @@ -165,10 +169,9 @@ return true; } - @SuppressWarnings("unchecked") public T getAdapter(Class 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! + } + } }