comparison src/org/tmatesoft/hg/repo/HgBundle.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 51d682cf9cdc
children a41d955dc360
comparison
equal deleted inserted replaced
511:122e0600799f 512:10ca3ede8367
16 */ 16 */
17 package org.tmatesoft.hg.repo; 17 package org.tmatesoft.hg.repo;
18 18
19 import java.io.File; 19 import java.io.File;
20 import java.io.IOException; 20 import java.io.IOException;
21 import java.util.ConcurrentModificationException;
21 22
22 import org.tmatesoft.hg.core.Nodeid; 23 import org.tmatesoft.hg.core.Nodeid;
23 import org.tmatesoft.hg.core.SessionContext; 24 import org.tmatesoft.hg.core.SessionContext;
24 import org.tmatesoft.hg.internal.ByteArrayChannel; 25 import org.tmatesoft.hg.internal.ByteArrayChannel;
25 import org.tmatesoft.hg.internal.ByteArrayDataAccess; 26 import org.tmatesoft.hg.internal.ByteArrayDataAccess;
27 import org.tmatesoft.hg.internal.Callback;
26 import org.tmatesoft.hg.internal.DataAccess; 28 import org.tmatesoft.hg.internal.DataAccess;
27 import org.tmatesoft.hg.internal.DataAccessProvider; 29 import org.tmatesoft.hg.internal.DataAccessProvider;
28 import org.tmatesoft.hg.internal.DigestHelper; 30 import org.tmatesoft.hg.internal.DigestHelper;
29 import org.tmatesoft.hg.internal.Experimental; 31 import org.tmatesoft.hg.internal.Experimental;
30 import org.tmatesoft.hg.internal.InflaterDataAccess; 32 import org.tmatesoft.hg.internal.InflaterDataAccess;
33 import org.tmatesoft.hg.internal.Lifecycle;
31 import org.tmatesoft.hg.internal.Patch; 34 import org.tmatesoft.hg.internal.Patch;
32 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; 35 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
36 import org.tmatesoft.hg.util.Adaptable;
33 import org.tmatesoft.hg.util.CancelledException; 37 import org.tmatesoft.hg.util.CancelledException;
34 38
35 /** 39 /**
36 * WORK IN PROGRESS 40 * WORK IN PROGRESS
37 * 41 *
44 public class HgBundle { 48 public class HgBundle {
45 49
46 private final File bundleFile; 50 private final File bundleFile;
47 private final DataAccessProvider accessProvider; 51 private final DataAccessProvider accessProvider;
48 // private final SessionContext sessionContext; 52 // private final SessionContext sessionContext;
53 private Lifecycle.BasicCallback flowControl;
49 54
50 HgBundle(SessionContext ctx, DataAccessProvider dap, File bundle) { 55 HgBundle(SessionContext ctx, DataAccessProvider dap, File bundle) {
51 // sessionContext = ctx; 56 // sessionContext = ctx;
52 accessProvider = dap; 57 accessProvider = dap;
53 bundleFile = bundle; 58 bundleFile = bundle;
184 }; 189 };
185 inspectChangelog(bundleInsp); 190 inspectChangelog(bundleInsp);
186 } 191 }
187 192
188 // callback to minimize amount of Strings and Nodeids instantiated 193 // callback to minimize amount of Strings and Nodeids instantiated
194 @Callback
189 public interface Inspector { 195 public interface Inspector {
190 void changelogStart(); 196 void changelogStart();
191 197
192 void changelogEnd(); 198 void changelogEnd();
193 199
214 */ 220 */
215 public void inspectChangelog(Inspector inspector) throws HgRuntimeException { 221 public void inspectChangelog(Inspector inspector) throws HgRuntimeException {
216 if (inspector == null) { 222 if (inspector == null) {
217 throw new IllegalArgumentException(); 223 throw new IllegalArgumentException();
218 } 224 }
225 final Lifecycle lifecycle = lifecycleSetUp(inspector);
219 DataAccess da = null; 226 DataAccess da = null;
220 try { 227 try {
221 da = getDataStream(); 228 da = getDataStream();
222 internalInspectChangelog(da, inspector); 229 internalInspectChangelog(da, inspector);
223 } catch (IOException ex) { 230 } catch (IOException ex) {
224 throw new HgInvalidFileException("Bundle.inspectChangelog failed", ex, bundleFile); 231 throw new HgInvalidFileException("Bundle.inspectChangelog failed", ex, bundleFile);
225 } finally { 232 } finally {
226 if (da != null) { 233 if (da != null) {
227 da.done(); 234 da.done();
228 } 235 }
236 lifecycleTearDown(lifecycle);
229 } 237 }
230 } 238 }
231 239
232 /** 240 /**
233 * @param inspector callback to visit manifest entries 241 * @param inspector callback to visit manifest entries
236 */ 244 */
237 public void inspectManifest(Inspector inspector) throws HgRuntimeException { 245 public void inspectManifest(Inspector inspector) throws HgRuntimeException {
238 if (inspector == null) { 246 if (inspector == null) {
239 throw new IllegalArgumentException(); 247 throw new IllegalArgumentException();
240 } 248 }
249 final Lifecycle lifecycle = lifecycleSetUp(inspector);
241 DataAccess da = null; 250 DataAccess da = null;
242 try { 251 try {
243 da = getDataStream(); 252 da = getDataStream();
244 if (da.isEmpty()) { 253 if (da.isEmpty()) {
245 return; 254 return;
250 throw new HgInvalidFileException("Bundle.inspectManifest failed", ex, bundleFile); 259 throw new HgInvalidFileException("Bundle.inspectManifest failed", ex, bundleFile);
251 } finally { 260 } finally {
252 if (da != null) { 261 if (da != null) {
253 da.done(); 262 da.done();
254 } 263 }
264 lifecycleTearDown(lifecycle);
255 } 265 }
256 } 266 }
257 267
258 /** 268 /**
259 * @param inspector callback to visit file entries 269 * @param inspector callback to visit file entries
262 */ 272 */
263 public void inspectFiles(Inspector inspector) throws HgRuntimeException { 273 public void inspectFiles(Inspector inspector) throws HgRuntimeException {
264 if (inspector == null) { 274 if (inspector == null) {
265 throw new IllegalArgumentException(); 275 throw new IllegalArgumentException();
266 } 276 }
277 final Lifecycle lifecycle = lifecycleSetUp(inspector);
267 DataAccess da = null; 278 DataAccess da = null;
268 try { 279 try {
269 da = getDataStream(); 280 da = getDataStream();
270 if (da.isEmpty()) { 281 if (da.isEmpty()) {
271 return; 282 return;
280 throw new HgInvalidFileException("Bundle.inspectFiles failed", ex, bundleFile); 291 throw new HgInvalidFileException("Bundle.inspectFiles failed", ex, bundleFile);
281 } finally { 292 } finally {
282 if (da != null) { 293 if (da != null) {
283 da.done(); 294 da.done();
284 } 295 }
296 lifecycleTearDown(lifecycle);
285 } 297 }
286 } 298 }
287 299
288 /** 300 /**
289 * @param inspector visit complete bundle (changelog, manifest and file entries) 301 * @param inspector visit complete bundle (changelog, manifest and file entries)
292 */ 304 */
293 public void inspectAll(Inspector inspector) throws HgRuntimeException { 305 public void inspectAll(Inspector inspector) throws HgRuntimeException {
294 if (inspector == null) { 306 if (inspector == null) {
295 throw new IllegalArgumentException(); 307 throw new IllegalArgumentException();
296 } 308 }
309 final Lifecycle lifecycle = lifecycleSetUp(inspector);
297 DataAccess da = null; 310 DataAccess da = null;
298 try { 311 try {
299 da = getDataStream(); 312 da = getDataStream();
300 internalInspectChangelog(da, inspector); 313 internalInspectChangelog(da, inspector);
301 internalInspectManifest(da, inspector); 314 internalInspectManifest(da, inspector);
304 throw new HgInvalidFileException("Bundle.inspectAll failed", ex, bundleFile); 317 throw new HgInvalidFileException("Bundle.inspectAll failed", ex, bundleFile);
305 } finally { 318 } finally {
306 if (da != null) { 319 if (da != null) {
307 da.done(); 320 da.done();
308 } 321 }
309 } 322 lifecycleTearDown(lifecycle);
323 }
324 }
325
326 // initialize flowControl, check for concurrent usage, starts lifecyle, if any
327 // return non-null only if inspector is interested in lifecycle events
328 private Lifecycle lifecycleSetUp(Inspector inspector) throws ConcurrentModificationException {
329 // Don't need flowControl in case Inspector doesn't implement Lifecycle,
330 // however is handy not to expect it == null inside internalInspect*
331 // XXX Once there's need to make this class thread-safe,
332 // shall move flowControl to thread-local state.
333 if (flowControl != null) {
334 throw new ConcurrentModificationException("HgBundle is in use and not thread-safe yet");
335 }
336 flowControl = new Lifecycle.BasicCallback();
337 final Lifecycle lifecycle = Adaptable.Factory.getAdapter(inspector, Lifecycle.class, null);
338 if (lifecycle != null) {
339 lifecycle.start(-1, flowControl, flowControl);
340 }
341 return lifecycle;
342 }
343
344 private void lifecycleTearDown(Lifecycle lifecycle) {
345 if (lifecycle != null) {
346 lifecycle.finish(flowControl);
347 }
348 flowControl = null;
310 } 349 }
311 350
312 private void internalInspectChangelog(DataAccess da, Inspector inspector) throws IOException { 351 private void internalInspectChangelog(DataAccess da, Inspector inspector) throws IOException {
313 if (da.isEmpty()) { 352 if (da.isEmpty()) {
314 return; 353 return;