changeset 366:189dc6dc1c3e

Use exceptions to expose errors reading mercurial data
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 16 Dec 2011 04:43:18 +0100
parents 3572fcb06473
children 2fadf8695f8a
files build.xml cmdline/org/tmatesoft/hg/console/Main.java src/org/tmatesoft/hg/core/HgChangeset.java src/org/tmatesoft/hg/core/HgChangesetTreeHandler.java src/org/tmatesoft/hg/core/HgDataStreamException.java src/org/tmatesoft/hg/core/HgIncomingCommand.java src/org/tmatesoft/hg/core/HgLogCommand.java src/org/tmatesoft/hg/core/HgManifestCommand.java src/org/tmatesoft/hg/core/HgOutgoingCommand.java src/org/tmatesoft/hg/internal/RevlogStream.java src/org/tmatesoft/hg/repo/HgBranches.java src/org/tmatesoft/hg/repo/HgChangelog.java src/org/tmatesoft/hg/repo/HgDataFile.java src/org/tmatesoft/hg/repo/HgManifest.java src/org/tmatesoft/hg/repo/HgRepository.java src/org/tmatesoft/hg/repo/HgStatusCollector.java src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java src/org/tmatesoft/hg/repo/Revlog.java test/org/tmatesoft/hg/test/MapTagsToFileRevisions.java
diffstat 19 files changed, 185 insertions(+), 146 deletions(-) [+]
line wrap: on
line diff
--- 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 @@
 
 	<property name="junit.jar" value="lib/junit-4.8.2.jar" />
 	<property name="ver.qualifier" value="" />
-	<property name="version.lib" value="0.5.0" />
+	<property name="version.lib" value="0.8.0" />
 	<property name="version.jar" value="${version.lib}${ver.qualifier}" />
 	<property name="compile-with-debug" value="yes"/>
 
