comparison src/org/tmatesoft/hg/core/HgLogCommand.java @ 423:9c9c442b5f2e

Major refactoring of exception handling. Low-level API uses RuntimeExceptions, while checked are left for higher level
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 23 Mar 2012 22:51:18 +0100
parents 7f136a3fa671
children 6437d261048a
comparison
equal deleted inserted replaced
422:5d1cc7366d04 423:9c9c442b5f2e
33 import org.tmatesoft.hg.internal.IntVector; 33 import org.tmatesoft.hg.internal.IntVector;
34 import org.tmatesoft.hg.repo.HgChangelog; 34 import org.tmatesoft.hg.repo.HgChangelog;
35 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; 35 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
36 import org.tmatesoft.hg.repo.HgDataFile; 36 import org.tmatesoft.hg.repo.HgDataFile;
37 import org.tmatesoft.hg.repo.HgInternals; 37 import org.tmatesoft.hg.repo.HgInternals;
38 import org.tmatesoft.hg.repo.HgInvalidControlFileException;
39 import org.tmatesoft.hg.repo.HgInvalidRevisionException;
40 import org.tmatesoft.hg.repo.HgInvalidStateException;
38 import org.tmatesoft.hg.repo.HgRepository; 41 import org.tmatesoft.hg.repo.HgRepository;
42 import org.tmatesoft.hg.repo.HgRuntimeException;
39 import org.tmatesoft.hg.repo.HgStatusCollector; 43 import org.tmatesoft.hg.repo.HgStatusCollector;
40 import org.tmatesoft.hg.util.CancelSupport; 44 import org.tmatesoft.hg.util.CancelSupport;
41 import org.tmatesoft.hg.util.CancelledException; 45 import org.tmatesoft.hg.util.CancelledException;
42 import org.tmatesoft.hg.util.Pair; 46 import org.tmatesoft.hg.util.Pair;
43 import org.tmatesoft.hg.util.Path; 47 import org.tmatesoft.hg.util.Path;
183 return file(Path.create(repo.getToRepoPathHelper().rewrite(file)), followCopyRename); 187 return file(Path.create(repo.getToRepoPathHelper().rewrite(file)), followCopyRename);
184 } 188 }
185 189
186 /** 190 /**
187 * Similar to {@link #execute(HgChangesetHandler)}, collects and return result as a list. 191 * Similar to {@link #execute(HgChangesetHandler)}, collects and return result as a list.
192 * @throws HgException FIXME EXCEPTIONS
188 */ 193 */
189 public List<HgChangeset> execute() throws HgException { 194 public List<HgChangeset> execute() throws HgException {
190 CollectHandler collector = new CollectHandler(); 195 CollectHandler collector = new CollectHandler();
191 try { 196 try {
192 execute(collector); 197 execute(collector);
198 } catch (HgCallbackTargetException ex) {
199 // see below for CanceledException
200 HgInvalidStateException t = new HgInvalidStateException("Internal error");
201 t.initCause(ex);
202 throw t;
193 } catch (CancelledException ex) { 203 } catch (CancelledException ex) {
194 // can't happen as long as our CollectHandler doesn't throw any exception 204 // can't happen as long as our CollectHandler doesn't throw any exception
195 throw new HgBadStateException(ex); 205 HgInvalidStateException t = new HgInvalidStateException("Internal error");
206 t.initCause(ex);
207 throw t;
196 } 208 }
197 return collector.getChanges(); 209 return collector.getChanges();
198 } 210 }
199 211
200 /** 212 /**
201 * Iterate over range of changesets configured in the command. 213 * Iterate over range of changesets configured in the command.
202 * 214 *
203 * @param handler callback to process changesets. 215 * @param handler callback to process changesets.
204 * @throws HgCallbackTargetException to re-throw exception from the handler 216 * @throws HgCallbackTargetException wrapper for any exception user callback code may produce
205 * @throws HgInvalidControlFileException if access to revlog index/data entry failed 217 * @throws HgInvalidControlFileException if access to revlog index/data entry failed
206 * @throws HgException in case of some other library issue 218 * @throws HgException in case of some other library issue
207 * @throws CancelledException if execution of the command was cancelled 219 * @throws CancelledException if execution of the command was cancelled
208 * @throws IllegalArgumentException when inspector argument is null 220 * @throws IllegalArgumentException when inspector argument is null
209 * @throws ConcurrentModificationException if this log command instance is already running 221 * @throws ConcurrentModificationException if this log command instance is already running
235 // even if we do not follow history, report file rename 247 // even if we do not follow history, report file rename
236 do { 248 do {
237 if (handler instanceof FileHistoryHandler) { 249 if (handler instanceof FileHistoryHandler) {
238 HgFileRevision src = new HgFileRevision(repo, fileNode.getCopySourceRevision(), null, fileNode.getCopySourceName()); 250 HgFileRevision src = new HgFileRevision(repo, fileNode.getCopySourceRevision(), null, fileNode.getCopySourceName());
239 HgFileRevision dst = new HgFileRevision(repo, fileNode.getRevision(0), null, fileNode.getPath(), src.getPath()); 251 HgFileRevision dst = new HgFileRevision(repo, fileNode.getRevision(0), null, fileNode.getPath(), src.getPath());
240 try { 252 ((FileHistoryHandler) handler).copy(src, dst);
241 ((FileHistoryHandler) handler).copy(src, dst);
242 } catch (HgCallbackTargetException.Wrap ex) {
243 throw new HgCallbackTargetException(ex).setRevision(fileNode.getCopySourceRevision()).setFileName(fileNode.getCopySourceName());
244 }
245 } 253 }
246 if (limit > 0 && count >= limit) { 254 if (limit > 0 && count >= limit) {
247 // if limit reach, follow is useless. 255 // if limit reach, follow is useless.
248 break; 256 break;
249 } 257 }
329 progressHelper.worked(1); 337 progressHelper.worked(1);
330 ph2 = new ProgressSupport.Sub(progressHelper, 2); 338 ph2 = new ProgressSupport.Sub(progressHelper, 2);
331 } else { 339 } else {
332 ph2 = new ProgressSupport.Sub(progressHelper, 3); 340 ph2 = new ProgressSupport.Sub(progressHelper, 3);
333 } 341 }
334 try { 342 ph2.start(completeHistory.length);
335 ph2.start(completeHistory.length); 343 // XXX shall sort completeHistory according to changeset numbers?
336 // XXX shall sort completeHistory according to changeset numbers? 344 for (int i = 0; i < completeHistory.length; i++ ) {
337 for (int i = 0; i < completeHistory.length; i++ ) { 345 final HistoryNode n = completeHistory[i];
338 final HistoryNode n = completeHistory[i]; 346 handler.next(ei.init(n));
339 handler.next(ei.init(n)); 347 ph2.worked(1);
340 ph2.worked(1); 348 cancelHelper.checkCancelled();
341 cancelHelper.checkCancelled();
342 }
343 } catch (HgCallbackTargetException.Wrap ex) {
344 throw new HgCallbackTargetException(ex);
345 } 349 }
346 progressHelper.done(); 350 progressHelper.done();
347 } 351 }
348 352
349 // 353 //
397 * @author TMate Software Ltd. 401 * @author TMate Software Ltd.
398 */ 402 */
399 public interface FileHistoryHandler extends HgChangesetHandler { // FIXME move to stanalone class file, perhaps? 403 public interface FileHistoryHandler extends HgChangesetHandler { // FIXME move to stanalone class file, perhaps?
400 // XXX perhaps, should distinguish copy from rename? And what about merged revisions and following them? 404 // XXX perhaps, should distinguish copy from rename? And what about merged revisions and following them?
401 /** 405 /**
402 * @throws HgCallbackTargetException.Wrap wrapper object for any exception user code may produce. Wrapped exception would get re-thrown with {@link HgCallbackTargetException} 406 * @throws HgCallbackTargetException wrapper object for any exception user code may produce
403 */ 407 */
404 void copy(HgFileRevision from, HgFileRevision to) throws HgCallbackTargetException.Wrap; 408 void copy(HgFileRevision from, HgFileRevision to) throws HgCallbackTargetException;
405 } 409 }
406 410
407 public static class CollectHandler implements HgChangesetHandler { 411 public static class CollectHandler implements HgChangesetHandler {
408 private final List<HgChangeset> result = new LinkedList<HgChangeset>(); 412 private final List<HgChangeset> result = new LinkedList<HgChangeset>();
409 413
469 473
470 public Nodeid fileRevision() { 474 public Nodeid fileRevision() {
471 return historyNode.fileRevision; 475 return historyNode.fileRevision;
472 } 476 }
473 477
474 public HgChangeset changeset() throws HgException { 478 public HgChangeset changeset() {
475 return get(historyNode.changeset)[0]; 479 return get(historyNode.changeset)[0];
476 } 480 }
477 481
478 public Pair<HgChangeset, HgChangeset> parents() throws HgException { 482 public Pair<HgChangeset, HgChangeset> parents() {
479 if (parents != null) { 483 if (parents != null) {
480 return parents; 484 return parents;
481 } 485 }
482 HistoryNode p; 486 HistoryNode p;
483 final int p1, p2; 487 final int p1, p2;
493 } 497 }
494 HgChangeset[] r = get(p1, p2); 498 HgChangeset[] r = get(p1, p2);
495 return parents = new Pair<HgChangeset, HgChangeset>(r[0], r[1]); 499 return parents = new Pair<HgChangeset, HgChangeset>(r[0], r[1]);
496 } 500 }
497 501
498 public Collection<HgChangeset> children() throws HgException { 502 public Collection<HgChangeset> children() {
499 if (children != null) { 503 if (children != null) {
500 return children; 504 return children;
501 } 505 }
502 if (historyNode.children == null) { 506 if (historyNode.children == null) {
503 children = Collections.emptyList(); 507 children = Collections.emptyList();
514 518
515 void populate(HgChangeset cs) { 519 void populate(HgChangeset cs) {
516 cachedChangesets.put(cs.getRevisionIndex(), cs); 520 cachedChangesets.put(cs.getRevisionIndex(), cs);
517 } 521 }
518 522
519 private HgChangeset[] get(int... changelogRevisionIndex) throws HgException { 523 private HgChangeset[] get(int... changelogRevisionIndex) {
520 HgChangeset[] rv = new HgChangeset[changelogRevisionIndex.length]; 524 HgChangeset[] rv = new HgChangeset[changelogRevisionIndex.length];
521 IntVector misses = new IntVector(changelogRevisionIndex.length, -1); 525 IntVector misses = new IntVector(changelogRevisionIndex.length, -1);
522 for (int i = 0; i < changelogRevisionIndex.length; i++) { 526 for (int i = 0; i < changelogRevisionIndex.length; i++) {
523 if (changelogRevisionIndex[i] == -1) { 527 if (changelogRevisionIndex[i] == -1) {
524 rv[i] = null; 528 rv[i] = null;
536 initTransform(); 540 initTransform();
537 repo.getChangelog().range(this, changesets2read); 541 repo.getChangelog().range(this, changesets2read);
538 for (int changeset2read : changesets2read) { 542 for (int changeset2read : changesets2read) {
539 HgChangeset cs = cachedChangesets.get(changeset2read); 543 HgChangeset cs = cachedChangesets.get(changeset2read);
540 if (cs == null) { 544 if (cs == null) {
541 throw new HgException(String.format("Can't get changeset for revision %d", changeset2read)); 545 HgInvalidStateException t = new HgInvalidStateException(String.format("Can't get changeset for revision %d", changeset2read));
546 throw t.setRevisionIndex(changeset2read);
542 } 547 }
543 // HgChangelog.range may reorder changesets according to their order in the changelog 548 // HgChangelog.range may reorder changesets according to their order in the changelog
544 // thus need to find original index 549 // thus need to find original index
545 boolean sanity = false; 550 boolean sanity = false;
546 for (int i = 0; i < changelogRevisionIndex.length; i++) { 551 for (int i = 0; i < changelogRevisionIndex.length; i++) {
558 } 563 }
559 return rv; 564 return rv;
560 } 565 }
561 566
562 // init only when needed 567 // init only when needed
563 void initTransform() throws HgInvalidControlFileException { 568 void initTransform() throws HgRuntimeException {
564 if (transform == null) { 569 if (transform == null) {
565 transform = new ChangesetTransformer.Transformation(new HgStatusCollector(repo)/*XXX try to reuse from context?*/, getParentHelper(false)); 570 transform = new ChangesetTransformer.Transformation(new HgStatusCollector(repo)/*XXX try to reuse from context?*/, getParentHelper(false));
566 } 571 }
567 } 572 }
568 573
569 public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) { 574 public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) {
570 HgChangeset cs = transform.handle(revisionNumber, nodeid, cset); 575 HgChangeset cs = transform.handle(revisionNumber, nodeid, cset);
571 populate(cs.clone()); 576 populate(cs.clone());
572 } 577 }
573 578
574 public Nodeid changesetRevision() throws HgException { 579 public Nodeid changesetRevision() {
575 if (changesetRevision == null) { 580 if (changesetRevision == null) {
576 changesetRevision = getRevision(historyNode.changeset); 581 changesetRevision = getRevision(historyNode.changeset);
577 } 582 }
578 return changesetRevision; 583 return changesetRevision;
579 } 584 }
580 585
581 public Pair<Nodeid, Nodeid> parentRevisions() throws HgException { 586 public Pair<Nodeid, Nodeid> parentRevisions() {
582 if (parentRevisions == null) { 587 if (parentRevisions == null) {
583 HistoryNode p; 588 HistoryNode p;
584 final Nodeid p1, p2; 589 final Nodeid p1, p2;
585 if ((p = historyNode.parent1) != null) { 590 if ((p = historyNode.parent1) != null) {
586 p1 = getRevision(p.changeset); 591 p1 = getRevision(p.changeset);
595 parentRevisions = new Pair<Nodeid, Nodeid>(p1, p2); 600 parentRevisions = new Pair<Nodeid, Nodeid>(p1, p2);
596 } 601 }
597 return parentRevisions; 602 return parentRevisions;
598 } 603 }
599 604
600 public Collection<Nodeid> childRevisions() throws HgException { 605 public Collection<Nodeid> childRevisions() {
601 if (childRevisions != null) { 606 if (childRevisions != null) {
602 return childRevisions; 607 return childRevisions;
603 } 608 }
604 if (historyNode.children == null) { 609 if (historyNode.children == null) {
605 childRevisions = Collections.emptyList(); 610 childRevisions = Collections.emptyList();
612 } 617 }
613 return childRevisions; 618 return childRevisions;
614 } 619 }
615 620
616 // reading nodeid involves reading index only, guess, can afford not to optimize multiple reads 621 // reading nodeid involves reading index only, guess, can afford not to optimize multiple reads
617 private Nodeid getRevision(int changelogRevisionNumber) throws HgInvalidControlFileException { 622 private Nodeid getRevision(int changelogRevisionNumber) {
618 // TODO [post-1.0] pipe through pool 623 // TODO post-1.0 pipe through pool
619 HgChangeset cs = cachedChangesets.get(changelogRevisionNumber); 624 HgChangeset cs = cachedChangesets.get(changelogRevisionNumber);
620 if (cs != null) { 625 if (cs != null) {
621 return cs.getNodeid(); 626 return cs.getNodeid();
622 } else { 627 } else {
623 return repo.getChangelog().getRevision(changelogRevisionNumber); 628 return repo.getChangelog().getRevision(changelogRevisionNumber);