diff src/org/tmatesoft/hg/core/HgFileInformer.java @ 248:3fbfce107f94

Issue 8: Means to find out information about given file at specific changeset. Inner ManifestRevisionInspector got promoted to ManifestRevision
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 12 Aug 2011 18:48:57 +0200
parents
children 8c951645bea0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tmatesoft/hg/core/HgFileInformer.java	Fri Aug 12 18:48:57 2011 +0200
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2011 TMate Software Ltd
+ *  
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * For information on how to redistribute this software under
+ * the terms of a license other than GNU General Public License
+ * contact TMate Software at support@hg4j.com
+ */
+package org.tmatesoft.hg.core;
+
+import org.tmatesoft.hg.internal.ManifestRevision;
+import org.tmatesoft.hg.repo.HgDataFile;
+import org.tmatesoft.hg.repo.HgRepository;
+import org.tmatesoft.hg.util.Path;
+
+/**
+ * Primary purpose is to provide information about file revisions at specific changeset. Multiple {@link #check(Path)} calls 
+ * are possible once {@link #changeset(Nodeid)} (and optionally, {@link #followRenames(boolean)}) were set.
+ *
+ * @author Artem Tikhomirov
+ * @author TMate Software Ltd.
+ */
+public class HgFileInformer {
+
+	private final HgRepository repo;
+	private boolean followRenames;
+	private Nodeid cset;
+	private ManifestRevision cachedManifest;
+	private HgFileRevision fileRevision;
+	private boolean checked, renamed; 
+
+	public HgFileInformer(HgRepository hgRepo) {
+		repo = hgRepo;
+	}
+
+	public HgFileInformer changeset(Nodeid nid) {
+		if (nid == null || Nodeid.NULL.equals(nid)) {
+			throw new IllegalArgumentException(); 
+		}
+		cset = nid;
+		cachedManifest = null;
+		fileRevision = null;
+		return this;
+	}
+	
+	public HgFileInformer followRenames(boolean follow) {
+		followRenames = follow;
+		fileRevision = null;
+		return this;
+	}
+
+	public boolean check(Path file) { // XXX IStatus instead of boolean?
+		fileRevision = null;
+		checked = false;
+		renamed = false;
+		if (cset == null || file == null || file.isDirectory()) {
+			throw new IllegalArgumentException();
+		}
+		HgDataFile dataFile = repo.getFileNode(file);
+		if (!dataFile.exists()) {
+			return false;
+		}
+		if (cachedManifest == null) {
+			int csetRev = repo.getChangelog().getLocalRevision(cset);
+			cachedManifest = new ManifestRevision(null, null); // XXX how about context and cached manifest revisions
+			repo.getManifest().walk(csetRev, csetRev, cachedManifest);
+			// cachedManifest shall be meaningful - changelog.getLocalRevision above ensures we've got version that exists.
+		}
+		Nodeid toExtract = cachedManifest.nodeid(file.toString());
+		try {
+			if (toExtract == null && followRenames) {
+				while (toExtract == null && dataFile.isCopy()) {
+					renamed = true;
+					file = dataFile.getCopySourceName();
+					dataFile = repo.getFileNode(file);
+					toExtract = cachedManifest.nodeid(file.toString());
+				}
+			}
+		} catch (HgDataStreamException ex) {
+			ex.printStackTrace(); // XXX log(INFO) 
+			// ignore now, however if there's IStatus retval, might report error with reasonable explanation.
+			// Perhaps, may add a String reason() method with such info?
+		}
+		checked = true;
+		if (toExtract != null) {
+			fileRevision = new HgFileRevision(repo, toExtract, dataFile.getPath());
+			return true;
+		} // else String.format("File %s nor its origins were not known at repository %s revision", file, cset.shortNotation())
+		return false;
+	}
+	
+	/**
+	 * @return result of the last {@link #check(Path)} call.
+	 */
+	public boolean exists() {
+		assertCheckRan();
+		return fileRevision != null;
+	}
+	
+	/**
+	 * @return <code>true</code> if checked file was known by another name at the time of specified changeset.
+	 */
+	public boolean hasAnotherName() {
+		assertCheckRan();
+		return renamed;
+	}
+
+	/**
+	 * @return holder for file revision information
+	 */
+	public HgFileRevision getFileRevision() {
+		assertCheckRan();
+		return fileRevision;
+	}
+
+	/**
+	 * Name of the checked file as it was known at the time of the specified changeset.
+	 * 
+	 * @return handy shortcut for <code>getFileRevision().getPath()</code>
+	 */
+	public Path filename() {
+		assertCheckRan();
+		return fileRevision.getPath();
+	}
+	
+	/**
+	 * Revision of the checked file
+	 * 
+	 * @return handy shortcut for <code>getFileRevision().getRevision()</code>
+	 */
+	public Nodeid revision() {
+		assertCheckRan();
+		return fileRevision.getRevision();
+	}
+
+	private void assertCheckRan() {
+		if (!checked) {
+			throw new HgBadStateException("Shall invoke #check(Path) first");
+		}
+	}
+}