--- 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<Nodeid> test = new HashSet<Nodeid>(entry.childRevisions());
-				for (HgChangeset cc : entry.children()) {
-					sb.append(cc.getRevision());
-					sb.append(':');
-					sb.append(cc.getNodeid().shortNotation());
-					sb.append(", ");
-				}
-				final Pair<Nodeid, Nodeid> 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<Nodeid> test = new HashSet<Nodeid>(entry.childRevisions());
+					for (HgChangeset cc : entry.children()) {
+						sb.append(cc.getRevision());
+						sb.append(':');
+						sb.append(cc.getNodeid().shortNotation());
+						sb.append(", ");
+					}
+					final Pair<Nodeid, Nodeid> 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) {
--- 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<HgFileRevision> getModifiedFiles() {
+	public List<HgFileRevision> getModifiedFiles() throws HgInvalidControlFileException {
 		if (modifiedFiles == null) {
 			initFileChanges();
 		}
 		return modifiedFiles;
 	}
 
-	public List<HgFileRevision> getAddedFiles() {
+	public List<HgFileRevision> getAddedFiles() throws HgInvalidControlFileException {
 		if (addedFiles == null) {
 			initFileChanges();
 		}
 		return addedFiles;
 	}
 
-	public List<Path> getRemovedFiles() {
+	public List<Path> 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 <code>null</code>
+	 * @throws HgInvalidControlFileException FIXME
 	 */
-	public Nodeid getFirstParentRevision() {
+	public Nodeid getFirstParentRevision() throws HgInvalidControlFileException {
 		if (parentHelper != null) {
 			return parentHelper.safeFirstParent(nodeid);
 		}
@@ -160,8 +161,9 @@
 	
 	/**
 	 * @return never <code>null</code>
+	 * @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<Path> deleted = new ArrayList<Path>();
 		ArrayList<HgFileRevision> modified = new ArrayList<HgFileRevision>();
 		ArrayList<HgFileRevision> added = new ArrayList<HgFileRevision>();
--- 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 <code>null</code>.
+		 * @throws HgException indicates failure dealing with Mercurial data
 		 */
-		public Pair<HgChangeset, HgChangeset> parents();
+		public Pair<HgChangeset, HgChangeset> parents() throws HgException;
 		
 		/**
 		 * Lightweight alternative to {@link #parents()}, give {@link Nodeid nodeids} only
@@ -63,7 +66,12 @@
 		 */
 		public Pair<Nodeid, Nodeid> parentRevisions();
 
-		public Collection<HgChangeset> 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<HgChangeset> children() throws HgException;
 
 		/**
 		 * Lightweight alternative to {@link #children()}.
--- 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.
--- 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<Nodeid> executeLite() throws HgRemoteConnectionException, CancelledException {
+	public List<Nodeid> executeLite() throws HgRemoteConnectionException, HgInvalidControlFileException, CancelledException {
 		LinkedHashSet<Nodeid> result = new LinkedHashSet<Nodeid>();
 		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<BranchChain> getMissingBranches() throws HgRemoteConnectionException, CancelledException {
+	private List<BranchChain> getMissingBranches() throws HgRemoteConnectionException, HgInvalidControlFileException, CancelledException {
 		if (missingBranches == null) {
 			missingBranches = getComparator().calculateMissingBranches();
 		}
 		return missingBranches;
 	}
 
-	private List<Nodeid> getCommon() throws HgRemoteConnectionException, CancelledException {
+	private List<Nodeid> getCommon() throws HgRemoteConnectionException, HgInvalidControlFileException, CancelledException {
 //		return getComparator(context).getCommon();
 		final LinkedHashSet<Nodeid> common = new LinkedHashSet<Nodeid>();
 		// XXX common can be obtained from repoCompare, but at the moment it would almost duplicate work of calculateMissingBranches
--- 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<HgChangeset, HgChangeset> parents() {
+		public Pair<HgChangeset, HgChangeset> parents() throws HgException {
 			if (parents != null) {
 				return parents;
 			}
@@ -475,7 +475,7 @@
 			return parents = new Pair<HgChangeset, HgChangeset>(r[0], r[1]);
 		}
 
-		public Collection<HgChangeset> children() {
+		public Collection<HgChangeset> 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));
 			}
--- 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 <code>null</code>
 	 * @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();
 		}
--- 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<Nodeid> executeLite() throws HgRemoteConnectionException, CancelledException {
+	public List<Nodeid> 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();
--- 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;
 	}
 }
--- 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) {
--- 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<RawChangeset> range(int start, int end) throws HgInvalidRevisionException {
+	public List<RawChangeset> 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<String> usersPool) {
+		// FIXME replace HgBadArgumentException with HgInvalidDataFormatException or HgInvalidControlFileException 
+		/* package-local */void init(byte[] data, int offset, int length, Pool<String> 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();
--- 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) {
--- 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 <code>null</code>
 	 */
-	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 <code>null</code> 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<Integer, Nodeid> getFileRevisions(final Path file, int... localChangelogRevisions) {
+	public Map<Integer, Nodeid> getFileRevisions(final Path file, int... localChangelogRevisions) throws HgInvalidControlFileException{
 		// FIXME need tests
 		int[] localManifestRevisions = toLocalManifestRevisions(localChangelogRevisions);
 		final HashMap<Integer,Nodeid> rv = new HashMap<Integer, Nodeid>(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  
--- 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));
--- 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 <rev>
-	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;
 			}
--- 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) {
--- 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<Nodeid> getRevisions(int... revisions) throws HgInvalidRevisionException {
+	public final List<Nodeid> getRevisions(int... revisions) throws HgInvalidRevisionException, HgInvalidControlFileException {
 		ArrayList<Nodeid> rv = new ArrayList<Nodeid>(revisions.length);
 		Arrays.sort(revisions);
 		getRevisionsInternal(rv, revisions);
 		return rv;
 	}
 	
-	/*package-local*/ void getRevisionsInternal(final List<Nodeid> retVal, int[] sortedRevs) throws HgInvalidRevisionException {
+	/*package-local*/ void getRevisionsInternal(final List<Nodeid> 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 <code>this</code> for convenience.
 		 */
-		public RevisionMap init(/*XXX Pool<Nodeid> to reuse nodeids, if possible. */) {
+		public RevisionMap init(/*XXX Pool<Nodeid> 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];
--- 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<List<TagInfo>> tagLocalRev2TagInfo, TagInfo[] allTags, Path targetPath) {
+	private void collectTagsPerFile_Approach_2(HgRepository repository, final int[] tagLocalRevs, final IntMap<List<TagInfo>> 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