comparison 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
comparison
equal deleted inserted replaced
511:122e0600799f 512:10ca3ede8367
31 import java.util.zip.DeflaterOutputStream; 31 import java.util.zip.DeflaterOutputStream;
32 32
33 import org.tmatesoft.hg.internal.ByteArrayDataAccess; 33 import org.tmatesoft.hg.internal.ByteArrayDataAccess;
34 import org.tmatesoft.hg.internal.DataAccess; 34 import org.tmatesoft.hg.internal.DataAccess;
35 import org.tmatesoft.hg.internal.DigestHelper; 35 import org.tmatesoft.hg.internal.DigestHelper;
36 import org.tmatesoft.hg.internal.Lifecycle;
36 import org.tmatesoft.hg.internal.RepoInitializer; 37 import org.tmatesoft.hg.internal.RepoInitializer;
37 import org.tmatesoft.hg.repo.HgBundle; 38 import org.tmatesoft.hg.repo.HgBundle;
38 import org.tmatesoft.hg.repo.HgBundle.GroupElement; 39 import org.tmatesoft.hg.repo.HgBundle.GroupElement;
39 import org.tmatesoft.hg.repo.HgInvalidControlFileException; 40 import org.tmatesoft.hg.repo.HgInvalidControlFileException;
40 import org.tmatesoft.hg.repo.HgInvalidFileException; 41 import org.tmatesoft.hg.repo.HgInvalidFileException;
41 import org.tmatesoft.hg.repo.HgInvalidStateException; 42 import org.tmatesoft.hg.repo.HgInvalidStateException;
42 import org.tmatesoft.hg.repo.HgLookup; 43 import org.tmatesoft.hg.repo.HgLookup;
43 import org.tmatesoft.hg.repo.HgRemoteRepository; 44 import org.tmatesoft.hg.repo.HgRemoteRepository;
44 import org.tmatesoft.hg.repo.HgRepository; 45 import org.tmatesoft.hg.repo.HgRepository;
45 import org.tmatesoft.hg.repo.HgRuntimeException; 46 import org.tmatesoft.hg.repo.HgRuntimeException;
47 import org.tmatesoft.hg.util.CancelSupport;
46 import org.tmatesoft.hg.util.CancelledException; 48 import org.tmatesoft.hg.util.CancelledException;
47 import org.tmatesoft.hg.util.PathRewrite; 49 import org.tmatesoft.hg.util.PathRewrite;
50 import org.tmatesoft.hg.util.ProgressSupport;
48 51
49 /** 52 /**
50 * WORK IN PROGRESS, DO NOT USE 53 * WORK IN PROGRESS, DO NOT USE
51 * 54 *
52 * @author Artem Tikhomirov 55 * @author Artem Tikhomirov
99 throw new HgBadArgumentException(String.format("% shall be empty", destination), null); 102 throw new HgBadArgumentException(String.format("% shall be empty", destination), null);
100 } 103 }
101 } else { 104 } else {
102 destination.mkdirs(); 105 destination.mkdirs();
103 } 106 }
107 ProgressSupport progress = getProgressSupport(null);
108 CancelSupport cancel = getCancelSupport(null, true);
109 cancel.checkCancelled();
104 // if cloning remote repo, which can stream and no revision is specified - 110 // if cloning remote repo, which can stream and no revision is specified -
105 // can use 'stream_out' wireproto 111 // can use 'stream_out' wireproto
106 // 112 //
107 // pull all changes from the very beginning 113 // pull all changes from the very beginning
108 // XXX consult getContext() if by any chance has a bundle ready, if not, then read and register 114 // XXX consult getContext() if by any chance has a bundle ready, if not, then read and register
109 HgBundle completeChanges = srcRepo.getChanges(Collections.singletonList(NULL)); 115 HgBundle completeChanges = srcRepo.getChanges(Collections.singletonList(NULL));
110 WriteDownMate mate = new WriteDownMate(srcRepo.getSessionContext(), destination); 116 cancel.checkCancelled();
117 WriteDownMate mate = new WriteDownMate(srcRepo.getSessionContext(), destination, progress, cancel);
111 try { 118 try {
112 // instantiate new repo in the destdir 119 // instantiate new repo in the destdir
113 mate.initEmptyRepository(); 120 mate.initEmptyRepository();
114 // pull changes 121 // pull changes
115 completeChanges.inspectAll(mate); 122 completeChanges.inspectAll(mate);
123 mate.checkFailure();
116 mate.complete(); 124 mate.complete();
117 } catch (IOException ex) { 125 } catch (IOException ex) {
118 throw new HgInvalidFileException(getClass().getName(), ex); 126 throw new HgInvalidFileException(getClass().getName(), ex);
119 } finally { 127 } finally {
120 completeChanges.unlink(); 128 completeChanges.unlink();
129 progress.done();
121 } 130 }
122 return new HgLookup().detect(destination); 131 return new HgLookup().detect(destination);
123 } 132 }
124 133
125 134
126 // 1. process changelog, memorize nodeids to index 135 // 1. process changelog, memorize nodeids to index
127 // 2. process manifest, using map from step 3, collect manifest nodeids 136 // 2. process manifest, using map from step 3, collect manifest nodeids
128 // 3. process every file, using map from 3, and consult set from step 4 to ensure repo is correct 137 // 3. process every file, using map from 3, and consult set from step 4 to ensure repo is correct
129 private static class WriteDownMate implements HgBundle.Inspector { 138 private static class WriteDownMate implements HgBundle.Inspector, Lifecycle {
130 private final File hgDir; 139 private final File hgDir;
131 private final PathRewrite storagePathHelper; 140 private final PathRewrite storagePathHelper;
141 private final ProgressSupport progressSupport;
142 private final CancelSupport cancelSupport;
132 private FileOutputStream indexFile; 143 private FileOutputStream indexFile;
133 private String filename; // human-readable name of the file being written, for log/exception purposes 144 private String filename; // human-readable name of the file being written, for log/exception purposes
134 145
135 private final TreeMap<Nodeid, Integer> changelogIndexes = new TreeMap<Nodeid, Integer>(); 146 private final TreeMap<Nodeid, Integer> changelogIndexes = new TreeMap<Nodeid, Integer>();
136 private boolean collectChangelogIndexes = false; 147 private boolean collectChangelogIndexes = false;
141 private final DigestHelper dh = new DigestHelper(); 152 private final DigestHelper dh = new DigestHelper();
142 private final ArrayList<Nodeid> revisionSequence = new ArrayList<Nodeid>(); // last visited nodes first 153 private final ArrayList<Nodeid> revisionSequence = new ArrayList<Nodeid>(); // last visited nodes first
143 154
144 private final LinkedList<String> fncacheFiles = new LinkedList<String>(); 155 private final LinkedList<String> fncacheFiles = new LinkedList<String>();
145 private RepoInitializer repoInit; 156 private RepoInitializer repoInit;
146 157 private Lifecycle.Callback lifecycleCallback;
147 public WriteDownMate(SessionContext ctx, File destDir) { 158 private CancelledException cancelException;
159
160 public WriteDownMate(SessionContext ctx, File destDir, ProgressSupport progress, CancelSupport cancel) {
148 hgDir = new File(destDir, ".hg"); 161 hgDir = new File(destDir, ".hg");
149 repoInit = new RepoInitializer(); 162 repoInit = new RepoInitializer();
150 repoInit.setRequires(STORE | FNCACHE | DOTENCODE); 163 repoInit.setRequires(STORE | FNCACHE | DOTENCODE);
151 storagePathHelper = repoInit.buildDataFilesHelper(ctx); 164 storagePathHelper = repoInit.buildDataFilesHelper(ctx);
165 progressSupport = progress;
166 cancelSupport = cancel;
152 } 167 }
153 168
154 public void initEmptyRepository() throws IOException { 169 public void initEmptyRepository() throws IOException {
155 repoInit.initEmptyRepository(hgDir); 170 repoInit.initEmptyRepository(hgDir);
156 } 171 }
345 String m = String.format("Failed to write revision %s of file %s", ge.node().shortNotation(), filename); 360 String m = String.format("Failed to write revision %s of file %s", ge.node().shortNotation(), filename);
346 throw new HgInvalidControlFileException(m, ex, new File(filename)); 361 throw new HgInvalidControlFileException(m, ex, new File(filename));
347 } 362 }
348 return true; 363 return true;
349 } 364 }
350 } 365
351 366 public void start(int count, Callback callback, Object token) {
367 progressSupport.start(count);
368 lifecycleCallback = callback;
369 }
370
371 public void finish(Object token) {
372 progressSupport.done();
373 lifecycleCallback = null;
374 }
375
376 public void checkFailure() throws CancelledException {
377 if (cancelException != null) {
378 throw cancelException;
379 }
380 }
381
382 private void stopIfCancelled() {
383 try {
384 cancelSupport.checkCancelled();
385 return;
386 } catch (CancelledException ex) {
387 cancelException = ex;
388 lifecycleCallback.stop();
389 }
390 }
391 }
352 } 392 }