changeset 47:b01500fe2604

Log command output to match 'hg log'
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 14 Jan 2011 20:03:14 +0100
parents 4022c34a4804
children e34f90b9ded1
files src/com/tmate/hgkit/console/Log.java src/com/tmate/hgkit/console/Main.java src/com/tmate/hgkit/ll/Changelog.java src/com/tmate/hgkit/ll/Changeset.java src/com/tmate/hgkit/ll/HgBundle.java
diffstat 5 files changed, 150 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/src/com/tmate/hgkit/console/Log.java	Fri Jan 14 04:56:53 2011 +0100
+++ b/src/com/tmate/hgkit/console/Log.java	Fri Jan 14 20:03:14 2011 +0100
@@ -1,12 +1,17 @@
-/**
- * Copyright (c) 2010 Artem Tikhomirov 
+/*
+ * Copyright (c) 2010, 2011 Artem Tikhomirov 
  */
 package com.tmate.hgkit.console;
 
+import java.util.Formatter;
+import java.util.LinkedList;
+import java.util.List;
+
 import com.tmate.hgkit.fs.RepositoryLookup;
 import com.tmate.hgkit.ll.Changeset;
 import com.tmate.hgkit.ll.HgDataFile;
 import com.tmate.hgkit.ll.HgRepository;
+import com.tmate.hgkit.ll.Nodeid;
 
 /**
  * @author artem
@@ -22,21 +27,19 @@
 			return;
 		}
 		System.out.println(hgRepo.getLocation());
-		final Changeset.Inspector callback = new Changeset.Inspector() {
-			
-			public void next(Changeset cset) {
-				System.out.println("==>");
-				cset.dump();
-			}
-		};
+		final Dump dump = new Dump(hgRepo);
+		dump.complete = false; //cmdLineOpts;
+		dump.reverseOrder = true;
 		if (cmdLineOpts.files.isEmpty()) {
-			System.out.println("Complete history of the repo:");
-			hgRepo.getChangelog().all(callback);
+			// no revisions and no limit
+			hgRepo.getChangelog().all(dump);
+			dump.complete();
 		} else {
 			for (String fname : cmdLineOpts.files) {
 				HgDataFile f1 = hgRepo.getFileNode(fname);
 				System.out.println("History of the file: " + f1.getPath());
-				f1.history(callback);
+				f1.history(dump);
+				dump.complete();
 			}
 		}
 		//
@@ -46,4 +49,61 @@
 		//
 		//new ChangelogWalker().setFile("hello.c").setRevisionRange(1, 4).accept(new Visitor);
 	}
+
+	private static final class Dump implements Changeset.Inspector {
+		// params
+		boolean complete = false;
+		boolean reverseOrder = false;
+		// own
+		private LinkedList<String> l = new LinkedList<String>();
+		private final HgRepository repo;
+
+		public Dump(HgRepository hgRepo) {
+			this.repo = hgRepo;
+		}
+
+		public void next(int revisionNumber, Nodeid nodeid, Changeset cset) {
+			final String s = print(revisionNumber, nodeid, cset);
+			if (reverseOrder) {
+				l.addFirst(s);
+			} else {
+				System.out.print(s);
+			}
+		}
+		
+		public void complete() {
+			if (!reverseOrder) {
+				return;
+			}
+			for (String s : l) {
+				System.out.print(s);
+			}
+			l.clear();
+		}
+
+		private String print(int revNumber, Nodeid csetNodeid, Changeset cset) {
+			StringBuilder sb = new StringBuilder();
+			Formatter f = new Formatter(sb);
+			f.format("changeset:   %d:%s\n", revNumber, complete ? csetNodeid : csetNodeid.shortNotation());
+			if (complete) {
+				f.format("parent:        %s\nparent:        %s\nmanifest:     %s", "-1", "-1", cset.manifest());
+			}
+			f.format("user:        %s\ndate:        %s\n", cset.user(), cset.dateString());
+			if (complete) {
+				final List<String> files = cset.files();
+				sb.append("files:    ");
+				for (String s : files) {
+					sb.append(' ');
+					sb.append(s);
+				}
+				f.format("description:\n%s\n\n", cset.comment());
+			} else {
+				f.format("summary:     %s\n\n", cset.comment());
+			}
+			if (cset.extras() != null) {
+				f.format("extra:    " + cset.extras()); // TODO
+			}
+			return sb.toString();
+		}
+	}
 }
--- a/src/com/tmate/hgkit/console/Main.java	Fri Jan 14 04:56:53 2011 +0100
+++ b/src/com/tmate/hgkit/console/Main.java	Fri Jan 14 20:03:14 2011 +0100
@@ -10,6 +10,7 @@
 import java.io.FileInputStream;
 import java.math.BigInteger;
 import java.util.LinkedList;
+import java.util.Locale;
 import java.util.zip.Inflater;
 
 import com.tmate.hgkit.ll.Changeset;
@@ -81,7 +82,18 @@
 		System.out.println("====================>");
 		for (Changeset cset : changelog) {
 			System.out.println(">");
-			cset.dump();
+			System.out.println("User: " + cset.user());
+			System.out.println("Comment: " + cset.comment());
+			System.out.println("Manifest: " + cset.manifest());
+			System.out.printf(Locale.US, "Date: %ta %<tb %<td %<tH:%<tM:%<tS %<tY %<tz\n", cset.date());
+			System.out.println("Files: " + cset.files().size());
+			if (cset.extras() != null) {
+				System.out.println("Extra: " + cset.extras());
+			}
+			for (String s : cset.files()) {
+				System.out.print('\t');
+					System.out.println(s);
+			}
 			System.out.println("<");
 		}
 	}
--- a/src/com/tmate/hgkit/ll/Changelog.java	Fri Jan 14 04:56:53 2011 +0100
+++ b/src/com/tmate/hgkit/ll/Changelog.java	Fri Jan 14 20:03:14 2011 +0100
@@ -23,7 +23,7 @@
 			public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, byte[] data) {
 				Changeset cset = Changeset.parse(data, 0, data.length);
 				// XXX there's no guarantee for Changeset.Callback that distinct instance comes each time, consider instance reuse
-				inspector.next(cset);
+				inspector.next(revisionNumber, Nodeid.fromBinary(nodeid, 0), cset);
 			}
 		};
 		content.iterate(0, content.revisionCount() - 1, true, i);
@@ -51,7 +51,7 @@
 			public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, byte[] data) {
 				if (Arrays.binarySearch(revisions, revisionNumber) >= 0) {
 					Changeset cset = Changeset.parse(data, 0, data.length);
-					inspector.next(cset);
+					inspector.next(revisionNumber, Nodeid.fromBinary(nodeid, 0), cset);
 				}
 			}
 		};
--- a/src/com/tmate/hgkit/ll/Changeset.java	Fri Jan 14 04:56:53 2011 +0100
+++ b/src/com/tmate/hgkit/ll/Changeset.java	Fri Jan 14 20:03:14 2011 +0100
@@ -5,8 +5,12 @@
 
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
+import java.util.Formatter;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 
 /**
  * @see mercurial/changelog.py:read()
@@ -24,28 +28,67 @@
  * </pre>
  * @author artem
  */
