changeset 608:e1b29756f901

Clean, organize and resolve some TODOs and FIXMEs: minor refactorings and comments
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 07 May 2013 21:27:51 +0200
parents 66f1cc23b906
children e4a71afd3c71
files src/org/tmatesoft/hg/internal/ByteArrayChannel.java src/org/tmatesoft/hg/internal/ConfigFile.java src/org/tmatesoft/hg/internal/DataAccess.java src/org/tmatesoft/hg/internal/DataAccessProvider.java src/org/tmatesoft/hg/internal/Internals.java src/org/tmatesoft/hg/internal/RevlogStream.java src/org/tmatesoft/hg/internal/RevlogStreamFactory.java src/org/tmatesoft/hg/internal/RevlogStreamWriter.java src/org/tmatesoft/hg/repo/HgDataFile.java src/org/tmatesoft/hg/repo/HgInternals.java src/org/tmatesoft/hg/repo/HgManifest.java src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java src/org/tmatesoft/hg/repo/Revlog.java src/org/tmatesoft/hg/util/FileWalker.java test/org/tmatesoft/hg/test/TestCheckout.java test/org/tmatesoft/hg/test/TestFileFlags.java
diffstat 16 files changed, 112 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/internal/ByteArrayChannel.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/ByteArrayChannel.java	Tue May 07 21:27:51 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 TMate Software Ltd
+ * Copyright (c) 2011-2013 TMate Software Ltd
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,7 +23,8 @@
 import org.tmatesoft.hg.util.ByteChannel;
 
 /**
- *
+ * {@link ByteChannel} implementation that serializes data into a byte array
+ * 
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
  */
@@ -48,7 +49,10 @@
 		}
 	}
 
-	// TODO document what happens on write after toArray() in each case
+	/*
+	 * {@link #toArray()} calls do not clear data collected so far, subsequent {@link #write(ByteBuffer)}  
+	 * augment collected content.
+	 */
 	public int write(ByteBuffer buffer) {
 		int rv = buffer.remaining();
 		if (buffers == null) {
@@ -58,9 +62,13 @@
 			copy.put(buffer);
 			buffers.add(copy);
 		}
+		result = null;
 		return rv;
 	}
 
+	/**
+	 * @return content accumulated so far
+	 */
 	public byte[] toArray() {
 		if (result != null) {
 			return result;
@@ -84,7 +92,6 @@
 				bb.get(result, off, bb.limit());
 				off += bb.limit();
 			}
-			buffers.clear();
 			return result;
 		}
 	}
--- a/src/org/tmatesoft/hg/internal/ConfigFile.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/ConfigFile.java	Tue May 07 21:27:51 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012 TMate Software Ltd
+ * Copyright (c) 2011-2013 TMate Software Ltd
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -183,7 +183,7 @@
 		private Map<String,String> section = new LinkedHashMap<String, String>();
 		private File contextFile;
 
