changeset 290:8faad08c709b

Expose dirstate to allow pre-configuration of FileIterators for status collection in particular
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 14 Sep 2011 01:52:41 +0200
parents 086a326f181f
children 1483e57541ef
files cmdline/org/tmatesoft/hg/console/Main.java src/org/tmatesoft/hg/repo/HgDirstate.java src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java
diffstat 3 files changed, 84 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/cmdline/org/tmatesoft/hg/console/Main.java	Mon Sep 12 14:11:45 2011 +0200
+++ b/cmdline/org/tmatesoft/hg/console/Main.java	Wed Sep 14 01:52:41 2011 +0200
@@ -40,6 +40,7 @@
 import org.tmatesoft.hg.repo.HgBranches;
 import org.tmatesoft.hg.repo.HgChangelog;
 import org.tmatesoft.hg.repo.HgDataFile;
+import org.tmatesoft.hg.repo.HgDirstate;
 import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgManifest;
 import org.tmatesoft.hg.repo.HgMergeState;
@@ -51,6 +52,8 @@
 import org.tmatesoft.hg.repo.HgSubrepoLocation.Kind;
 import org.tmatesoft.hg.repo.HgWorkingCopyStatusCollector;
 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
+import org.tmatesoft.hg.repo.HgDirstate.EntryKind;
+import org.tmatesoft.hg.repo.HgDirstate.Record;
 import org.tmatesoft.hg.util.FileWalker;
 import org.tmatesoft.hg.util.Pair;
 import org.tmatesoft.hg.util.Path;
@@ -86,12 +89,12 @@
 //		m.testParents();
 //		m.testEffectiveFileLog();
 //		m.testCatAtCsetRevision();
-		m.testMergeState();
+//		m.testMergeState();
 //		m.testFileStatus();
 //		m.dumpBranches();
 //		m.inflaterLengthException();
 //		m.dumpIgnored();
-//		m.dumpDirstate();
+		m.dumpDirstate();
 //		m.testStatusInternals();
 //		m.catCompleteHistory();
 //		m.dumpCompleteManifestLow();
@@ -325,6 +328,14 @@
 	
 	private void dumpDirstate() {
 		new HgInternals(hgRepo).dumpDirstate();
+		HgWorkingCopyStatusCollector wcc = HgWorkingCopyStatusCollector.create(hgRepo, new Path.Matcher.Any());
+		wcc.getDirstate().walk(new HgDirstate.Inspector() {
+			
+			public boolean next(EntryKind kind, Record entry) {
+				System.out.printf("%s %s\n", kind, entry.name());
+				return true;
+			}
+		});
 	}
 
 	
--- a/src/org/tmatesoft/hg/repo/HgDirstate.java	Mon Sep 12 14:11:45 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgDirstate.java	Wed Sep 14 01:52:41 2011 +0200
@@ -42,7 +42,11 @@
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
  */
