changeset 5:fc265ddeab26

File content and non-effective, although working, patch application
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 21 Dec 2010 05:11:06 +0100
parents aa1912c70b36
children 5abe5af181bd
files design.txt src/com/tmate/hgkit/console/Cat.java src/com/tmate/hgkit/ll/Changeset.java src/com/tmate/hgkit/ll/HgDataFile.java src/com/tmate/hgkit/ll/HgRepository.java src/com/tmate/hgkit/ll/RevlogStream.java
diffstat 6 files changed, 90 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/design.txt	Mon Dec 20 04:20:52 2010 +0100
+++ b/design.txt	Tue Dec 21 05:11:06 2010 +0100
@@ -25,3 +25,4 @@
 
 input stream impl + lifecycle
 delta merge
+Changeset to get index (local revision number)
\ No newline at end of file
--- a/src/com/tmate/hgkit/console/Cat.java	Mon Dec 20 04:20:52 2010 +0100
+++ b/src/com/tmate/hgkit/console/Cat.java	Tue Dec 21 05:11:06 2010 +0100
@@ -4,6 +4,7 @@
 package com.tmate.hgkit.console;
 
 import com.tmate.hgkit.fs.RepositoryLookup;
+import com.tmate.hgkit.ll.HgDataFile;
 import com.tmate.hgkit.ll.HgRepository;
 
 /**
@@ -14,12 +15,26 @@
 
 	public static void main(String[] args) throws Exception {
 		RepositoryLookup repoLookup = new RepositoryLookup();
-		HgRepository hgRepo = repoLookup.detect(args);
+		RepositoryLookup.Options cmdLineOpts = RepositoryLookup.Options.parse(args);
+		HgRepository hgRepo = repoLookup.detect(cmdLineOpts);
 		if (hgRepo.isInvalid()) {
 			System.err.printf("Can't find repository in: %s\n", hgRepo.getLocation());
 			return;
 		}
-		byte[] tipContent = hgRepo.getFileNode("hello.c").content();
-		System.out.println(new String(tipContent));
+		for (String fname : cmdLineOpts.files) {
+			System.out.println(fname);
+			HgDataFile fn = hgRepo.getFileNode(fname);
+			if (fn.exists()) {
+				int total = fn.getRevisionCount();
+				System.out.printf("Total revisions: %d\n", total);
+				for (int i = 0; i < total; i++) {
+					byte[] content = fn.content(i);
+					System.out.println("==========>");
+					System.out.println(new String(content));
+				}
+			} else {
+				System.out.println(">>>Not found!");
+			}
+		}
 	}
 }
--- a/src/com/tmate/hgkit/ll/Changeset.java	Mon Dec 20 04:20:52 2010 +0100
+++ b/src/com/tmate/hgkit/ll/Changeset.java	Tue Dec 21 05:11:06 2010 +0100
@@ -44,30 +44,35 @@
 
 	public static Changeset parse(byte[] data, int offset, int length) {
 		Changeset rv = new Changeset();
+		rv.init(data, offset, length);
+		return rv;
+	}
+
+	/*package-local*/ void init(byte[] data, int offset, int length) {
 		final int bufferEndIndex = offset + length;
 		final byte lineBreak = (byte) '\n';
 		int breakIndex1 = indexOf(data, lineBreak, offset, bufferEndIndex);
 		if (breakIndex1 == -1) {
 			throw new IllegalArgumentException("Bad Changeset data");
 		}
-		rv.nodeid = Nodeid.fromAscii(data, 0, breakIndex1);
+		Nodeid _nodeid = Nodeid.fromAscii(data, 0, breakIndex1);
 		int breakIndex2 = indexOf(data, lineBreak, breakIndex1+1, bufferEndIndex);
 		if (breakIndex2 == -1) {
 			throw new IllegalArgumentException("Bad Changeset data");
 		}
-		rv.user = new String(data, breakIndex1+1, breakIndex2 - breakIndex1 - 1);
+		String _user = new String(data, breakIndex1+1, breakIndex2 - breakIndex1 - 1);
 		int breakIndex3 = indexOf(data, lineBreak, breakIndex2+1, bufferEndIndex);
 		if (breakIndex3 == -1) {
 			throw new IllegalArgumentException("Bad Changeset data");
 		}
-		rv.timezone = new String(data, breakIndex2+1, breakIndex3 - breakIndex2 - 1);
+		String _timezone = new String(data, breakIndex2+1, breakIndex3 - breakIndex2 - 1);
 		
 		//
 		int lastStart = breakIndex3 + 1;
 		int breakIndex4 = indexOf(data, lineBreak, lastStart, bufferEndIndex);
-		rv.files = new ArrayList<String>(5);
+		ArrayList<String> _files = new ArrayList<String>(5);
 		while (breakIndex4 != -1 && breakIndex4 + 1 < bufferEndIndex) {
-			rv.files.add(new String(data, lastStart, breakIndex4 - lastStart));
+			_files.add(new String(data, lastStart, breakIndex4 - lastStart));
 			lastStart = breakIndex4 + 1;
 			if (data[breakIndex4 + 1] == lineBreak) {
 				// found \n\n
@@ -79,13 +84,19 @@
 		if (breakIndex4 == -1 || breakIndex4 >= bufferEndIndex) {
 			throw new IllegalArgumentException("Bad Changeset data");
 		}
+		String _comment;
 		try {
-			rv.comment = new String(data, breakIndex4+2, bufferEndIndex - breakIndex4 - 2, "UTF-8");
+			_comment = new String(data, breakIndex4+2, bufferEndIndex - breakIndex4 - 2, "UTF-8");
 		} catch (UnsupportedEncodingException ex) {
-			rv.comment = "";
+			_comment = "";
 			throw new IllegalStateException("Could hardly happen");
 		}
-		return rv;
+		// change this instance at once, don't leave it partially changes in case of error
+		this.nodeid = _nodeid;
+		this.user = _user;
+		this.timezone = _timezone;
+		this.files = _files;
+		this.comment = _comment;
 	}
 
 	private static int indexOf(byte[] src, byte what, int startOffset, int endIndex) {
--- a/src/com/tmate/hgkit/ll/HgDataFile.java	Mon Dec 20 04:20:52 2010 +0100
+++ b/src/com/tmate/hgkit/ll/HgDataFile.java	Tue Dec 21 05:11:06 2010 +0100
@@ -3,6 +3,8 @@
  */
 package com.tmate.hgkit.ll;
 
+import static com.tmate.hgkit.ll.HgRepository.TIP;
+
 /**
  * Extends Revlog/uses RevlogStream?
  * ? name:HgFileNode?
@@ -31,14 +33,23 @@
 		return path; // hgRepo.backresolve(this) -> name?
 	}
 
-	private static final int TIP = -2;
+	public int getRevisionCount() {
+		return content.revisionCount();
+	}
 
 	public byte[] content() {
 		return content(TIP);
 	}
 	
 	public byte[] content(int revision) {
-		throw HgRepository.notImplemented();
+		final byte[][] dataPtr = new byte[1][];
+		Revlog.Inspector insp = new Revlog.Inspector() {
+			public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, byte[] data) {
+				dataPtr[0] = data;
+			}
+		};
+		content.iterate(revision, revision, true, insp);
+		return dataPtr[0];
 	}
 
 	public void history(Changeset.Inspector inspector) {
--- a/src/com/tmate/hgkit/ll/HgRepository.java	Mon Dec 20 04:20:52 2010 +0100
+++ b/src/com/tmate/hgkit/ll/HgRepository.java	Tue Dec 21 05:11:06 2010 +0100
@@ -9,6 +9,8 @@
  */
 public abstract class HgRepository {
 
+	public static final int TIP = -1;
+
 	// temp aux marker method
 	public static IllegalStateException notImplemented() {
 		return new IllegalStateException("Not implemented");
--- a/src/com/tmate/hgkit/ll/RevlogStream.java	Mon Dec 20 04:20:52 2010 +0100
+++ b/src/com/tmate/hgkit/ll/RevlogStream.java	Tue Dec 21 05:11:06 2010 +0100
@@ -3,6 +3,8 @@
  */
 package com.tmate.hgkit.ll;
 
+import static com.tmate.hgkit.ll.HgRepository.TIP;
+
 import java.io.BufferedInputStream;
 import java.io.DataInput;
 import java.io.DataInputStream;
@@ -74,9 +76,12 @@
 		if (indexSize == 0) {
 			return;
 		}
-		if (end == -1 /*FIXME TIP*/) {
+		if (end == TIP) {
 			end = indexSize - 1;
 		}
+		if (start == TIP) {
+			start = indexSize - 1;
+		}
 		if (start < 0 || start >= indexSize) {
 			throw new IllegalArgumentException("Bad left range boundary " + start);
 		}
@@ -91,10 +96,17 @@
 			diData = getDataStream();
 		}
 		try {
-			int skipped = diIndex.skipBytes(inline ? (int) index.get(start).offset : start * 64);
 			byte[] lastData = null;
-			for (int i = start; i <= end; i++ ) {
-				IndexEntry ie = index.get(i);
+			int i;
+			boolean extraReadsToBaseRev = false;
+			if (needData && index.get(start).baseRevision < start) {
+				i = index.get(start).baseRevision;
+				extraReadsToBaseRev = true;
+			} else {
+				i = start;
+			}
+			diIndex.skipBytes(inline ? (int) index.get(i).offset : start * 64);
+			for (; i <= end; i++ ) {
 				long l = diIndex.readLong();
 				long offset = l >>> 16;
 				int flags = (int) (l & 0X0FFFF);
@@ -114,7 +126,7 @@
 					if (inline) {
 						diIndex.readFully(dataBuf);
 					} else {
-						diData.skipBytes((int) ie.offset); // FIXME not skip but seek!!! (skip would work only for the first time)
+						diData.skipBytes((int) index.get(i).offset); // FIXME not skip but seek!!! (skip would work only for the first time)
 						diData.readFully(dataBuf);
 					}
 					if (dataBuf[0] == 0x78 /* 'x' */) {
@@ -145,23 +157,14 @@
 						int patchElementIndex = 0;
 						do {
 							final int x = patchElementIndex; // shorthand
-							int p1 = (data[x] << 24) | (data[x+1] << 16) | (data[x+2] << 8) | data[x+3];
-							int p2 = (data[x+4] << 24) | (data[x+5] << 16) | (data[x+6] << 8) | data[x+7];
-							int len = (data[x+8] << 24) | (data[x+9] << 16) | (data[x+10] << 8) | data[x+11];
+							int p1 =  ((data[x] & 0xFF)<< 24)    | ((data[x+1] & 0xFF) << 16) | ((data[x+2] & 0xFF) << 8)  | (data[x+3] & 0xFF);
+							int p2 =  ((data[x+4] & 0xFF) << 24) | ((data[x+5] & 0xFF) << 16) | ((data[x+6] & 0xFF) << 8)  | (data[x+7] & 0xFF);
+							int len = ((data[x+8] & 0xFF) << 24) | ((data[x+9] & 0xFF) << 16) | ((data[x+10] & 0xFF) << 8) | (data[x+11] & 0xFF);
 							patchElementIndex += 12 + len;
 							patches.add(new PatchRecord(p1, p2, len, data, x+12));
 						} while (patchElementIndex < data.length);
 						//
-						byte[] baseRevContent;
-						if (baseRevision == i - 1) {
-							baseRevContent = lastData;
-						} else {
-							// FIXME implement delta collection from few revisions
-							// read baseRevision plus all deltas between this revision and base. Need to do this effectively.
-							throw HgRepository.notImplemented();
-						}
-						
-						// FIXME need to collect all patches between baseRevision and current version 
+						byte[] baseRevContent = lastData;
 						data = apply(baseRevContent, patches);
 					}
 				} else {
@@ -169,7 +172,9 @@
 						diIndex.skipBytes(compressedLen);
 					}
 				}
-				inspector.next(i, actualLen, baseRevision, linkRevision, parent1Revision, parent2Revision, buf, data);
+				if (!extraReadsToBaseRev || i >= start) {
+					inspector.next(i, actualLen, baseRevision, linkRevision, parent1Revision, parent2Revision, buf, data);
+				}
 				lastData = data;
 			}
 		} catch (EOFException ex) {
@@ -196,19 +201,20 @@
 			long offset = 0; // first offset is always 0, thus Hg uses it for other purposes
 			while(true) { // EOFExcepiton should get us outta here. FIXME Our inputstream should has explicit no-more-data indicator
 				int compressedLen = di.readInt();
-				// 8+4 = 12 bytes total read
-//				int actualLen = di.readInt();
-//				int baseRevision = di.readInt();
+				// 8+4 = 12 bytes total read here
+				int actualLen = di.readInt();
+				int baseRevision = di.readInt();
+				// 12 + 8 = 20 bytes read here
 //				int linkRevision = di.readInt();
 //				int parent1Revision = di.readInt();
 //				int parent2Revision = di.readInt();
 //				byte[] nodeid = new byte[32];
 				if (inline) {
-					res.add(new IndexEntry(offset + 64*res.size(), compressedLen));
-					di.skipBytes(5*4 + 32 + compressedLen); // Check: 52 (skip) + 12 (read) = 64 (total RevlogNG record size)
+					res.add(new IndexEntry(offset + 64*res.size(), baseRevision));
+					di.skipBytes(3*4 + 32 + compressedLen); // Check: 44 (skip) + 20 (read) = 64 (total RevlogNG record size)
 				} else {
-					res.add(new IndexEntry(offset, compressedLen));
-					di.skipBytes(5*4 + 32);
+					res.add(new IndexEntry(offset, baseRevision));
+					di.skipBytes(3*4 + 32);
 				}
 				long l = di.readLong();
 				offset = l >>> 16;
@@ -241,13 +247,15 @@
 
 
 	// perhaps, package-local or protected, if anyone else from low-level needs them
+	// XXX think over if we should keep offset in case of separate data file - we read the field anyway. Perhaps, distinct entry classes for Inline and non-inline indexes?
 	private static class IndexEntry {
 		public final long offset; // for separate .i and .d - copy of index record entry, for inline index - actual offset of the record in the .i file (record entry + revision * record size))
-		public final int length; // data past fixed record (need to decide whether including header size or not), and whether length is of compressed data or not
+		//public final int length; // data past fixed record (need to decide whether including header size or not), and whether length is of compressed data or not
+		public final int baseRevision;
 
-		public IndexEntry(long o, int l) {
+		public IndexEntry(long o, int baseRev) {
 			offset = o;
-			length = l;
+			baseRevision = baseRev;
 		}
 	}