-		// TODO "" and lists
+		// TODO [post-1.1] "" and lists
 		// XXX perhaps, single string to keep whole section with substrings for keys/values to minimize number of arrays (String.value)
 		public boolean consume(String line, ConfigFile cfg) throws IOException {
 			int x;
@@ -237,7 +237,7 @@
 		// include failure doesn't propagate
 		private void processInclude(String includeValue, ConfigFile cfg) {
 			File f; 
-			// TODO handle environment variable expansion
+			// TODO [post-1.1] handle environment variable expansion
 			if (includeValue.startsWith("~/")) {
 				f = new File(System.getProperty("user.home"), includeValue.substring(2));
 			} else {
--- a/src/org/tmatesoft/hg/internal/DataAccess.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/DataAccess.java	Tue May 07 21:27:51 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012 TMate Software Ltd
+ * Copyright (c) 2010-2013 TMate Software Ltd
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -99,9 +99,10 @@
 		}
 		throw new IOException(String.format("No data, can't read %d bytes", length));
 	}
-	// reads bytes into ByteBuffer, up to its limit or total data length, whichever smaller
-	// TODO post-1.0 perhaps, in DataAccess paradigm (when we read known number of bytes, we shall pass specific byte count to read)
-	// for 1.0, it's ok as it's our internal class
+	/**
+	 * reads bytes into ByteBuffer, up to its limit or total data length, whichever smaller.
+	 * XXX perhaps, in DataAccess paradigm (when we read known number of bytes, we shall pass specific byte count to read)
+	 */
 	public void readBytes(ByteBuffer buf) throws IOException {
 //		int toRead = Math.min(buf.remaining(), (int) length());
 //		if (buf.hasArray()) {
@@ -111,7 +112,7 @@
 //			readBytes(bb, 0, bb.length);
 //			buf.put(bb);
 //		}
-		// TODO post-1.0 optimize to read as much as possible at once
+		// TODO [post-1.1] optimize to read as much as possible at once
 		while (!isEmpty() && buf.hasRemaining()) {
 			buf.put(readByte());
 		}
@@ -120,8 +121,14 @@
 		throw new UnsupportedOperationException();
 	}
 
-	// XXX decide whether may or may not change position in the DataAccess
-	// TODO REVISIT exception handling may not be right, initially just for the sake of quick test
+	/**
+	 * Content of this DataAccess as byte array.
+	 * Note, likely changes position in the DataAccess.
+	 * Might provide direct access to underlying data structure in certain cases, do not alter.
+	 * 
+	 * @return byte array of {@link #length()} size, filled with data   
+	 * @throws IOException
+	 */
 	public byte[] byteArray() throws IOException {
 		reset();
 		byte[] rv = new byte[length()];
--- a/src/org/tmatesoft/hg/internal/DataAccessProvider.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/DataAccessProvider.java	Tue May 07 21:27:51 2013 +0200
@@ -54,8 +54,6 @@
 	private final int mapioMagicBoundary;
 	private final int bufferSize, mapioBufSize;
 	private final SessionContext context;
-	// not the right place for the property, but DAP is the only place currently available to RevlogStream to get the value
-	private final boolean shallMergePatches;
 	
 	public DataAccessProvider(SessionContext ctx) {
 		context = ctx;
@@ -63,7 +61,6 @@
 		mapioMagicBoundary = mapioBoundaryValue(pm.getInt(CFG_PROPERTY_MAPIO_LIMIT, DEFAULT_MAPIO_LIMIT));
 		bufferSize = pm.getInt(CFG_PROPERTY_FILE_BUFFER_SIZE, DEFAULT_FILE_BUFFER);
 		mapioBufSize = pm.getInt(CFG_PROPERTY_MAPIO_BUFFER_SIZE, DEFAULT_MAPIO_BUFFER);
-		shallMergePatches = pm.getBoolean(Internals.CFG_PROPERTY_PATCH_MERGE, false);
 	}
 	
 	public DataAccessProvider(SessionContext ctx, int mapioBoundary, int regularBufferSize, int mapioBufferSize) {
@@ -71,14 +68,8 @@
 		mapioMagicBoundary = mapioBoundaryValue(mapioBoundary);
 		bufferSize = regularBufferSize;
 		mapioBufSize = mapioBufferSize;
-		shallMergePatches = new PropertyMarshal(ctx).getBoolean(Internals.CFG_PROPERTY_PATCH_MERGE, false);
 	}
 	
-	// TODO [post-1.1] find a better place for this option, it's unrelated to the DAP
-	public boolean shallMergePatches() {
-		return shallMergePatches;
-	}
-
 	// ensure contract of CFG_PROPERTY_MAPIO_LIMIT, for mapioBoundary == 0 use MAX_VALUE so that no file is memmap-ed
 	private static int mapioBoundaryValue(int mapioBoundary) {
 		return mapioBoundary == 0 ? Integer.MAX_VALUE : mapioBoundary;
--- a/src/org/tmatesoft/hg/internal/Internals.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/Internals.java	Tue May 07 21:27:51 2013 +0200
@@ -125,6 +125,7 @@
 	private final PathRewrite dataPathHelper; // access to file storage area (usually under .hg/store/data/), with filenames mangled  
 	private final PathRewrite repoPathHelper; // access to system files (under .hg/store if requires has 'store' flag)
 
+	private final boolean shallMergePatches;
 	private final RevlogStreamFactory streamProvider;
 
 	public Internals(HgRepository hgRepo, File hgDir, ImplAccess implementationAccess) throws HgRuntimeException {
@@ -138,8 +139,10 @@
 		requiresFlags = repoInit.getRequires();
 		dataPathHelper = repoInit.buildDataFilesHelper(getSessionContext());
 		repoPathHelper = repoInit.buildStoreFilesHelper();
-		boolean shallCacheRevlogsInRepo = new PropertyMarshal(ctx).getBoolean(CFG_PROPERTY_REVLOG_STREAM_CACHE, true);
+		final PropertyMarshal pm = new PropertyMarshal(ctx);
+		boolean shallCacheRevlogsInRepo = pm.getBoolean(CFG_PROPERTY_REVLOG_STREAM_CACHE, true);
 		streamProvider = new RevlogStreamFactory(this, shallCacheRevlogsInRepo); 
+		shallMergePatches = pm.getBoolean(Internals.CFG_PROPERTY_PATCH_MERGE, false);
 	}
 	
 	public boolean isInvalid() {
@@ -266,6 +269,16 @@
 		return requiresFlags;
 	}
 	
+	boolean shallMergePatches() {
+		return shallMergePatches;
+	}
+
+	RevlogChangeMonitor getRevlogTracker(File f) {
+		// TODO decide whether to use one monitor per multiple files or 
+		// an instance per file; and let SessionContext pass alternative implementation)
+		return new RevlogChangeMonitor(f);
+	}
+	
 	public static boolean runningOnWindows() {
 		return System.getProperty("os.name").indexOf("Windows") != -1;
 	}
@@ -390,7 +403,7 @@
 		if (f.canRead() && f.isDirectory()) {
 			return listConfigFiles(f);
 		}
-		// TODO post-1.0 query registry, e.g. with
+		// TODO [post-1.1] query registry, e.g. with
 		// Runtime.exec("reg query HKLM\Software\Mercurial")
 		//
 		f = new File("C:\\Mercurial\\Mercurial.ini");
--- a/src/org/tmatesoft/hg/internal/RevlogStream.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/RevlogStream.java	Tue May 07 21:27:51 2013 +0200
@@ -50,6 +50,8 @@
  */
 public class RevlogStream {
 
+	static final int INLINEDATA = 1 << 16;
+
 	/*
 	 * makes sense for index with inline data only - actual offset of the record in the .i file (record entry + revision * record size))
 	 * 
@@ -63,7 +65,7 @@
 	private boolean inline = false;
 	private final File indexFile;
 	private File dataFile;
-	private final DataAccessProvider dataAccess;
+	private final Internals repo;
 	// keeps last complete revision we've read. Note, this cached revision doesn't help
 	// for subsequent #iterate() calls with the same revision (Inspector needs more data than 
 	// we currently cache here, perhaps, we shall cache everything it wants to cover same 
@@ -77,14 +79,10 @@
 	private List<Observer> observers;
 	private boolean shallDropDerivedCaches = false;
 
-	// if we need anything else from HgRepo, might replace DAP parameter with HgRepo and query it for DAP.
-	public RevlogStream(DataAccessProvider dap, File indexFile) {
-		this.dataAccess = dap;
+	public RevlogStream(Internals hgRepo, File indexFile) {
+		repo = hgRepo;
 		this.indexFile = indexFile;
-		// TODO in fact, shall ask Internals for an instance (there we'll decide whether to use
-		// one monitor per multiple files or an instance per file; and let SessionContext pass
-		// alternative implementation)
-		changeTracker = new RevlogChangeMonitor(indexFile);
+		changeTracker = repo.getRevlogTracker(indexFile);
 	}
 
 	/**
@@ -94,18 +92,22 @@
 	/*package*/ DataAccess getIndexStream(boolean shortRead) {
 		// shortRead hint helps  to avoid mmap files when only 
 		// few bytes are to be read (i.e. #dataLength())
+		DataAccessProvider dataAccess = repo.getDataAccess();
 		return dataAccess.createReader(indexFile, shortRead);
 	}
 
 	/*package*/ DataAccess getDataStream() {
+		DataAccessProvider dataAccess = repo.getDataAccess();
 		return dataAccess.createReader(getDataFile(), false);
 	}
 	
 	/*package*/ DataSerializer getIndexStreamWriter() {
+		DataAccessProvider dataAccess = repo.getDataAccess();
 		return dataAccess.createWriter(indexFile, true);
 	}
 	
 	/*package*/ DataSerializer getDataStreamWriter() {
+		DataAccessProvider dataAccess = repo.getDataAccess();
 		return dataAccess.createWriter(getDataFile(), true);
 	}
 	
@@ -301,14 +303,12 @@
 		HgInternals.checkRevlogRange(start, end, indexSize-1);
 		// XXX may cache [start .. end] from index with a single read (pre-read)
 		
-		ReaderN1 r = new ReaderN1(needData, inspector, dataAccess.shallMergePatches());
+		ReaderN1 r = new ReaderN1(needData, inspector, repo.shallMergePatches());
 		try {
 			r.start(end - start + 1, getLastRevisionRead());
 			r.range(start, end);
 		} catch (IOException ex) {
 			throw new HgInvalidControlFileException(String.format("Failed reading [%d..%d]", start, end), ex, indexFile);
-		} catch (HgInvalidControlFileException ex) {
-			throw ex;
 		} finally {
 			CachedRevision cr = r.finish();
 			setLastRevisionRead(cr);
@@ -334,7 +334,7 @@
 			throw new HgInvalidRevisionException(String.format("Can't iterate [%d, %d] in range [0..%d]", sortedRevisions[0], sortedRevisions[sortedRevisions.length - 1], indexSize), null, sortedRevisions[sortedRevisions.length - 1]);
 		}
 
-		ReaderN1 r = new ReaderN1(needData, inspector, dataAccess.shallMergePatches());
+		ReaderN1 r = new ReaderN1(needData, inspector, repo.shallMergePatches());
 		try {
 			r.start(sortedRevisions.length, getLastRevisionRead());
 			for (int i = 0; i < sortedRevisions.length; ) {
@@ -354,10 +354,7 @@
 			}
 		} catch (IOException 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);
-		} catch (HgInvalidControlFileException ex) {
-			// TODO post-1.0 fill HgRuntimeException with appropriate file (either index or data, depending on error source)
-			throw ex;
+			throw new HgInvalidControlFileException(String.format("Failed reading %d revisions in [%d; %d]", c, sortedRevisions[0], sortedRevisions[c-1]), ex, indexFile);
 		} finally {
 			CachedRevision cr = r.finish();
 			setLastRevisionRead(cr);
@@ -488,7 +485,6 @@
 			}
 			int versionField = da.readInt();
 			da.readInt(); // just to skip next 4 bytes of offset + flags
-			final int INLINEDATA = 1 << 16;
 			inline = (versionField & INLINEDATA) != 0;
 			IntVector resBases, resOffsets = null;
 			int entryCountGuess = Internals.ltoi(da.longLength() / REVLOGV1_RECORD_SIZE);
@@ -592,7 +588,7 @@
 		// next are transient values, for range() use only
 		private final Inflater inflater = new Inflater();
 		// can share buffer between instances of InflaterDataAccess as I never read any two of them in parallel
-		private final byte[] inflaterBuffer = new byte[10 * 1024]; // TODO consider using DAP.DEFAULT_FILE_BUFFER
+		private final byte[] inflaterBuffer = new byte[10 * 1024]; // TODO [post-1.1] consider using DAP.DEFAULT_FILE_BUFFER
 		private final byte[] nodeidBuf = new byte[20];
 		// revlog record fields
 		private long offset;
@@ -829,9 +825,22 @@
 
 	
 	public interface Inspector {
-		// 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
+		/**
+		 * XXX boolean retVal to indicate whether to continue?
+		 * 
+		 * Implementers shall not invoke DataAccess.done(), it's accomplished by #iterate at appropriate moment
+		 * 
+		 * @param revisionIndex absolute index of revision in revlog being iterated
+		 * @param actualLen length of the user data at this revision
+		 * @param baseRevision last revision known to hold complete revision (other hold patches). 
+		 *        if baseRevision != revisionIndex, data for this revision is a result of a sequence of patches
+		 * @param linkRevision index of corresponding changeset revision
+		 * @param parent1Revision index of first parent revision in this revlog, or {@link HgRepository#NO_REVISION}
+		 * @param parent2Revision index of second parent revision in this revlog, or {@link HgRepository#NO_REVISION}
+		 * @param nodeid 20-byte buffer, shared between invocations 
+		 * @param data access to revision content of actualLen size, or <code>null</code> if no data has been requested with 
+		 *        {@link RevlogStream#iterate(int[], boolean, Inspector)}
+		 */
 		void next(int revisionIndex, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[/*20*/] nodeid, DataAccess data);
 	}
 
--- a/src/org/tmatesoft/hg/internal/RevlogStreamFactory.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/RevlogStreamFactory.java	Tue May 07 21:27:51 2013 +0200
@@ -49,7 +49,7 @@
 	 * Creates a stream for specified file, doesn't cache stream
 	 */
 	/*package-local*/ RevlogStream create(File f) {
-		return new RevlogStream(repo.getDataAccess(), f);
+		return new RevlogStream(repo, f);
 	}
 
 	/**
--- a/src/org/tmatesoft/hg/internal/RevlogStreamWriter.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/RevlogStreamWriter.java	Tue May 07 21:27:51 2013 +0200
@@ -29,7 +29,7 @@
 
 /**
  * 
- * TODO separate operation to check if index is too big and split into index+data
+ * TODO [post-1.1] separate operation to check if index is too big and split into index+data
  * 
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
@@ -255,8 +255,7 @@
 			if (offset == 0) {
 				int version = 1 /* RevlogNG */;
 				if (isInline) {
-					final int INLINEDATA = 1 << 16; // FIXME extract constant
-					version |= INLINEDATA;
+					version |= RevlogStream.INLINEDATA;
 				}
 				header.putInt(version);
 				header.putInt(0);
--- a/src/org/tmatesoft/hg/repo/HgDataFile.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/repo/HgDataFile.java	Tue May 07 21:27:51 2013 +0200
@@ -572,7 +572,6 @@
 			} catch (IOException ex) {
 				recordFailure(ex);
 			} catch (HgInvalidControlFileException ex) {
-				// TODO RevlogStream, where this RevlogStream.Inspector goes, shall set File (as it's the only one having access to it)
 				recordFailure(ex.isRevisionIndexSet() ? ex : ex.setRevisionIndex(revisionNumber));
 			}
 		}
--- a/src/org/tmatesoft/hg/repo/HgInternals.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/repo/HgInternals.java	Tue May 07 21:27:51 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012 TMate Software Ltd
+ * Copyright (c) 2011-2013 TMate Software Ltd
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -144,7 +144,7 @@
 		// Impl note: simple source is enough as files in the working dir are all unique
 		// even if they might get reused (i.e. after FileIterator#reset() and walking once again),
 		// path caching is better to be done in the code which knows that path are being reused 
-		return new FileWalker(repo.getSessionContext(), repoRoot, pathSrc, workindDirScope);
+		return new FileWalker(repo, repoRoot, pathSrc, workindDirScope);
 	}
 	
 	// Convenient check of revision index for validity (not all negative values are wrong as long as we use negative constants)
