changeset 109:dd4d2d0e42cd

Handler for StatusCommand to get notifications in the form of HgStatus object
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Sat, 29 Jan 2011 04:17:13 +0100
parents 0c9804857000
children 0170f95ca915
files TODO src/org/tmatesoft/hg/core/StatusCommand.java test/org/tmatesoft/hg/test/TestStatus.java
diffstat 3 files changed, 111 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/TODO	Sat Jan 29 02:31:09 2011 +0100
+++ b/TODO	Sat Jan 29 04:17:13 2011 +0100
@@ -26,10 +26,17 @@
   + glob
   + pattern
 
-+ Tests with JUnit 
++ Tests with JUnit
+  - allow to specify repo location (system property)
+  - keep a .zip of repo along with tests 
 
 * tags
   * Tags are read and can be queried (cmdline Log does)
+  
+- keywords
+
+- newlines
+
 
 Proposed:
 - LogCommand.revision(int... rev)+ to walk selected revisions only (list->sort(array) on execute, binary search)
--- a/src/org/tmatesoft/hg/core/StatusCommand.java	Sat Jan 29 02:31:09 2011 +0100
+++ b/src/org/tmatesoft/hg/core/StatusCommand.java	Sat Jan 29 04:17:13 2011 +0100
@@ -16,17 +16,16 @@
  */
 package org.tmatesoft.hg.core;
 
-import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION;
-import static org.tmatesoft.hg.repo.HgRepository.TIP;
-import static org.tmatesoft.hg.repo.HgRepository.WORKING_COPY;
+import static org.tmatesoft.hg.core.StatusCommand.HgStatus.Kind.*;
+import static org.tmatesoft.hg.repo.HgRepository.*;
 
 import java.util.ConcurrentModificationException;
 
-import org.tmatesoft.hg.core.LogCommand.FileRevision;
 import org.tmatesoft.hg.core.Path.Matcher;
+import org.tmatesoft.hg.core.StatusCommand.HgStatus.Kind;
 import org.tmatesoft.hg.repo.HgRepository;
+import org.tmatesoft.hg.repo.HgStatusCollector;
 import org.tmatesoft.hg.repo.HgStatusInspector;
-import org.tmatesoft.hg.repo.HgStatusCollector;
 import org.tmatesoft.hg.repo.HgWorkingCopyStatusCollector;
 
 /**
@@ -41,7 +40,7 @@
 	private int endRevision = WORKING_COPY; 
 	private boolean visitSubRepo = true;
 	
-	private HgStatusInspector visitor;
+	private Handler handler;
 	private final Mediator mediator = new Mediator();
 
 	public StatusCommand(HgRepository hgRepo) { 
@@ -143,14 +142,14 @@
 	 * @throws IllegalArgumentException if handler is <code>null</code>
 	 * @throws ConcurrentModificationException if this command already runs (i.e. being used from another thread)
 	 */
