# HG changeset patch # User Artem Tikhomirov # Date 1317208156 -7200 # Node ID ee6b467c1a5f884020b43c3dca90bbb39d338f9f # Parent 8952f89be195e2c62f42b46fafb0b00d0b4288c2 Supply HGFileRevision with copy information when possible, calculate it otherwise diff -r 8952f89be195 -r ee6b467c1a5f src/org/tmatesoft/hg/core/HgChangeset.java --- 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 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 diff -r 8952f89be195 -r ee6b467c1a5f src/org/tmatesoft/hg/core/HgFileRevision.java --- 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 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 null if {@link #wasCopied()} is false, 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; + } } diff -r 8952f89be195 -r ee6b467c1a5f src/org/tmatesoft/hg/core/HgLogCommand.java --- 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) { diff -r 8952f89be195 -r ee6b467c1a5f src/org/tmatesoft/hg/repo/HgStatusCollector.java --- 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. + * + *

Naturally, {@link Record Records} originating from {@link HgStatusCollector} would report only modified, added, + * removed and clean values, other are available only when using {@link Record} with {@link HgWorkingCopyStatusCollector}. + * + *

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 modified, added, removed, clean, missing, unknown, ignored; private Map copied; @@ -362,6 +371,9 @@ return proper(removed); } + /** + * Map files from {@link #getAdded()} to their original filenames, if were copied/moved. + */ public Map getCopied() { if (copied == null) { return Collections.emptyMap(); @@ -385,7 +397,7 @@ return proper(ignored); } - private List proper(List l) { + private static List proper(List l) { if (l == null) { return Collections.emptyList(); } diff -r 8952f89be195 -r ee6b467c1a5f src/org/tmatesoft/hg/repo/HgStatusInspector.java --- 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 this.added(fnameAdded) + */ + 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