--- a/src/org/tmatesoft/hg/repo/HgManifest.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/repo/HgManifest.java	Tue May 07 21:27:51 2013 +0200
@@ -109,7 +109,19 @@
 			}
 			throw new IllegalStateException(new String(data, start, length));
 		}
-
+		
+		static Flags parse(int dirstateFileMode) {
+			// source/include/linux/stat.h
+			final int S_IFLNK = 0120000, S_IXUSR = 00100;
+			if ((dirstateFileMode & S_IFLNK) == S_IFLNK) {
+				return Link;
+			}
+			if ((dirstateFileMode & S_IXUSR) == S_IXUSR) {
+				return Exec;
+			}
+			return RegularFile;
+		}
+		
 		String nativeString() {
 			if (this == Exec) {
 				return "x";
--- a/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java	Tue May 07 21:27:51 2013 +0200
@@ -375,8 +375,7 @@
 					} else {
 						HgDataFile df = repo.getFileNode(fname);
 						if (!df.exists()) {
-							// TODO pass Internals right into HgWCSC cons
-							Internals implRepo = HgInternals.getImplementationRepo(repo);
+							Internals implRepo = repo.getImplHelper();
 							String msg = String.format("File %s known as normal in dirstate (%d, %d), doesn't exist at %s", fname, r.modificationTime(), r.size(), implRepo.getStoragePath(df));
 							throw new HgInvalidFileException(msg, null).setFileName(fname);
 						}
@@ -496,7 +495,7 @@
 			// only those left in baseRevNames after processing are reported as removed 
 		}
 
-		// TODO think over if content comparison may be done more effectively by e.g. calculating nodeid for a local file and comparing it with nodeid from manifest
+		// TODO [post-1.1] think over if content comparison may be done more effectively by e.g. calculating nodeid for a local file and comparing it with nodeid from manifest
 		// we don't need to tell exact difference, hash should be enough to detect difference, and it doesn't involve reading historical file content, and it's relatively 
 		// cheap to calc hash on a file (no need to keep it completely in memory). OTOH, if I'm right that the next approach is used for nodeids: 
 		// changeset nodeid + hash(actual content) => entry (Nodeid) in the next Manifest
@@ -624,16 +623,7 @@
 	}
 	
 	private boolean checkFlagsEqual(FileInfo f, int dirstateFileMode) {
-		// source/include/linux/stat.h
-		final int S_IFLNK = 0120000, S_IXUSR = 00100;
-		// TODO post-1.0 HgManifest.Flags.parse(int)
-		if ((dirstateFileMode & S_IFLNK) == S_IFLNK) {
-			return checkFlagsEqual(f, HgManifest.Flags.Link);
-		}
-		if ((dirstateFileMode & S_IXUSR) == S_IXUSR) {
-			return checkFlagsEqual(f, HgManifest.Flags.Exec);
-		}
-		return checkFlagsEqual(f, HgManifest.Flags.RegularFile); // no flags
+		return checkFlagsEqual(f, HgManifest.Flags.parse(dirstateFileMode)); 
 	}
 
 	/**
--- a/src/org/tmatesoft/hg/repo/Revlog.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/repo/Revlog.java	Tue May 07 21:27:51 2013 +0200
@@ -251,7 +251,7 @@
 		} catch (IOException ex) {
 			HgInvalidControlFileException e = new HgInvalidControlFileException(String.format("Access to revision %d content failed", revisionIndex), ex, null);
 			e.setRevisionIndex(revisionIndex);
-			// TODO post 1.0 e.setFileName(content.getIndexFile() or this.getHumanFriendlyPath()) - shall decide whether 
+			// TODO [post 1.1] e.setFileName(content.getIndexFile() or this.getHumanFriendlyPath()) - shall decide whether 
 			// protected abstract getHFPath() with impl in HgDataFile, HgManifest and HgChangelog or path is data of either Revlog or RevlogStream
 			// Do the same (add file name) below
 			throw e;
@@ -375,7 +375,7 @@
 		});
 		if (parentInsp != null && _start > 0) {
 			assert missingParents.size() > 0; // in fact, more relaxed than assert. rather 'assume'
-			// TODO int[] IntMap#keys() or even sort of iterator that can modify values
+			// TODO [post-1.1] int[] IntMap#keys() or even sort of iterator that can modify values
 			for (int k = missingParents.firstKey(), l = missingParents.lastKey(); k <= l; k++) {
 				if (missingParents.containsKey(k)) {
 					Nodeid nid = getRepo().getChangelog().getRevision(k);
@@ -433,7 +433,8 @@
 	}
 	
 	/*
-	 * class with cancel and few other exceptions support. TODO consider general superclass to share with e.g. HgManifestCommand.Mediator
+	 * class with cancel and few other exceptions support. 
+	 * TODO [post-1.1] consider general superclass to share with e.g. HgManifestCommand.Mediator
 	 */
 	protected abstract static class ErrorHandlingInspector implements RevlogStream.Inspector, CancelSupport {
 		private Exception failure;
--- a/src/org/tmatesoft/hg/util/FileWalker.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/util/FileWalker.java	Tue May 07 21:27:51 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012 TMate Software Ltd
+ * Copyright (c) 2011-2013 TMate Software Ltd
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -41,19 +41,25 @@
 	private RegularFileInfo nextFile;
 	private Path nextPath;
 
-	// TODO FileWalker to accept SessionContext.Source and SessionContext to implement SessionContext.Source
-	// (if it doesn't break binary compatibility)
 	public FileWalker(SessionContext ctx, File dir, Path.Source pathFactory) {
 		this(ctx, dir, pathFactory, null);
 	}
+	
+	/**
+	 * @see FileWalker#FileWalker(SessionContext, File, Path.Source, Matcher)
+	 */
+	public FileWalker(SessionContext.Source ctxSource, File dir, Path.Source pathFactory, Path.Matcher scopeMatcher) {
+		this(ctxSource.getSessionContext(), dir, pathFactory, scopeMatcher);
+	}
 
 	/**
+	 * Implementation of {@link FileIterator} with regular {@link java.io.File}.
 	 * 
-	 * @param dir
-	 * @param pathFactory
+	 * @param dir directory to start at, not <code>null</code>
+	 * @param pathFactory factory to create {@link Path} instances, not <code>null</code>
 	 * @param scopeMatcher - this matcher shall be capable to tell not only files of interest, but
 	 * also whether directories shall be traversed or not (Paths it gets in {@link Path.Matcher#accept(Path)} may 
-	 * point to directories)   
+	 * point to directories); may be <code>null</code>
 	 */
 	public FileWalker(SessionContext ctx, File dir, Path.Source pathFactory, Path.Matcher scopeMatcher) {
 		sessionContext = ctx;
--- a/test/org/tmatesoft/hg/test/TestCheckout.java	Tue May 07 16:52:46 2013 +0200
+++ b/test/org/tmatesoft/hg/test/TestCheckout.java	Tue May 07 21:27:51 2013 +0200
@@ -124,7 +124,7 @@
 		repo = new HgLookup().detect(testRepoLoc);
 		new HgCheckoutCommand(repo).clean(true).changeset(0).execute();
 		
-		FileWalker fw = new FileWalker(repo.getSessionContext(), testRepoLoc, new Path.SimpleSource());
+		FileWalker fw = new FileWalker(repo, testRepoLoc, new Path.SimpleSource(), null);
 		int execFound, linkFound, regularFound;
 		execFound = linkFound = regularFound = 0;
 		while(fw.hasNext()) {
--- a/test/org/tmatesoft/hg/test/TestFileFlags.java	Tue May 07 16:52:46 2013 +0200
+++ b/test/org/tmatesoft/hg/test/TestFileFlags.java	Tue May 07 21:27:51 2013 +0200
@@ -65,7 +65,7 @@
 	public void testFlagsInWorkingCopy() throws Exception {
 		File repoRoot = repo.getWorkingDir();
 		Path.Source pathSrc = new Path.SimpleSource(new PathRewrite.Composite(new RelativePathRewrite(repoRoot), repo.getToRepoPathHelper()));
-		FileWalker fw = new FileWalker(repo.getSessionContext(), repoRoot, pathSrc);
+		FileWalker fw = new FileWalker(repo, repoRoot, pathSrc, null);
 		
 		if (Internals.runningOnWindows()) {
 			System.out.println("Executing tests on Windows, no actual file flags in working area are checked");