diff src/org/tmatesoft/hg/core/HgCloneCommand.java @ 512:10ca3ede8367

Issue 39: Progress and Cancel support for Clone command
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 14 Dec 2012 20:10:15 +0100
parents b3c16d1aede0
children a41d955dc360
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/core/HgCloneCommand.java	Fri Dec 14 15:39:49 2012 +0100
+++ b/src/org/tmatesoft/hg/core/HgCloneCommand.java	Fri Dec 14 20:10:15 2012 +0100
@@ -33,6 +33,7 @@
 import org.tmatesoft.hg.internal.ByteArrayDataAccess;
 import org.tmatesoft.hg.internal.DataAccess;
 import org.tmatesoft.hg.internal.DigestHelper;
+import org.tmatesoft.hg.internal.Lifecycle;
 import org.tmatesoft.hg.internal.RepoInitializer;
 import org.tmatesoft.hg.repo.HgBundle;
 import org.tmatesoft.hg.repo.HgBundle.GroupElement;
@@ -43,8 +44,10 @@
 import org.tmatesoft.hg.repo.HgRemoteRepository;
 import org.tmatesoft.hg.repo.HgRepository;
 import org.tmatesoft.hg.repo.HgRuntimeException;
+import org.tmatesoft.hg.util.CancelSupport;
 import org.tmatesoft.hg.util.CancelledException;
 import org.tmatesoft.hg.util.PathRewrite;
+import org.tmatesoft.hg.util.ProgressSupport;
 
 /**
  * WORK IN PROGRESS, DO NOT USE
@@ -101,23 +104,29 @@
 		} else {
 			destination.mkdirs();
 		}
+		ProgressSupport progress = getProgressSupport(null);
+		CancelSupport cancel = getCancelSupport(null, true);
+		cancel.checkCancelled();
 		// if cloning remote repo, which can stream and no revision is specified -
 		// can use 'stream_out' wireproto
 		//
 		// pull all changes from the very beginning
-		// XXX consult getContext() if by any chance has a bundle ready, if not, then read and register 
+		// XXX consult getContext() if by any chance has a bundle ready, if not, then read and register
 		HgBundle completeChanges = srcRepo.getChanges(Collections.singletonList(NULL));
-		WriteDownMate mate = new WriteDownMate(srcRepo.getSessionContext(), destination);
+		cancel.checkCancelled();
+		WriteDownMate mate = new WriteDownMate(srcRepo.getSessionContext(), destination, progress, cancel);
 		try {
 			// instantiate new repo in the destdir
 			mate.initEmptyRepository();
 			// pull changes
 			completeChanges.inspectAll(mate);
+			mate.checkFailure();
 			mate.complete();
 		} catch (IOException ex) {
 			throw new HgInvalidFileException(getClass().getName(), ex);
 		} finally {
 			completeChanges.unlink();
+			progress.done();
 		}
 		return new HgLookup().detect(destination);
 	}
@@ -126,9 +135,11 @@
 	// 1. process changelog, memorize nodeids to index
 	// 2. process manifest, using map from step 3, collect manifest nodeids
 	// 3. process every file, using map from 3, and consult set from step 4 to ensure repo is correct
-	private static class WriteDownMate implements HgBundle.Inspector {
+	private static class WriteDownMate implements HgBundle.Inspector, Lifecycle {
 		private final File hgDir;
 		private final PathRewrite storagePathHelper;
+		private final ProgressSupport progressSupport;
+		private final CancelSupport cancelSupport;
 		private FileOutputStream indexFile;
 		private String filename; // human-readable name of the file being written, for log/exception purposes 
 
@@ -143,12 +154,16 @@
 
 		private final LinkedList<String> fncacheFiles = new LinkedList<String>();
 		private RepoInitializer repoInit;
+		private Lifecycle.Callback lifecycleCallback;
+		private CancelledException cancelException;
 
-		public WriteDownMate(SessionContext ctx, File destDir) {
+		public WriteDownMate(SessionContext ctx, File destDir, ProgressSupport progress, CancelSupport cancel) {
 			hgDir = new File(destDir, ".hg");
 			repoInit = new RepoInitializer();
 			repoInit.setRequires(STORE | FNCACHE | DOTENCODE);
 			storagePathHelper = repoInit.buildDataFilesHelper(ctx);
+			progressSupport = progress;
+			cancelSupport = cancel;
 		}
 
 		public void initEmptyRepository() throws IOException {
@@ -347,6 +362,31 @@
 			}
 			return true;
 		}
+
+		public void start(int count, Callback callback, Object token) {
+			progressSupport.start(count);
+			lifecycleCallback = callback;
+		}
+
+		public void finish(Object token) {
+			progressSupport.done();
+			lifecycleCallback = null;
+		}
+		
+		public void checkFailure() throws CancelledException {
+			if (cancelException != null) {
+				throw cancelException;
+			}
+		}
+		
+		private void stopIfCancelled() {
+			try {
+				cancelSupport.checkCancelled();
+				return;
+			} catch (CancelledException ex) {
+				cancelException = ex;
+				lifecycleCallback.stop();
+			}
+		}
 	}
-
 }