changeset 316:ee6b467c1a5f

Supply HGFileRevision with copy information when possible, calculate it otherwise
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 28 Sep 2011 13:09:16 +0200
parents 8952f89be195
children 09628675bcee
files src/org/tmatesoft/hg/core/HgChangeset.java src/org/tmatesoft/hg/core/HgFileRevision.java src/org/tmatesoft/hg/core/HgLogCommand.java src/org/tmatesoft/hg/repo/HgStatusCollector.java src/org/tmatesoft/hg/repo/HgStatusInspector.java
diffstat 5 files changed, 68 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/core/HgChangeset.java	Wed Sep 28 12:18:21 2011 +0200
+++ b/src/org/tmatesoft/hg/core/HgChangeset.java	Wed Sep 28 13:09:16 2011 +0200
@@ -19,6 +19,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
 import org.tmatesoft.hg.repo.HgChangelog;
@@ -195,14 +196,15 @@
 			if (nid == null) {
 				throw new HgBadStateException();
 			}
-			modified.add(new HgFileRevision(repo, nid, s));
+			modified.add(new HgFileRevision(repo, nid, s, null));
 		}
+		final Map<Path, Path> copied = r.getCopied();
 		for (Path s : r.getAdded()) {
 			Nodeid nid = r.nodeidAfterChange(s);
 			if (nid == null) {
 				throw new HgBadStateException();
 			}
-			added.add(new HgFileRevision(repo, nid, s));
+			added.add(new HgFileRevision(repo, nid, s, copied.get(s)));
 		}
 		for (Path s : r.getRemoved()) {
 			// with Path from getRemoved, may just copy
--- a/src/org/tmatesoft/hg/core/HgFileRevision.java	Wed Sep 28 12:18:21 2011 +0200
+++ b/src/org/tmatesoft/hg/core/HgFileRevision.java	Wed Sep 28 13:09:16 2011 +0200
@@ -17,6 +17,7 @@
 package org.tmatesoft.hg.core;
 
 import org.tmatesoft.hg.repo.HgDataFile;
+import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgRepository;
 import org.tmatesoft.hg.util.ByteChannel;
 import org.tmatesoft.hg.util.CancelledException;
@@ -32,16 +33,25 @@
 	private final HgRepository repo;
 	private final Nodeid revision;
 	private final Path path;
-	
+	private Path origin;
+	private Boolean isCopy = null; // null means not yet known
+
 	public HgFileRevision(HgRepository hgRepo, Nodeid rev, Path p) {
 		if (hgRepo == null || rev == null || p == null) {
 			// since it's package local, it is our code to blame for non validated arguments
-			throw new HgBadStateException();
+			throw new IllegalArgumentException();
 		}
 		repo = hgRepo;
 		revision = rev;
 		path = p;
 	}
+
+	// this cons shall be used when we know whether p was a copy. Perhaps, shall pass Map<Path,Path> instead to stress orig argument is not optional  
+	HgFileRevision(HgRepository hgRepo, Nodeid rev, Path p, Path orig) {
+		this(hgRepo, rev, p);
+		isCopy = Boolean.valueOf(orig == null);
+		origin = orig; 
+	}
 	
 	public Path getPath() {
 		return path;
@@ -49,10 +59,42 @@
 	public Nodeid getRevision() {
 		return revision;
 	}
+	public boolean wasCopied() {
+		if (isCopy == null) {
+			checkCopy();
+		}
+		return isCopy.booleanValue();
+	}
+	/**
+	 * @return <code>null</code> if {@link #wasCopied()} is <code>false</code>, name of the copy source otherwise.
+	 */
+	public Path getOriginIfCopy() {
+		if (wasCopied()) {
+			return origin;
+		}
+		return null;
+	}
+
 	public void putContentTo(ByteChannel sink) throws HgDataStreamException, CancelledException {
 		HgDataFile fn = repo.getFileNode(path);
 		int localRevision = fn.getLocalRevision(revision);
 		fn.contentWithFilters(localRevision, sink);
 	}
 
+	private void checkCopy() {
+		HgDataFile fn = repo.getFileNode(path);
+		try {
+			if (fn.isCopy()) {
+				if (fn.getRevision(0).equals(revision)) {
+					// this HgFileRevision represents first revision of the copy
+					isCopy = Boolean.TRUE;
+					origin = fn.getCopySourceName();
+					return;
+				}
+			}
+		} catch (HgDataStreamException ex) {
+			HgInternals.getContext(repo).getLog().error(getClass(), ex, null);
+		}
+		isCopy = Boolean.FALSE;
+	}
 }
--- a/src/org/tmatesoft/hg/core/HgLogCommand.java	Wed Sep 28 12:18:21 2011 +0200
+++ b/src/org/tmatesoft/hg/core/HgLogCommand.java	Wed Sep 28 13:09:16 2011 +0200
@@ -226,7 +226,7 @@
 					do {
 						if (handler instanceof FileHistoryHandler) {
 							HgFileRevision src = new HgFileRevision(repo, fileNode.getCopySourceRevision(), fileNode.getCopySourceName());
-							HgFileRevision dst = new HgFileRevision(repo, fileNode.getRevision(0), fileNode.getPath());
+							HgFileRevision dst = new HgFileRevision(repo, fileNode.getRevision(0), fileNode.getPath(), src.getPath());
 							try {
 								((FileHistoryHandler) handler).copy(src, dst);
 							} catch (RuntimeException ex) {
--- a/src/org/tmatesoft/hg/repo/HgStatusCollector.java	Wed Sep 28 12:18:21 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgStatusCollector.java	Wed Sep 28 13:09:16 2011 +0200
@@ -311,6 +311,15 @@
 
 	// XXX for r1..r2 status, only modified, added, removed (and perhaps, clean) make sense
 	// XXX Need to specify whether copy targets are in added or not (@see Inspector#copied above)
+	/**
+	 * Straightforward {@link HgStatusInspector} implementation that collects all status values.
+	 * 
+	 * <p>Naturally, {@link Record Records} originating from {@link HgStatusCollector} would report only <em>modified, added,
+	 * removed</em> and <em>clean</em> values, other are available only when using {@link Record} with {@link HgWorkingCopyStatusCollector}.
+	 * 
+	 * <p>Note, this implementation records copied files as added, thus key values in {@link #getCopied()} map are subset of paths
+	 * from {@link #getAdded()}.  
+	 */
 	public static class Record implements HgStatusInspector {
 		private List<Path> modified, added, removed, clean, missing, unknown, ignored;
 		private Map<Path, Path> copied;
@@ -362,6 +371,9 @@
 			return proper(removed);
 		}
 
+		/**
+		 * Map files from {@link #getAdded()} to their original filenames, if were copied/moved.
+		 */
 		public Map<Path,Path> getCopied() {
 			if (copied == null) {
 				return Collections.emptyMap();
@@ -385,7 +397,7 @@
 			return proper(ignored);
 		}
 		
-		private List<Path> proper(List<Path> l) {
+		private static List<Path> proper(List<Path> l) {
 			if (l == null) {
 				return Collections.emptyList();
 			}
--- a/src/org/tmatesoft/hg/repo/HgStatusInspector.java	Wed Sep 28 12:18:21 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgStatusInspector.java	Wed Sep 28 13:09:16 2011 +0200
@@ -27,8 +27,12 @@
 public interface HgStatusInspector {
 	void modified(Path fname);
 	void added(Path fname);
-	// XXX need to specify whether StatusCollector invokes added() along with copied or not!
-	void copied(Path fnameOrigin, Path fnameAdded); // if copied files of no interest, should delegate to self.added(fnameAdded);
+	/**
+	 * This method is invoked for files that we added as a result of a copy/move operation, and it's the sole
+	 * method invoked in this case, that is {@link #added(Path)} method is NOT invoked along with it.
+	 * If copied files of no interest, it is implementation responsibility to delegate to <code>this.added(fnameAdded)</code>
+	 */
+	void copied(Path fnameOrigin, Path fnameAdded);
 	void removed(Path fname);
 	void clean(Path fname);
 	void missing(Path fname); // aka deleted (tracked by Hg, but not available in FS any more