-class HgDirstate /* XXX RepoChangeListener */{
+public final class HgDirstate /* XXX RepoChangeListener */{
+	
+	public enum EntryKind {
+		Normal, Added, Removed, Merged, // order is being used in code of this class, don't change unless any use is checked
+	}
 
 	private final HgRepository repo;
 	private final File dirstateFile;
@@ -54,7 +58,7 @@
 	private Pair<Nodeid, Nodeid> parents;
 	private String currentBranch;
 	
-	public HgDirstate(HgRepository hgRepo, File dirstate, PathPool pathPool) {
+	/*package-local*/ HgDirstate(HgRepository hgRepo, File dirstate, PathPool pathPool) {
 		repo = hgRepo;
 		dirstateFile = dirstate; // XXX decide whether file names shall be kept local to reader (see #branches()) or passed from outside
 		this.pathPool = pathPool;
@@ -126,7 +130,7 @@
 	}
 	
 	/**
-	 * @return array of length 2 with working copy parents, non null.
+	 * @return pair of working copy parents, with {@link Nodeid#NULL} for missing values.
 	 */
 	public Pair<Nodeid,Nodeid> parents() {
 		if (parents == null) {
@@ -138,7 +142,7 @@
 	/**
 	 * @return pair of parents, both {@link Nodeid#NULL} if dirstate is not available
 	 */
-	public static Pair<Nodeid, Nodeid> readParents(HgRepository repo, File dirstateFile) {
+	/*package-local*/ static Pair<Nodeid, Nodeid> readParents(HgRepository repo, File dirstateFile) {
 		// do not read whole dirstate if all we need is WC parent information
 		if (dirstateFile == null || !dirstateFile.exists()) {
 			return new Pair<Nodeid,Nodeid>(NULL, NULL);
@@ -157,10 +161,10 @@
 	}
 	
 	/**
-	 * XXX is it really proper place for the method?
 	 * @return branch associated with the working directory
 	 */
 	public String branch() {
+		// XXX is it really proper place for the method?
 		if (currentBranch == null) {
 			currentBranch = readBranch(repo);
 		}
@@ -171,7 +175,7 @@
 	 * XXX is it really proper place for the method?
 	 * @return branch associated with the working directory
 	 */
-	public static String readBranch(HgRepository repo) {
+	/*package-local*/ static String readBranch(HgRepository repo) {
 		String branch = HgRepository.DEFAULT_BRANCH_NAME;
 		File branchFile = new File(repo.getRepositoryRoot(), "branch");
 		if (branchFile.exists()) {
@@ -193,7 +197,9 @@
 
 	// new, modifiable collection
 	/*package-local*/ TreeSet<Path> all() {
-		read();
+		if (normal == null) {
+			read();
+		}
 		TreeSet<Path> rv = new TreeSet<Path>();
 		@SuppressWarnings("unchecked")
 		Map<Path, Record>[] all = new Map[] { normal, added, removed, merged };
@@ -239,16 +245,33 @@
 		}
 	}
 	
-	/*package-local*/ static class Record {
-		final int mode;
-		// it seems Dirstate keeps local file size (i.e. that with any filters already applied). 
+	public void walk(Inspector inspector) {
+		if (normal == null) {
+			read();
+		}
+		@SuppressWarnings("unchecked")
+		Map<Path, Record>[] all = new Map[] { normal, added, removed, merged };
+		for (int i = 0; i < all.length; i++) {
+			EntryKind k = EntryKind.values()[i];
+			for (Record r : all[i].values()) {
+				if (!inspector.next(k, r)) {
+					return;
+				}
+			}
+		}
+	}
+
+	public interface Inspector {
+		boolean next(EntryKind kind, Record entry);
+	}
+
+	public static final class Record {
+		private final int mode, size, time;
+		// Dirstate keeps local file size (i.e. that with any filters already applied). 
 		// Thus, can't compare directly to HgDataFile.length()
-		final int size; 
-		final int time;
-		final Path name1;
-		final Path name2;
+		private final Path name1, name2;
 
-		public Record(int fmode, int fsize, int ftime, Path name1, Path name2) {
+		/*package-local*/ Record(int fmode, int fsize, int ftime, Path name1, Path name2) {
 			mode = fmode;
 			size = fsize;
 			time = ftime;
@@ -256,5 +279,24 @@
 			this.name2 = name2;
 			
 		}
+
+		public Path name() {
+			return name1;
+		}
+
+		/**
+		 * @return non-<code>null</code> for copy/move
+		 */
+		public Path copySource() {
+			return name2;
+		}
+
+		public int modificationTime() {
+			return time;
+		}
+
+		public int size() {
+			return size;
+		}
 	}
 }
--- a/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java	Mon Sep 12 14:11:45 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java	Wed Sep 14 01:52:41 2011 +0200
@@ -95,8 +95,11 @@
 		this.pathPool = pathPool;
 	}
 
-	
-	private HgDirstate getDirstate() {
+	/**
+	 * Access to directory state information this collector uses.
+	 * @return directory state holder, never <code>null</code> 
+	 */
+	public HgDirstate getDirstate() {
 		if (dirstate == null) {
 			dirstate = repo.loadDirstate(getPathPool());
 		}
@@ -252,10 +255,10 @@
 		HgDirstate.Record r;
 		if ((r = getDirstate().checkNormal(fname)) != null) {
 			// either clean or modified
-			final boolean timestampEqual = f.lastModified() == r.time, sizeEqual = r.size == f.length();
+			final boolean timestampEqual = f.lastModified() == r.modificationTime(), sizeEqual = r.size() == f.length();
 			if (timestampEqual && sizeEqual) {
 				inspector.clean(fname);
-			} else if (!sizeEqual && r.size >= 0) {
+			} else if (!sizeEqual && r.size() >= 0) {
 				inspector.modified(fname);
 			} else {
 				// size is the same or unknown, and, perhaps, different timestamp
@@ -269,10 +272,10 @@
 				}
 			}
 		} else if ((r = getDirstate().checkAdded(fname)) != null) {
-			if (r.name2 == null) {
+			if (r.copySource() == null) {
 				inspector.added(fname);
 			} else {
-				inspector.copied(getPathPool().path(r.name2), fname);
+				inspector.copied(r.copySource(), fname);
 			}
 		} else if ((r = getDirstate().checkRemoved(fname)) != null) {
 			inspector.removed(fname);
@@ -303,9 +306,9 @@
 					// FIXME report to a mediator, continue status collection
 				}
 			} else if ((r = getDirstate().checkAdded(fname)) != null) {
-				if (r.name2 != null && baseRevNames.contains(r.name2)) {
-					baseRevNames.remove(r.name2); // XXX surely I shall not report rename source as Removed?
-					inspector.copied(r.name2, fname);
+				if (r.copySource() != null && baseRevNames.contains(r.copySource())) {
+					baseRevNames.remove(r.copySource()); // XXX surely I shall not report rename source as Removed?
+					inspector.copied(r.copySource(), fname);
 					return;
 				}
 				// fall-through, report as added
@@ -320,12 +323,12 @@
 			if ((r = getDirstate().checkNormal(fname)) != null && nid1.equals(nidFromDirstate)) {
 				// regular file, was the same up to WC initialization. Check if was modified since, and, if not, report right away
 				// same code as in #checkLocalStatusAgainstFile
-				final boolean timestampEqual = f.lastModified() == r.time, sizeEqual = r.size == f.length();
+				final boolean timestampEqual = f.lastModified() == r.modificationTime(), sizeEqual = r.size() == f.length();
 				boolean handled = false;
 				if (timestampEqual && sizeEqual) {
 					inspector.clean(fname);
 					handled = true;
-				} else if (!sizeEqual && r.size >= 0) {
+				} else if (!sizeEqual && r.size() >= 0) {
 					inspector.modified(fname);
 					handled = true;
 				} else if (!todoCheckFlagsEqual(f, flags)) {