# HG changeset patch # User Artem Tikhomirov # Date 1324006998 -3600 # Node ID 189dc6dc1c3efe0a66c4fe71c1478ff77531043a # Parent 3572fcb06473c3909451416c300e4a7e85c1a598 Use exceptions to expose errors reading mercurial data diff -r 3572fcb06473 -r 189dc6dc1c3e build.xml --- a/build.xml Sun Dec 11 00:39:07 2011 +0100 +++ b/build.xml Fri Dec 16 04:43:18 2011 +0100 @@ -27,7 +27,7 @@ - + diff -r 3572fcb06473 -r 189dc6dc1c3e cmdline/org/tmatesoft/hg/console/Main.java --- a/cmdline/org/tmatesoft/hg/console/Main.java Sun Dec 11 00:39:07 2011 +0100 +++ b/cmdline/org/tmatesoft/hg/console/Main.java Fri Dec 16 04:43:18 2011 +0100 @@ -120,44 +120,48 @@ cmd.file("file1", false); cmd.execute(new HgChangesetTreeHandler() { public void next(HgChangesetTreeHandler.TreeElement entry) { - StringBuilder sb = new StringBuilder(); - HashSet test = new HashSet(entry.childRevisions()); - for (HgChangeset cc : entry.children()) { - sb.append(cc.getRevision()); - sb.append(':'); - sb.append(cc.getNodeid().shortNotation()); - sb.append(", "); - } - final Pair parents = entry.parentRevisions(); - final boolean isJoin = !parents.first().isNull() && !parents.second().isNull(); - final boolean isFork = entry.children().size() > 1; - final HgChangeset cset = entry.changeset(); - System.out.printf("%d:%s - %s\n", cset.getRevision(), cset.getNodeid().shortNotation(), cset.getComment()); - if (!isJoin && !isFork && !entry.children().isEmpty()) { - System.out.printf("\t=> %s\n", sb); - } - if (isJoin) { - HgChangeset p1 = entry.parents().first(); - HgChangeset p2 = entry.parents().second(); - System.out.printf("\tjoin <= (%d:%s, %d:%s)", p1.getRevision(), p1.getNodeid().shortNotation(), p2.getRevision(), p2.getNodeid().shortNotation()); + try { + StringBuilder sb = new StringBuilder(); + HashSet test = new HashSet(entry.childRevisions()); + for (HgChangeset cc : entry.children()) { + sb.append(cc.getRevision()); + sb.append(':'); + sb.append(cc.getNodeid().shortNotation()); + sb.append(", "); + } + final Pair parents = entry.parentRevisions(); + final boolean isJoin = !parents.first().isNull() && !parents.second().isNull(); + final boolean isFork = entry.children().size() > 1; + final HgChangeset cset = entry.changeset(); + System.out.printf("%d:%s - %s\n", cset.getRevision(), cset.getNodeid().shortNotation(), cset.getComment()); + if (!isJoin && !isFork && !entry.children().isEmpty()) { + System.out.printf("\t=> %s\n", sb); + } + if (isJoin) { + HgChangeset p1 = entry.parents().first(); + HgChangeset p2 = entry.parents().second(); + System.out.printf("\tjoin <= (%d:%s, %d:%s)", p1.getRevision(), p1.getNodeid().shortNotation(), p2.getRevision(), p2.getNodeid().shortNotation()); + if (isFork) { + System.out.print(", "); + } + } if (isFork) { - System.out.print(", "); + if (!isJoin) { + System.out.print('\t'); + } + System.out.printf("fork => [%s]", sb); } - } - if (isFork) { - if (!isJoin) { - System.out.print('\t'); + if (isJoin || isFork) { + System.out.println(); } - System.out.printf("fork => [%s]", sb); - } - if (isJoin || isFork) { - System.out.println(); + } catch (HgException ex) { + ex.printStackTrace(); } } }); } - private void buildFileLogOld() { + private void buildFileLogOld() throws Exception { final HgDataFile fn = hgRepo.getFileNode("file1"); final int[] fileChangesetRevisions = new int[fn.getRevisionCount()]; fn.history(new HgChangelog.Inspector() { @@ -165,22 +169,26 @@ private int[] parentRevisions = new int[2]; public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) { - fileChangesetRevisions[fileLocalRevisions] = revisionNumber; - fn.parents(fileLocalRevisions, parentRevisions, null, null); - boolean join = parentRevisions[0] != -1 && parentRevisions[1] != -1; - if (join) { - System.out.print("join["); + try { + fileChangesetRevisions[fileLocalRevisions] = revisionNumber; + fn.parents(fileLocalRevisions, parentRevisions, null, null); + boolean join = parentRevisions[0] != -1 && parentRevisions[1] != -1; + if (join) { + System.out.print("join["); + } + if (parentRevisions[0] != -1) { + System.out.printf("%2d->%2d, ", fileChangesetRevisions[parentRevisions[0]], revisionNumber); + } + if (parentRevisions[1] != -1) { + System.out.printf("%2d->%2d, ", fileChangesetRevisions[parentRevisions[1]], revisionNumber); + } + if (join) { + System.out.print("]"); + } + fileLocalRevisions++; + } catch (HgException ex) { + ex.printStackTrace(); } - if (parentRevisions[0] != -1) { - System.out.printf("%2d->%2d, ", fileChangesetRevisions[parentRevisions[0]], revisionNumber); - } - if (parentRevisions[1] != -1) { - System.out.printf("%2d->%2d, ", fileChangesetRevisions[parentRevisions[1]], revisionNumber); - } - if (join) { - System.out.print("]"); - } - fileLocalRevisions++; } }); System.out.println(); @@ -307,7 +315,7 @@ * RevlogStream with separate iterate(int[] sortedRevisions,...) * RevlogStream.ReaderN1.range(): 185 380 ms */ - private void testEffectiveFileLog() { + private void testEffectiveFileLog() throws Exception { for (String fname : cmdLineOpts.getList("")) { System.out.println(fname); final long start = System.currentTimeMillis(); @@ -381,7 +389,7 @@ * First, single run - 18 563 * 10 runs (after 1 warm up) of HgBranches.collect took 167391 ms, ~17 seconds per run. */ - private void dumpBranches() { + private void dumpBranches() throws Exception { final long start0 = System.currentTimeMillis(); HgBranches b = hgRepo.getBranches(); System.out.println("1:" + (System.currentTimeMillis() - start0)); @@ -476,7 +484,7 @@ } } - private void dumpCompleteManifestLow() { + private void dumpCompleteManifestLow() throws Exception { hgRepo.getManifest().walk(0, TIP, new ManifestDump()); } @@ -500,7 +508,7 @@ } } - private void dumpCompleteManifestHigh() { + private void dumpCompleteManifestHigh() throws Exception { new HgManifestCommand(hgRepo).dirs(true).execute(new HgManifestCommand.Handler() { public void begin(Nodeid manifestRevision) { diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/core/HgChangeset.java --- a/src/org/tmatesoft/hg/core/HgChangeset.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/core/HgChangeset.java Fri Dec 16 04:43:18 2011 +0100 @@ -116,36 +116,37 @@ return rv; } - public List getModifiedFiles() { + public List getModifiedFiles() throws HgInvalidControlFileException { if (modifiedFiles == null) { initFileChanges(); } return modifiedFiles; } - public List getAddedFiles() { + public List getAddedFiles() throws HgInvalidControlFileException { if (addedFiles == null) { initFileChanges(); } return addedFiles; } - public List getRemovedFiles() { + public List getRemovedFiles() throws HgInvalidControlFileException { if (deletedFiles == null) { initFileChanges(); } return deletedFiles; } - public boolean isMerge() { + public boolean isMerge() throws HgInvalidControlFileException { // p1 == -1 and p2 != -1 is legitimate case return !(getFirstParentRevision().isNull() || getSecondParentRevision().isNull()); } /** * @return never null + * @throws HgInvalidControlFileException FIXME */ - public Nodeid getFirstParentRevision() { + public Nodeid getFirstParentRevision() throws HgInvalidControlFileException { if (parentHelper != null) { return parentHelper.safeFirstParent(nodeid); } @@ -160,8 +161,9 @@ /** * @return never null + * @throws HgInvalidControlFileException FIXME */ - public Nodeid getSecondParentRevision() { + public Nodeid getSecondParentRevision() throws HgInvalidControlFileException { if (parentHelper != null) { return parentHelper.safeSecondParent(nodeid); } @@ -184,7 +186,7 @@ } } - private /*synchronized*/ void initFileChanges() { + private /*synchronized*/ void initFileChanges() throws HgInvalidControlFileException { ArrayList deleted = new ArrayList(); ArrayList modified = new ArrayList(); ArrayList added = new ArrayList(); diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/core/HgChangesetTreeHandler.java --- a/src/org/tmatesoft/hg/core/HgChangesetTreeHandler.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/core/HgChangesetTreeHandler.java Fri Dec 16 04:43:18 2011 +0100 @@ -40,10 +40,12 @@ * @return revision of the revlog being iterated. */ public Nodeid fileRevision(); + /** * @return changeset associated with the current revision + * @throws HgException indicates failure dealing with Mercurial data */ - public HgChangeset changeset(); + public HgChangeset changeset() throws HgException; /** * Lightweight alternative to {@link #changeset()}, identifies changeset in which current file node has been modified @@ -54,8 +56,9 @@ /** * Node, these are not necessarily in direct relation to parents of changeset from {@link #changeset()} * @return changesets that correspond to parents of the current file node, either pair element may be null. + * @throws HgException indicates failure dealing with Mercurial data */ - public Pair parents(); + public Pair parents() throws HgException; /** * Lightweight alternative to {@link #parents()}, give {@link Nodeid nodeids} only @@ -63,7 +66,12 @@ */ public Pair parentRevisions(); - public Collection children(); + /** + * Changes that originate from the given change and bear it as their parent. + * @return collection (possibly empty) of immediate children of the change + * @throws HgException indicates failure dealing with Mercurial data + */ + public Collection children() throws HgException; /** * Lightweight alternative to {@link #children()}. diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/core/HgDataStreamException.java --- a/src/org/tmatesoft/hg/core/HgDataStreamException.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/core/HgDataStreamException.java Fri Dec 16 04:43:18 2011 +0100 @@ -20,7 +20,8 @@ import org.tmatesoft.hg.util.Path; /** - * Any erroneous state with @link {@link HgDataFile} input/output, read/write operations + * Any erroneous state with @link {@link HgDataFile} input/output, read/write operations + * FIXME/REVISIT if HgInvalidControlFileExceptio and HgInvalidFileException is not sufficient? Is there real need for all 3? * * @author Artem Tikhomirov * @author TMate Software Ltd. diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/core/HgIncomingCommand.java --- a/src/org/tmatesoft/hg/core/HgIncomingCommand.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/core/HgIncomingCommand.java Fri Dec 16 04:43:18 2011 +0100 @@ -100,9 +100,10 @@ * * @return list of nodes present at remote and missing locally * @throws HgRemoteConnectionException when failed to communicate with remote repository + * @throws HgInvalidControlFileException FIXME * @throws CancelledException */ - public List executeLite() throws HgRemoteConnectionException, CancelledException { + public List executeLite() throws HgRemoteConnectionException, HgInvalidControlFileException, CancelledException { LinkedHashSet result = new LinkedHashSet(); RepositoryComparator repoCompare = getComparator(); for (BranchChain bc : getMissingBranches()) { @@ -121,11 +122,12 @@ * Full information about incoming changes * * @throws HgRemoteConnectionException when failed to communicate with remote repository + * @throws HgInvalidControlFileException FIXME * @throws HgInvalidFileException to indicate failure working with locally downloaded changes in a bundle file * @throws HgCallbackTargetException to re-throw exception from the handler * @throws CancelledException */ - public void executeFull(final HgChangesetHandler handler) throws HgRemoteConnectionException, HgInvalidFileException, HgCallbackTargetException, CancelledException { + public void executeFull(final HgChangesetHandler handler) throws HgRemoteConnectionException, HgInvalidControlFileException, HgInvalidFileException, HgCallbackTargetException, CancelledException { if (handler == null) { throw new IllegalArgumentException("Delegate can't be null"); } @@ -161,7 +163,7 @@ } } - private RepositoryComparator getComparator() throws CancelledException { + private RepositoryComparator getComparator() throws HgInvalidControlFileException, CancelledException { if (remoteRepo == null) { throw new IllegalArgumentException("Shall specify remote repository to compare against", null); } @@ -172,7 +174,7 @@ return comparator; } - private HgChangelog.ParentWalker getParentHelper() { + private HgChangelog.ParentWalker getParentHelper() throws HgInvalidControlFileException { if (parentHelper == null) { parentHelper = localRepo.getChangelog().new ParentWalker(); parentHelper.init(); @@ -180,14 +182,14 @@ return parentHelper; } - private List getMissingBranches() throws HgRemoteConnectionException, CancelledException { + private List getMissingBranches() throws HgRemoteConnectionException, HgInvalidControlFileException, CancelledException { if (missingBranches == null) { missingBranches = getComparator().calculateMissingBranches(); } return missingBranches; } - private List getCommon() throws HgRemoteConnectionException, CancelledException { + private List getCommon() throws HgRemoteConnectionException, HgInvalidControlFileException, CancelledException { // return getComparator(context).getCommon(); final LinkedHashSet common = new LinkedHashSet(); // XXX common can be obtained from repoCompare, but at the moment it would almost duplicate work of calculateMissingBranches diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/core/HgLogCommand.java --- a/src/org/tmatesoft/hg/core/HgLogCommand.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/core/HgLogCommand.java Fri Dec 16 04:43:18 2011 +0100 @@ -259,7 +259,7 @@ } } - public void execute(HgChangesetTreeHandler handler) throws CancelledException { + public void execute(HgChangesetTreeHandler handler) throws CancelledException, HgException { if (handler == null) { throw new IllegalArgumentException(); } @@ -291,7 +291,7 @@ completeHistory[revisionNumber] = new HistoryNode(commitRevisions[revisionNumber], revision, p1, p2); } - HistoryNode[] go(HgDataFile fileNode) { + HistoryNode[] go(HgDataFile fileNode) throws HgInvalidControlFileException { completeHistory = new HistoryNode[fileNode.getRevisionCount()]; commitRevisions = new int[completeHistory.length]; fileNode.walk(0, TIP, this); @@ -358,7 +358,7 @@ csetTransform.next(revisionNumber, nodeid, cset); } - private HgChangelog.ParentWalker getParentHelper(boolean create) { + private HgChangelog.ParentWalker getParentHelper(boolean create) throws HgInvalidControlFileException { if (parentHelper == null && create) { parentHelper = repo.getChangelog().new ParentWalker(); parentHelper.init(); @@ -451,11 +451,11 @@ return historyNode.fileRevision; } - public HgChangeset changeset() { + public HgChangeset changeset() throws HgException { return get(historyNode.changeset)[0]; } - public Pair parents() { + public Pair parents() throws HgException { if (parents != null) { return parents; } @@ -475,7 +475,7 @@ return parents = new Pair(r[0], r[1]); } - public Collection children() { + public Collection children() throws HgException { if (children != null) { return children; } @@ -496,7 +496,7 @@ cachedChangesets.put(cs.getRevision(), cs); } - private HgChangeset[] get(int... changelogRevisionNumber) { + private HgChangeset[] get(int... changelogRevisionNumber) throws HgInvalidControlFileException { HgChangeset[] rv = new HgChangeset[changelogRevisionNumber.length]; IntVector misses = new IntVector(changelogRevisionNumber.length, -1); for (int i = 0; i < changelogRevisionNumber.length; i++) { @@ -537,7 +537,7 @@ } // init only when needed - void initTransform() { + void initTransform() throws HgInvalidControlFileException { if (transform == null) { transform = new ChangesetTransformer.Transformation(new HgStatusCollector(repo)/*XXX try to reuse from context?*/, getParentHelper(false)); } diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/core/HgManifestCommand.java --- a/src/org/tmatesoft/hg/core/HgManifestCommand.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/core/HgManifestCommand.java Fri Dec 16 04:43:18 2011 +0100 @@ -101,7 +101,7 @@ * @throws IllegalArgumentException if handler is null * @throws ConcurrentModificationException if this command is already in use (running) */ - public void execute(Handler handler) { + public void execute(Handler handler) throws HgException { if (handler == null) { throw new IllegalArgumentException(); } diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/core/HgOutgoingCommand.java --- a/src/org/tmatesoft/hg/core/HgOutgoingCommand.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/core/HgOutgoingCommand.java Fri Dec 16 04:43:18 2011 +0100 @@ -93,8 +93,11 @@ * Reported changes are from any branch (limits set by {@link #branch(String)} are not taken into account. * * @return list on local nodes known to be missing at remote server + * @throws HgRemoteConnectionException FIXME + * @throws HgInvalidControlFileException FIXME + * @throws CancelledException FIXME */ - public List executeLite() throws HgRemoteConnectionException, CancelledException { + public List executeLite() throws HgRemoteConnectionException, HgInvalidControlFileException, CancelledException { final ProgressSupport ps = getProgressSupport(null); try { ps.start(10); @@ -126,7 +129,7 @@ } } - private RepositoryComparator getComparator(ProgressSupport ps, CancelSupport cs) throws HgRemoteConnectionException, CancelledException { + private RepositoryComparator getComparator(ProgressSupport ps, CancelSupport cs) throws HgRemoteConnectionException, HgInvalidControlFileException, CancelledException { if (remoteRepo == null) { throw new IllegalArgumentException("Shall specify remote repository to compare against"); } @@ -137,7 +140,7 @@ return comparator; } - private HgChangelog.ParentWalker getParentHelper() { + private HgChangelog.ParentWalker getParentHelper() throws HgInvalidControlFileException { if (parentHelper == null) { parentHelper = localRepo.getChangelog().new ParentWalker(); parentHelper.init(); diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/internal/RevlogStream.java --- a/src/org/tmatesoft/hg/internal/RevlogStream.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/internal/RevlogStream.java Fri Dec 16 04:43:18 2011 +0100 @@ -24,6 +24,7 @@ import java.util.zip.Inflater; import org.tmatesoft.hg.core.HgBadStateException; +import org.tmatesoft.hg.core.HgException; import org.tmatesoft.hg.core.HgInvalidControlFileException; import org.tmatesoft.hg.core.HgInvalidRevisionException; import org.tmatesoft.hg.core.Nodeid; @@ -181,7 +182,7 @@ // should be possible to use TIP, ALL, or -1, -2, -n notation of Hg // ? boolean needsNodeid - public void iterate(int start, int end, boolean needData, Inspector inspector) throws HgInvalidRevisionException { + public void iterate(int start, int end, boolean needData, Inspector inspector) throws HgInvalidRevisionException, HgInvalidControlFileException /*REVISIT - too general exception*/ { initOutline(); final int indexSize = revisionCount(); if (indexSize == 0) { @@ -201,7 +202,11 @@ r.start(end - start + 1); r.range(start, end); } catch (IOException ex) { - throw new HgBadStateException(ex); // FIXME need better handling + throw new HgInvalidControlFileException(String.format("Failed reading [%d..%d]", start, end), ex, indexFile); + } catch (HgInvalidControlFileException ex) { + throw ex; + } catch (HgException ex) { + throw new HgInvalidControlFileException(String.format("Failed reading [%d..%d]", start, end), ex, indexFile); } finally { r.finish(); } @@ -214,7 +219,7 @@ * @param needData whether inspector needs access to header only * @param inspector callback to process entries */ - public void iterate(int[] sortedRevisions, boolean needData, Inspector inspector) throws HgInvalidRevisionException { + public void iterate(int[] sortedRevisions, boolean needData, Inspector inspector) throws HgInvalidRevisionException, HgInvalidControlFileException /*REVISIT - too general exception*/ { final int indexSize = revisionCount(); if (indexSize == 0 || sortedRevisions.length == 0) { return; @@ -245,7 +250,13 @@ } } } catch (IOException ex) { - throw new HgBadStateException(ex); // FIXME need better handling + final int c = sortedRevisions.length; + throw new HgInvalidControlFileException(String.format("Failed reading %d revisions in [%d; %d]",c, sortedRevisions[0], sortedRevisions[c-1]), ex, indexFile); + } catch (HgInvalidControlFileException ex) { + throw ex; + } catch (HgException ex) { + final int c = sortedRevisions.length; + throw new HgInvalidControlFileException(String.format("Failed reading %d revisions in [%d; %d]",c, sortedRevisions[0], sortedRevisions[c-1]), ex, indexFile); } finally { r.finish(); } @@ -337,7 +348,7 @@ } } } catch (IOException ex) { - ex.printStackTrace(); // log error + ex.printStackTrace(); // FIXME, log error is not enough // too bad, no outline then, but don't fail with NPE baseRevisions = new int[0]; } finally { @@ -347,7 +358,7 @@ /** * operation with single file open/close and multiple diverse reads. - * XXX initOutline might need similar extraction to keen N1 format knowledge + * XXX initOutline might need similar extraction to keep N1 format knowledge */ class ReaderN1 { private final Inspector inspector; @@ -393,7 +404,7 @@ // System.out.printf("applyTime:%d ms, inspectorTime: %d ms\n", applyTime, inspectorTime); // TIMING } - public boolean range(int start, int end) throws IOException { + public boolean range(int start, int end) throws IOException, HgException { byte[] nodeidBuf = new byte[20]; int i; // it (i.e. replace with i >= start) @@ -517,6 +528,6 @@ // XXX boolean retVal to indicate whether to continue? // TODO specify nodeid and data length, and reuse policy (i.e. if revlog stream doesn't reuse nodeid[] for each call) // implementers shall not invoke DataAccess.done(), it's accomplished by #iterate at appropraite moment - void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[/*20*/] nodeid, DataAccess data); + void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[/*20*/] nodeid, DataAccess data) throws HgException; } } diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/repo/HgBranches.java --- a/src/org/tmatesoft/hg/repo/HgBranches.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgBranches.java Fri Dec 16 04:43:18 2011 +0100 @@ -125,7 +125,7 @@ return -1; // deliberately not lastInCache, to avoid anything but -1 when 1st line was read and there's error is in lines 2..end } - void collect(final ProgressSupport ps) { + void collect(final ProgressSupport ps) throws HgInvalidControlFileException { branches.clear(); ps.start(1 + repo.getChangelog().getRevisionCount() * 2); // @@ -299,7 +299,7 @@ this(branchName, Nodeid.NULL, branchHeads); } - void validate(HgChangelog clog, HgChangelog.RevisionMap rmap) { + void validate(HgChangelog clog, HgChangelog.RevisionMap rmap) throws HgInvalidControlFileException { int[] localCset = new int[heads.size()]; int i = 0; for (Nodeid h : heads) { diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/repo/HgChangelog.java --- a/src/org/tmatesoft/hg/repo/HgChangelog.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgChangelog.java Fri Dec 16 04:43:18 2011 +0100 @@ -31,7 +31,8 @@ import java.util.Map; import java.util.TimeZone; -import org.tmatesoft.hg.core.HgBadStateException; +import org.tmatesoft.hg.core.HgBadArgumentException; +import org.tmatesoft.hg.core.HgException; import org.tmatesoft.hg.core.HgInvalidControlFileException; import org.tmatesoft.hg.core.HgInvalidRevisionException; import org.tmatesoft.hg.core.Nodeid; @@ -56,18 +57,18 @@ super(hgRepo, content); } - public void all(final HgChangelog.Inspector inspector) throws HgInvalidRevisionException { + public void all(final HgChangelog.Inspector inspector) throws HgInvalidRevisionException, HgInvalidControlFileException { range(0, getLastRevision(), inspector); } - public void range(int start, int end, final HgChangelog.Inspector inspector) throws HgInvalidRevisionException { + public void range(int start, int end, final HgChangelog.Inspector inspector) throws HgInvalidRevisionException, HgInvalidControlFileException { if (inspector == null) { throw new IllegalArgumentException(); } content.iterate(start, end, true, new RawCsetParser(inspector)); } - public List range(int start, int end) throws HgInvalidRevisionException { + public List range(int start, int end) throws HgInvalidRevisionException, HgInvalidControlFileException { final RawCsetCollector c = new RawCsetCollector(end - start + 1); range(start, end, c); return c.result; @@ -79,7 +80,7 @@ * @param inspector callback to get changesets * @param revisions revisions to read, unrestricted ordering. */ - public void range(final HgChangelog.Inspector inspector, final int... revisions) throws HgInvalidRevisionException { + public void range(final HgChangelog.Inspector inspector, final int... revisions) throws HgInvalidRevisionException, HgInvalidControlFileException { Arrays.sort(revisions); rangeInternal(inspector, revisions); } @@ -87,7 +88,7 @@ /** * Friends-only version of {@link #range(Inspector, int...)}, when callers know array is sorted */ - /*package-local*/ void rangeInternal(HgChangelog.Inspector inspector, int[] sortedRevisions) throws HgInvalidRevisionException { + /*package-local*/ void rangeInternal(HgChangelog.Inspector inspector, int[] sortedRevisions) throws HgInvalidRevisionException, HgInvalidControlFileException { if (sortedRevisions == null || sortedRevisions.length == 0) { return; } @@ -238,7 +239,7 @@ } } - /*package*/ static RawChangeset parse(DataAccess da) throws IOException { + /*package*/ static RawChangeset parse(DataAccess da) throws IOException, HgBadArgumentException { byte[] data = da.byteArray(); RawChangeset rv = new RawChangeset(); rv.init(data, 0, data.length, null); @@ -246,18 +247,18 @@ } // @param usersPool - it's likely user names get repeated again and again throughout repository. can be null - // FIXME throws "Error reading changeset data" - /* package-local */void init(byte[] data, int offset, int length, Pool usersPool) { + // FIXME replace HgBadArgumentException with HgInvalidDataFormatException or HgInvalidControlFileException + /* package-local */void init(byte[] data, int offset, int length, Pool usersPool) throws HgBadArgumentException { final int bufferEndIndex = offset + length; final byte lineBreak = (byte) '\n'; int breakIndex1 = indexOf(data, lineBreak, offset, bufferEndIndex); if (breakIndex1 == -1) { - throw new IllegalArgumentException("Bad Changeset data"); + throw new HgBadArgumentException("Bad Changeset data", null); } Nodeid _nodeid = Nodeid.fromAscii(data, 0, breakIndex1); int breakIndex2 = indexOf(data, lineBreak, breakIndex1 + 1, bufferEndIndex); if (breakIndex2 == -1) { - throw new IllegalArgumentException("Bad Changeset data"); + throw new HgBadArgumentException("Bad Changeset data", null); } String _user = new String(data, breakIndex1 + 1, breakIndex2 - breakIndex1 - 1); if (usersPool != null) { @@ -265,12 +266,12 @@ } int breakIndex3 = indexOf(data, lineBreak, breakIndex2 + 1, bufferEndIndex); if (breakIndex3 == -1) { - throw new IllegalArgumentException("Bad Changeset data"); + throw new HgBadArgumentException("Bad Changeset data", null); } String _timeString = new String(data, breakIndex2 + 1, breakIndex3 - breakIndex2 - 1); int space1 = _timeString.indexOf(' '); if (space1 == -1) { - throw new IllegalArgumentException("Bad Changeset data"); + throw new HgBadArgumentException(String.format("Bad Changeset data: %s in [%d..%d]", "time string", breakIndex2+1, breakIndex3), null); } int space2 = _timeString.indexOf(' ', space1 + 1); if (space2 == -1) { @@ -316,7 +317,7 @@ } } if (breakIndex4 == -1 || breakIndex4 >= bufferEndIndex) { - throw new IllegalArgumentException("Bad Changeset data"); + throw new HgBadArgumentException("Bad Changeset data", null); } } else { breakIndex4--; @@ -327,7 +328,8 @@ // FIXME respect ui.fallbackencoding and try to decode if set } catch (UnsupportedEncodingException ex) { _comment = ""; - throw new IllegalStateException("Could hardly happen"); + // Could hardly happen + throw new HgBadArgumentException("Bad Changeset data", ex); } // change this instance at once, don't leave it partially changes in case of error this.manifest = _nodeid; @@ -384,15 +386,15 @@ progressHelper = ProgressSupport.Factory.get(delegate); } - public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) { + public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) throws HgException { try { byte[] data = da.byteArray(); cset.init(data, 0, data.length, usersPool); // XXX there's no guarantee for Changeset.Callback that distinct instance comes each time, consider instance reuse inspector.next(revisionNumber, Nodeid.fromBinary(nodeid, 0), cset); progressHelper.worked(1); - } catch (Exception ex) { - throw new HgBadStateException(ex); // FIXME exception handling + } catch (IOException ex) { + throw new HgException(ex); // XXX need better exception, perhaps smth like HgChangelogException (extends HgInvalidControlFileException) } if (iterateControl != null) { iterateControl.checkCancelled(); diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/repo/HgDataFile.java --- a/src/org/tmatesoft/hg/repo/HgDataFile.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgDataFile.java Fri Dec 16 04:43:18 2011 +0100 @@ -127,7 +127,7 @@ * @throws HgDataStreamException to indicate troubles reading repository file * @throws CancelledException if operation was cancelled */ - public void workingCopy(ByteChannel sink) throws HgDataStreamException, CancelledException { + public void workingCopy(ByteChannel sink) throws HgDataStreamException, HgInvalidControlFileException, CancelledException { File f = getRepo().getFile(this); if (f.exists()) { final CancelSupport cs = CancelSupport.Factory.get(sink); @@ -190,7 +190,7 @@ // } /*XXX not sure distinct method contentWithFilters() is the best way to do, perhaps, callers shall add filters themselves?*/ - public void contentWithFilters(int revision, ByteChannel sink) throws HgDataStreamException, CancelledException, HgInvalidRevisionException { + public void contentWithFilters(int revision, ByteChannel sink) throws HgDataStreamException, HgInvalidControlFileException, CancelledException, HgInvalidRevisionException { if (revision == WORKING_COPY) { workingCopy(sink); // pass un-mangled sink } else { @@ -200,7 +200,7 @@ // for data files need to check heading of the file content for possible metadata // @see http://mercurial.selenic.com/wiki/FileFormats#data.2BAC8- - public void content(int revision, ByteChannel sink) throws HgDataStreamException, CancelledException, HgInvalidRevisionException { + public void content(int revision, ByteChannel sink) throws HgDataStreamException, HgInvalidControlFileException, CancelledException, HgInvalidRevisionException { if (revision == TIP) { revision = getLastRevision(); } @@ -277,7 +277,7 @@ * @deprecated use {@link HgLogCommand#execute(org.tmatesoft.hg.core.HgChangesetTreeHandler)} instead */ @Deprecated - public void history(HgChangelog.TreeInspector inspector) { + public void history(HgChangelog.TreeInspector inspector) throws HgInvalidControlFileException{ final CancelSupport cancelSupport = CancelSupport.Factory.get(inspector); try { final boolean[] needsSorting = { false }; @@ -359,11 +359,11 @@ } } - public void history(HgChangelog.Inspector inspector) { + public void history(HgChangelog.Inspector inspector) throws HgInvalidControlFileException { history(0, getLastRevision(), inspector); } - public void history(int start, int end, HgChangelog.Inspector inspector) throws HgInvalidRevisionException { + public void history(int start, int end, HgChangelog.Inspector inspector) throws HgInvalidRevisionException, HgInvalidControlFileException { if (!exists()) { throw new IllegalStateException("Can't get history of invalid repository file node"); } @@ -484,6 +484,8 @@ }); } catch (CancelledException ex) { // it's ok, we did that + } catch (HgInvalidControlFileException ex) { + throw new HgDataStreamException(getPath(), ex); } } @@ -581,7 +583,7 @@ setCancelSupport(CancelSupport.Factory.get(chain)); } - public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { + public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) throws HgException { try { final int daLength = data.length(); if (daLength < 4 || data.readByte() != 1 || data.readByte() != 10) { diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/repo/HgManifest.java --- a/src/org/tmatesoft/hg/repo/HgManifest.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgManifest.java Fri Dec 16 04:43:18 2011 +0100 @@ -25,7 +25,7 @@ import java.util.HashMap; import java.util.Map; -import org.tmatesoft.hg.core.HgBadStateException; +import org.tmatesoft.hg.core.HgException; import org.tmatesoft.hg.core.HgInvalidControlFileException; import org.tmatesoft.hg.core.Nodeid; import org.tmatesoft.hg.internal.DataAccess; @@ -102,7 +102,7 @@ * @param end changelog (not manifest!) revision to stop, inclusive. * @param inspector can't be null */ - public void walk(int start, int end, final Inspector inspector) { + public void walk(int start, int end, final Inspector inspector) throws /*FIXME HgInvalidRevisionException,*/ HgInvalidControlFileException { if (inspector == null) { throw new IllegalArgumentException(); } @@ -123,7 +123,7 @@ * @param inspector * @param localRevisions local changeset revisions to visit */ - public void walk(final Inspector inspector, int... localRevisions) { + public void walk(final Inspector inspector, int... localRevisions) throws HgInvalidControlFileException{ if (inspector == null || localRevisions == null) { throw new IllegalArgumentException(); } @@ -132,7 +132,7 @@ } // manifest revision number that corresponds to the given changeset - /*package-local*/ int fromChangelog(int revisionNumber) { + /*package-local*/ int fromChangelog(int revisionNumber) throws HgInvalidControlFileException { if (HgInternals.wrongLocalRevision(revisionNumber)) { throw new IllegalArgumentException(String.valueOf(revisionNumber)); } @@ -155,19 +155,19 @@ * @return file revision or null if manifest at specified revision doesn't list such file */ @Experimental(reason="Perhaps, HgDataFile shall own this method, or get a delegate?") - public Nodeid getFileRevision(int localChangelogRevision, final Path file) { + public Nodeid getFileRevision(int localChangelogRevision, final Path file) throws HgInvalidControlFileException{ return getFileRevisions(file, localChangelogRevision).get(localChangelogRevision); } // XXX package-local, IntMap, and HgDataFile getFileRevisionAt(int... localChangelogRevisions) @Experimental(reason="@see #getFileRevision") - public Map getFileRevisions(final Path file, int... localChangelogRevisions) { + public Map getFileRevisions(final Path file, int... localChangelogRevisions) throws HgInvalidControlFileException{ // FIXME need tests int[] localManifestRevisions = toLocalManifestRevisions(localChangelogRevisions); final HashMap rv = new HashMap(localChangelogRevisions.length); content.iterate(localManifestRevisions, true, new RevlogStream.Inspector() { - public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { + public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) throws HgException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { byte b; @@ -191,7 +191,7 @@ } } } catch (IOException ex) { - throw new HgBadStateException(ex); + throw new HgException(ex); } } }); @@ -199,7 +199,7 @@ } - private int[] toLocalManifestRevisions(int[] localChangelogRevisions) { + private int[] toLocalManifestRevisions(int[] localChangelogRevisions) throws HgInvalidControlFileException { int[] localManifestRevs = new int[localChangelogRevisions.length]; boolean needsSort = false; for (int i = 0; i < localChangelogRevisions.length; i++) { @@ -318,7 +318,7 @@ progressHelper = ProgressSupport.Factory.get(delegate); } - public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) { + public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) throws HgException { try { if (!inspector.begin(revisionNumber, new Nodeid(nodeid, true), linkRevision)) { iterateControl.stop(); @@ -392,7 +392,7 @@ iterateControl.checkCancelled(); progressHelper.worked(1); } catch (IOException ex) { - throw new HgBadStateException(ex); + throw new HgException(ex); } } @@ -472,10 +472,10 @@ } } for (int u : undefinedChangelogRevision) { - Nodeid manifest = repo.getChangelog().range(u, u).get(0).manifest(); - // FIXME calculate those missing effectively (e.g. cache and sort nodeids to speed lookup - // right away in the #next (may refactor ParentWalker's sequential and sorted into dedicated helper and reuse here) try { + Nodeid manifest = repo.getChangelog().range(u, u).get(0).manifest(); + // FIXME calculate those missing effectively (e.g. cache and sort nodeids to speed lookup + // right away in the #next (may refactor ParentWalker's sequential and sorted into dedicated helper and reuse here) changelog2manifest[u] = repo.getManifest().getLocalRevision(manifest); } catch (HgInvalidControlFileException ex) { // FIXME need to propagate the error up to client diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/repo/HgRepository.java --- a/src/org/tmatesoft/hg/repo/HgRepository.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgRepository.java Fri Dec 16 04:43:18 2011 +0100 @@ -208,7 +208,7 @@ return tags; } - public HgBranches getBranches() { + public HgBranches getBranches() throws HgInvalidControlFileException { if (branches == null) { branches = new HgBranches(this); branches.collect(ProgressSupport.Factory.get(null)); diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/repo/HgStatusCollector.java --- a/src/org/tmatesoft/hg/repo/HgStatusCollector.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgStatusCollector.java Fri Dec 16 04:43:18 2011 +0100 @@ -75,7 +75,7 @@ return repo; } - private ManifestRevision get(int rev) { + private ManifestRevision get(int rev) throws HgInvalidControlFileException { ManifestRevision i = cache.get(rev); if (i == null) { if (rev == -1) { @@ -100,7 +100,7 @@ } } - private void initCacheRange(int minRev, int maxRev) { + private void initCacheRange(int minRev, int maxRev) throws HgInvalidControlFileException { ensureCacheSize(); // In fact, walk(minRev, maxRev) doesn't imply // there would be maxRev-minRev+1 revisions visited. For example, @@ -159,7 +159,7 @@ return fakeEmptyRev; } - /*package-local*/ ManifestRevision raw(int rev) { + /*package-local*/ ManifestRevision raw(int rev) throws HgInvalidControlFileException { return get(rev); } /*package-local*/ PathPool getPathPool() { @@ -186,7 +186,7 @@ } // hg status --change - public void change(int rev, HgStatusInspector inspector) { + public void change(int rev, HgStatusInspector inspector) throws /*FIXME HInvalidRevisionException,*/ HgInvalidControlFileException { int[] parents = new int[2]; repo.getChangelog().parents(rev, parents, null, null); walk(parents[0], rev, inspector); @@ -196,7 +196,7 @@ // Either rev1 or rev2 may be -1 to indicate comparison to empty repository (XXX this is due to use of // parents in #change(), I believe. Perhaps, need a constant for this? Otherwise this hidden knowledge gets // exposed to e.g. Record - public void walk(int rev1, int rev2, HgStatusInspector inspector) { + public void walk(int rev1, int rev2, HgStatusInspector inspector) throws /*FIXME HInvalidRevisionException,*/ HgInvalidControlFileException { if (rev1 == rev2) { throw new IllegalArgumentException(); } @@ -284,7 +284,7 @@ } } - public Record status(int rev1, int rev2) { + public Record status(int rev1, int rev2) throws /*FIXME HInvalidRevisionException,*/ HgInvalidControlFileException { Record rv = new Record(); walk(rev1, rev2, rv); return rv; @@ -347,7 +347,7 @@ statusHelper = self; } - public Nodeid nodeidBeforeChange(Path fname) { + public Nodeid nodeidBeforeChange(Path fname) throws HgInvalidControlFileException { if (statusHelper == null || startRev == BAD_REVISION) { return null; } @@ -356,7 +356,7 @@ } return statusHelper.raw(startRev).nodeid(fname); } - public Nodeid nodeidAfterChange(Path fname) { + public Nodeid nodeidAfterChange(Path fname) throws HgInvalidControlFileException { if (statusHelper == null || endRev == BAD_REVISION) { return null; } diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java --- a/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Fri Dec 16 04:43:18 2011 +0100 @@ -122,7 +122,7 @@ return dirstate; } - private ManifestRevision getManifest(int changelogLocalRev) { + private ManifestRevision getManifest(int changelogLocalRev) throws HgInvalidControlFileException { assert changelogLocalRev >= 0; ManifestRevision mr; if (baseRevisionCollector != null) { diff -r 3572fcb06473 -r 189dc6dc1c3e src/org/tmatesoft/hg/repo/Revlog.java --- a/src/org/tmatesoft/hg/repo/Revlog.java Sun Dec 11 00:39:07 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/Revlog.java Fri Dec 16 04:43:18 2011 +0100 @@ -99,7 +99,7 @@ * @throws HgInvalidRevisionException if supplied argument doesn't represent revision index in this revlog * @throws HgInvalidControlFileException if access to revlog index/data entry failed */ - public final Nodeid getRevision(int revision) throws HgInvalidControlFileException, HgInvalidRevisionException { + public final Nodeid getRevision(int revision) throws HgInvalidRevisionException, HgInvalidControlFileException { // XXX cache nodeids? Rather, if context.getCache(this).getRevisionMap(create == false) != null, use it return Nodeid.fromBinary(content.nodeid(revision), 0); } @@ -107,14 +107,14 @@ /** * FIXME need to be careful about (1) ordering of the revisions in the return list; (2) modifications (sorting) of the argument array */ - public final List getRevisions(int... revisions) throws HgInvalidRevisionException { + public final List getRevisions(int... revisions) throws HgInvalidRevisionException, HgInvalidControlFileException { ArrayList rv = new ArrayList(revisions.length); Arrays.sort(revisions); getRevisionsInternal(rv, revisions); return rv; } - /*package-local*/ void getRevisionsInternal(final List retVal, int[] sortedRevs) throws HgInvalidRevisionException { + /*package-local*/ void getRevisionsInternal(final List retVal, int[] sortedRevs) throws HgInvalidRevisionException, HgInvalidControlFileException { // once I have getRevisionMap and may find out whether it is avalable from cache, // may use it, perhaps only for small number of revisions content.iterate(sortedRevs, false, new RevlogStream.Inspector() { @@ -196,7 +196,7 @@ * @throws HgInvalidRevisionException * @throws IllegalArgumentException */ - public void parents(int revision, int[] parentRevisions, byte[] parent1, byte[] parent2) throws HgInvalidRevisionException { + public void parents(int revision, int[] parentRevisions, byte[] parent1, byte[] parent2) throws HgInvalidRevisionException, HgInvalidControlFileException { if (revision != TIP && !(revision >= 0 && revision < content.revisionCount())) { throw new HgInvalidRevisionException(revision); } @@ -245,7 +245,7 @@ } @Experimental - public void walk(int start, int end, final Revlog.Inspector inspector) throws HgInvalidRevisionException { + public void walk(int start, int end, final Revlog.Inspector inspector) throws HgInvalidRevisionException, HgInvalidControlFileException { int lastRev = getLastRevision(); if (start == TIP) { start = lastRev; @@ -332,7 +332,7 @@ } } - public void init() { + public void init() throws HgInvalidControlFileException { final int revisionCount = Revlog.this.getRevisionCount(); firstParent = new Nodeid[revisionCount]; // although branches/merges are less frequent, and most of secondParent would be -1/null, some sort of @@ -519,7 +519,7 @@ /** * @return this for convenience. */ - public RevisionMap init(/*XXX Pool to reuse nodeids, if possible. */) { + public RevisionMap init(/*XXX Pool to reuse nodeids, if possible. */) throws HgInvalidControlFileException{ // XXX HgRepository.register((RepoChangeListener) this); // listen to changes in repo, re-init if needed? final int revisionCount = Revlog.this.getRevisionCount(); sequential = new Nodeid[revisionCount]; diff -r 3572fcb06473 -r 189dc6dc1c3e test/org/tmatesoft/hg/test/MapTagsToFileRevisions.java --- a/test/org/tmatesoft/hg/test/MapTagsToFileRevisions.java Sun Dec 11 00:39:07 2011 +0100 +++ b/test/org/tmatesoft/hg/test/MapTagsToFileRevisions.java Fri Dec 16 04:43:18 2011 +0100 @@ -339,7 +339,7 @@ } } - private void collectTagsPerFile_Approach_2(HgRepository repository, final int[] tagLocalRevs, final IntMap> tagLocalRev2TagInfo, TagInfo[] allTags, Path targetPath) { + private void collectTagsPerFile_Approach_2(HgRepository repository, final int[] tagLocalRevs, final IntMap> tagLocalRev2TagInfo, TagInfo[] allTags, Path targetPath) throws HgException { // // Approach 2. No all-file map. Collect file revisions recorded at the time of tagging, // then for each file revision check if it is among those above, and if yes, take corresponding tags