Mercurial > hg4j
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); |