-	public void execute(final HgStatusInspector handler) {
-		if (handler == null) {
+	public void execute(Handler statusHandler) {
+		if (statusHandler == null) {
 			throw new IllegalArgumentException();
 		}
-		if (visitor != null) {
+		if (handler != null) {
 			throw new ConcurrentModificationException();
 		}
-		visitor = handler;
+		handler = statusHandler;
 		HgStatusCollector sc = new HgStatusCollector(repo); // TODO from CommandContext
 //		PathPool pathHelper = new PathPool(repo.getPathHelper()); // TODO from CommandContext
 		try {
@@ -170,10 +169,50 @@
 			}
 		} finally {
 			mediator.done();
-			visitor = null;
+			handler = null;
 		}
 	}
 
+	public interface Handler {
+		void handleStatus(HgStatus s);
+	}
+
+	public static class HgStatus {
+		public enum Kind {
+			Modified, Added, Removed, Unknown, Missing, Clean, Ignored
+		};
+		private final Kind kind;
+		private final Path path;
+		private final Path origin;
+		
+		HgStatus(Kind kind, Path path) {
+			this(kind, path, null);
+		}
+
+		HgStatus(Kind kind, Path path, Path copyOrigin) {
+			this.kind = kind;
+			this.path  = path;
+			origin = copyOrigin;
+		}
+
+		public Kind getKind() {
+			return kind;
+		}
+
+		public Path getPath() {
+			return path;
+		}
+
+		public Path getOriginalPath() {
+			return origin;
+		}
+
+		public boolean isCopy() {
+			return origin != null;
+		}
+	}
+
+	
 	private class Mediator implements HgStatusInspector {
 		boolean needModified;
 		boolean needAdded;
@@ -197,56 +236,56 @@
 		public void modified(Path fname) {
 			if (needModified) {
 				if (matcher == null || matcher.accept(fname)) {
-					visitor.modified(fname);
+					handler.handleStatus(new HgStatus(Modified, fname));
 				}
 			}
 		}
 		public void added(Path fname) {
 			if (needAdded) {
 				if (matcher == null || matcher.accept(fname)) {
-					visitor.added(fname);
+					handler.handleStatus(new HgStatus(Added, fname));
 				}
 			}
 		}
 		public void removed(Path fname) {
 			if (needRemoved) {
 				if (matcher == null || matcher.accept(fname)) {
-					visitor.removed(fname);
+					handler.handleStatus(new HgStatus(Removed, fname));
 				}
 			}
 		}
 		public void copied(Path fnameOrigin, Path fnameAdded) {
 			if (needCopies) {
 				if (matcher == null || matcher.accept(fnameAdded)) {
-					visitor.copied(fnameOrigin, fnameAdded);
+					handler.handleStatus(new HgStatus(Kind.Added, fnameAdded, fnameOrigin));
 				}
 			}
 		}
 		public void missing(Path fname) {
 			if (needMissing) {
 				if (matcher == null || matcher.accept(fname)) {
-					visitor.missing(fname);
+					handler.handleStatus(new HgStatus(Missing, fname));
 				}
 			}
 		}
 		public void unknown(Path fname) {
 			if (needUnknown) {
 				if (matcher == null || matcher.accept(fname)) {
-					visitor.unknown(fname);
+					handler.handleStatus(new HgStatus(Unknown, fname));
 				}
 			}
 		}
 		public void clean(Path fname) {
 			if (needClean) {
 				if (matcher == null || matcher.accept(fname)) {
-					visitor.clean(fname);
+					handler.handleStatus(new HgStatus(Clean, fname));
 				}
 			}
 		}
 		public void ignored(Path fname) {
 			if (needIgnored) {
 				if (matcher == null || matcher.accept(fname)) {
-					visitor.ignored(fname);
+					handler.handleStatus(new HgStatus(Ignored, fname));
 				}
 			}
 		}
--- a/test/org/tmatesoft/hg/test/TestStatus.java	Sat Jan 29 02:31:09 2011 +0100
+++ b/test/org/tmatesoft/hg/test/TestStatus.java	Sat Jan 29 04:17:13 2011 +0100
@@ -17,6 +17,7 @@
 package org.tmatesoft.hg.test;
 
 import static org.hamcrest.CoreMatchers.equalTo;
+import static org.tmatesoft.hg.core.StatusCommand.HgStatus.Kind.*;
 import static org.tmatesoft.hg.repo.HgRepository.TIP;
 
 import java.util.Collection;
@@ -24,12 +25,16 @@
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 import org.junit.Assume;
 import org.junit.Rule;
 import org.junit.Test;
 import org.tmatesoft.hg.core.Path;
 import org.tmatesoft.hg.core.StatusCommand;
+import org.tmatesoft.hg.core.StatusCommand.HgStatus;
+import org.tmatesoft.hg.core.StatusCommand.HgStatus.Kind;
 import org.tmatesoft.hg.repo.HgLookup;
 import org.tmatesoft.hg.repo.HgRepository;
 import org.tmatesoft.hg.repo.HgStatusCollector;
@@ -100,26 +105,47 @@
 	@Test
 	public void testStatusCommand() throws Exception {
 		final StatusCommand sc = new StatusCommand(repo).all();
-		HgStatusCollector.Record r;
+		StatusCollector r;
 		statusParser.reset();
 		eh.run("hg", "status", "-A");
-		sc.execute(r = new HgStatusCollector.Record());
-		report("hg status -A", r, statusParser);
+		sc.execute(r = new StatusCollector());
+		report("hg status -A", r);
 		//
 		statusParser.reset();
 		int revision = 3;
 		eh.run("hg", "status", "-A", "--rev", String.valueOf(revision));
-		sc.base(revision).execute(r = new HgStatusCollector.Record());
-		report("status -A --rev " + revision, r, statusParser);
+		sc.base(revision).execute(r = new StatusCollector());
+		report("status -A --rev " + revision, r);
 		//
 		statusParser.reset();
 		eh.run("hg", "status", "-A", "--change", String.valueOf(revision));
-		sc.base(TIP).revision(revision).execute(r = new HgStatusCollector.Record());
-		report("status -A --change " + revision, r, statusParser);
+		sc.base(TIP).revision(revision).execute(r = new StatusCollector());
+		report("status -A --change " + revision, r);
 		
 		// TODO check not -A, but defaults()/custom set of modifications 
 	}
 	
+	private static class StatusCollector implements StatusCommand.Handler {
+		private final Map<StatusCommand.HgStatus.Kind, List<Path>> map = new TreeMap<StatusCommand.HgStatus.Kind, List<Path>>();
+
+		public void handleStatus(HgStatus s) {
+			List<Path> l = map.get(s.getKind());
+			if (l == null) {
+				l = new LinkedList<Path>();
+				map.put(s.getKind(), l);
+			}
+			l.add(s.getPath());
+		}
+		
+		public List<Path> get(Kind k) {
+			List<Path> rv = map.get(k);
+			if (rv == null) {
+				return Collections.emptyList();
+			}
+			return rv;
+		}
+	}
+	
 	public void testRemovedAgainstNonTip() {
 		/*
 		 status --rev N when a file added past revision N was removed ((both physically and in dirstate), but not yet committed
@@ -143,14 +169,24 @@
 		}
 		final long start2 = System.currentTimeMillis();
 		for (int i = 0; i < runs; i++) {
-			HgStatusCollector.Record r = new HgStatusCollector.Record();
+			StatusCollector r = new StatusCollector();
 			new StatusCommand(repo).all().base(3).revision(80).execute(r);
 		}
 		final long end = System.currentTimeMillis();
 		System.out.printf("'hg status -A --rev 3:80', %d runs:  Native client total %d (%d per run), Java client %d (%d)\n", runs, start2-start1, (start2-start1)/runs, end-start2, (end-start2)/runs);
 	}
 	
-	
+	private void report(String what, StatusCollector r) {
+		reportNotEqual(what + "#MODIFIED", r.get(Modified), statusParser.getModified());
+		reportNotEqual(what + "#ADDED", r.get(Added), statusParser.getAdded());
+		reportNotEqual(what + "#REMOVED", r.get(Removed), statusParser.getRemoved());
+		reportNotEqual(what + "#CLEAN", r.get(Clean), statusParser.getClean());
+		reportNotEqual(what + "#IGNORED", r.get(Ignored), statusParser.getIgnored());
+		reportNotEqual(what + "#MISSING", r.get(Missing), statusParser.getMissing());
+		reportNotEqual(what + "#UNKNOWN", r.get(Unknown), statusParser.getUnknown());
+		// FIXME test copies
+	}
+
 	private void report(String what, HgStatusCollector.Record r, StatusOutputParser statusParser) {
 		reportNotEqual(what + "#MODIFIED", r.getModified(), statusParser.getModified());
 		reportNotEqual(what + "#ADDED", r.getAdded(), statusParser.getAdded());