-public class Changeset {
+public class Changeset implements Cloneable /*for those that would like to keep a copy*/ {
 	// TODO immutable
 	private /*final*/ Nodeid manifest;
 	private String user;
 	private String comment;
-	private ArrayList<String> files;
+	private List<String> files; // unmodifiable collection (otherwise #files() and implicit #clone() shall be revised)
 	private Date time;
+	private int timezone; // not sure it's of any use
 	private String extras; // TODO branch, etc.
 	
-	public void dump() {
-		System.out.println("User: " + user);
-		System.out.println("Comment: " + comment);
-		System.out.println("Manifest: " + manifest);
-		System.out.printf(Locale.US, "Date: %ta %<tb %<td %<tH:%<tM:%<tS %<tY %<tz\n", time);
-		System.out.println("Files: " + files.size());
+	private Changeset() {
+	}
+	
+	public Nodeid manifest() {
+		return manifest;
+	}
+	
+	public String user() {
+		return user;
+	}
+	
+	public String comment() {
+		return comment;
+	}
+	
+	public List<String> files() {
+		return files;
+	}
+
+	public Date date() {
+		return time;
+	}
+	
+	public String dateString() {
+		StringBuilder sb = new StringBuilder(30);
+		Formatter f = new Formatter(sb, Locale.US);
+		f.format("%ta %<tb %<td %<tH:%<tM:%<tS %<tY %<tz", time);
+		return sb.toString();
+	}
+
+	public Map<String, String> extras() {
+		return null; // TODO
+	}
+	
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		sb.append("Changeset {");
+		sb.append("User: ").append(user).append(", ");
+		sb.append("Comment: ").append(comment).append(", ");
+		sb.append("Manifest: ").append(manifest).append(", ");
+		sb.append("Date: ").append(time).append(", ");
+		sb.append("Files: ").append(files.size());
+		for (String s : files) {
+			sb.append(", ").append(s);
+		}
 		if (extras != null) {
-			System.out.println("Extra: " + extras);
+			sb.append(", Extra: ").append(extras);
 		}
-		for (String s : files) {
-			System.out.print('\t');
-			System.out.println(s);
-		}
+		sb.append("}");
+		return sb.toString();
 	}
 
 	public static Changeset parse(byte[] data, int offset, int length) {
@@ -81,10 +124,10 @@
 			space2 = _timeString.length();
 		}
 		long unixTime = Long.parseLong(_timeString.substring(0, space1)); // XXX Float, perhaps
-		int timezone = Integer.parseInt(_timeString.substring(space1+1, space2));
+		int _timezone = Integer.parseInt(_timeString.substring(space1+1, space2));
 		// XXX not sure need to add timezone here - I can't figure out whether Hg keeps GMT time, and records timezone just for info, or unixTime is taken local
 		// on commit and timezone is recorded to adjust it to UTC.
-		Date _time = new Date((unixTime + timezone) * 1000);
+		Date _time = new Date(unixTime * 1000);
 		String _extras = space2 < _timeString.length() ? _timeString.substring(space2+1) : null;
 		
 		//
@@ -115,7 +158,8 @@
 		this.manifest = _nodeid;
 		this.user = _user;
 		this.time = _time;
-		this.files = _files;
+		this.timezone = _timezone;
+		this.files = Collections.unmodifiableList(_files);
 		this.comment = _comment;
 		this.extras = _extras;
 	}
@@ -132,6 +176,7 @@
 	public interface Inspector {
 		// first(), last(), single().
 		// <T>
-		void next(Changeset cset);
+		// TODO describe whether cset is new instance each time
+		void next(int revisionNumber, Nodeid nodeid, Changeset cset);
 	}
 }
--- a/src/com/tmate/hgkit/ll/HgBundle.java	Fri Jan 14 04:56:53 2011 +0100
+++ b/src/com/tmate/hgkit/ll/HgBundle.java	Fri Jan 14 20:03:14 2011 +0100
@@ -51,7 +51,7 @@
 					throw new IllegalStateException("Integrity check failed on " + bundleFile + ", node:" + ge.node());
 				}
 				Changeset cs = Changeset.parse(csetContent, 0, csetContent.length);
-				cs.dump();
+				System.out.println(cs.toString());
 				baseRevContent = csetContent;
 			}
 		} finally {