diff src/org/tmatesoft/hg/repo/HgManifest.java @ 232:b7347daa50e3

Allow to cat a file with changeset revision
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 02 Jun 2011 05:13:39 +0200
parents 373e07cd3991
children a620f0663a37
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/HgManifest.java	Wed Jun 01 05:44:25 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgManifest.java	Thu Jun 02 05:13:39 2011 +0200
@@ -18,6 +18,7 @@
 
 import static org.tmatesoft.hg.repo.HgRepository.TIP;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -25,9 +26,11 @@
 import org.tmatesoft.hg.core.HgBadStateException;
 import org.tmatesoft.hg.core.Nodeid;
 import org.tmatesoft.hg.internal.DataAccess;
+import org.tmatesoft.hg.internal.Experimental;
 import org.tmatesoft.hg.internal.Lifecycle;
 import org.tmatesoft.hg.internal.Pool;
 import org.tmatesoft.hg.internal.RevlogStream;
+import org.tmatesoft.hg.util.Path;
 
 
 /**
@@ -57,6 +60,7 @@
 		content.iterate(start0, end0, true, new ManifestParser(inspector));
 	}
 	
+	// manifest revision number that corresponds to the given changeset
 	/*package-local*/ int fromChangelog(int revisionNumber) {
 		if (HgInternals.wrongLocalRevision(revisionNumber)) {
 			throw new IllegalArgumentException(String.valueOf(revisionNumber));
@@ -68,6 +72,48 @@
 		return revisionMap.at(revisionNumber);
 	}
 	
+	/**
+	 * Extracts file revision as it was known at the time of given changeset.
+	 * 
+	 * @param revisionNumber local changeset index 
+	 * @param file path to file in question
+	 * @return file revision or <code>null</code> if manifest at specified revision doesn't list such file
+	 */
+	@Experimental(reason="Perhaps, HgDataFile shall own this method")
+	public Nodeid getFileRevision(int revisionNumber, final Path file) {
+		int rev = fromChangelog(revisionNumber);
+		final Nodeid[] rv = new Nodeid[] { null };
+		content.iterate(rev, rev, true, new RevlogStream.Inspector() {
+			
+			public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) {
+				ByteArrayOutputStream bos = new ByteArrayOutputStream();
+				try {
+					byte b;
+					while (!data.isEmpty() && (b = data.readByte()) != '\n') {
+						if (b != 0) {
+							bos.write(b);
+						} else {
+							String fname = new String(bos.toByteArray());
+							bos.reset();
+							if (file.toString().equals(fname)) {
+								byte[] nid = new byte[40];  
+								data.readBytes(nid, 0, 40);
+								rv[0] = Nodeid.fromAscii(nid, 0, 40);
+								break;
+							}
+							// else skip to the end of line
+							while (!data.isEmpty() && (b = data.readByte()) != '\n')
+								;
+						}
+					}
+				} catch (IOException ex) {
+					throw new HgBadStateException(ex);
+				}
+			}
+		});
+		return rv[0];
+	}
+			
 	public interface Inspector {
 		boolean begin(int mainfestRevision, Nodeid nid, int changelogRevision);
 		boolean next(Nodeid nid, String fname, String flags);