changeset 239:df9d2854d3d6

Initial access to subrepositories
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 16 Jun 2011 04:23:51 +0200
parents 4817d4ccc50e
children 29231022fec8
files cmdline/org/tmatesoft/hg/console/Main.java src/org/tmatesoft/hg/internal/SubrepoManager.java src/org/tmatesoft/hg/repo/HgRepository.java src/org/tmatesoft/hg/repo/HgSubrepoLocation.java
diffstat 4 files changed, 260 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/cmdline/org/tmatesoft/hg/console/Main.java	Wed Jun 15 18:06:39 2011 +0200
+++ b/cmdline/org/tmatesoft/hg/console/Main.java	Thu Jun 16 04:23:51 2011 +0200
@@ -41,6 +41,8 @@
 import org.tmatesoft.hg.repo.HgRepository;
 import org.tmatesoft.hg.repo.HgStatusCollector;
 import org.tmatesoft.hg.repo.HgStatusInspector;
+import org.tmatesoft.hg.repo.HgSubrepoLocation;
+import org.tmatesoft.hg.repo.HgSubrepoLocation.Kind;
 import org.tmatesoft.hg.repo.HgWorkingCopyStatusCollector;
 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
 import org.tmatesoft.hg.util.Pair;
@@ -70,7 +72,8 @@
 
 	public static void main(String[] args) throws Exception {
 		Main m = new Main(args);
-		m.testReadWorkingCopy();
+		m.testSubrepos();
+//		m.testReadWorkingCopy();
 //		m.testParents();
 //		m.testEffectiveFileLog();
 //		m.testCatAtCsetRevision();
@@ -86,7 +89,24 @@
 //		m.dumpCompleteManifestHigh();
 //		m.bunchOfTests();
 	}
-	
+
+	private void testSubrepos() throws Exception {
+		for (HgSubrepoLocation l : hgRepo.getSubrepositories()) {
+			System.out.println(l.getLocation());
+			System.out.println(l.getSource());
+			System.out.println(l.getType());
+			System.out.println(l.isCommitted() ? l.getRevision() : "not yet committed");
+			if (l.getType() == Kind.Hg) {
+				HgRepository r = l.getRepo();
+				System.out.printf("%s has %d revisions\n", l.getLocation(), r.getChangelog().getLastRevision() + 1);
+				if (r.getChangelog().getLastRevision() >= 0) {
+					final RawChangeset c = r.getChangelog().range(TIP, TIP).get(0);
+					System.out.printf("TIP: %s %s %s\n", c.user(), c.dateString(), c.comment());
+				}
+			}
+		}
+	}
+
 	private void testReadWorkingCopy() throws Exception {
 		for (String fname : cmdLineOpts.getList("")) {
 			HgDataFile fn = hgRepo.getFileNode(fname);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tmatesoft/hg/internal/SubrepoManager.java	Thu Jun 16 04:23:51 2011 +0200
@@ -0,0 +1,129 @@
+/*
+ * 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.internal;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.tmatesoft.hg.repo.HgRepository;
+import org.tmatesoft.hg.repo.HgSubrepoLocation;
+
+/**
+ * 
+ * @author Artem Tikhomirov
+ * @author TMate Software Ltd.
+ */
+public class SubrepoManager /* XXX RepoChangeNotifier, RepoChangeListener */{
+
+	private final HgRepository repo;
+	private List<HgSubrepoLocation> subRepos;
+
+	public SubrepoManager(HgRepository hgRepo) {
+		assert hgRepo != null;
+		repo = hgRepo;
+	}
+
+	private List<HgSubrepoLocation> readActualState() {
+		File hgsubFile = new File(repo.getWorkingDir(), ".hgsub");
+		if (!hgsubFile.canRead()) {
+			return Collections.emptyList();
+		}
+		try {
+			Map<String, String> state; // path -> revision
+			File hgstateFile = new File(repo.getWorkingDir(), ".hgsubstate");
+			if (hgstateFile.canRead()) {
+				state = readState(new BufferedReader(new FileReader(hgstateFile)));
+			} else {
+				state = Collections.emptyMap();
+			}
+			BufferedReader br = new BufferedReader(new FileReader(hgsubFile));
+			return readConfig(br, state);
+		} catch (IOException ex) {
+			ex.printStackTrace(); // XXX log. Generally, shall not happen
+		}
+		return Collections.emptyList();
+	}
+
+	private List<HgSubrepoLocation> readConfig(BufferedReader br, Map<String, String> substate) throws IOException {
+		try {
+			String line;
+			LinkedList<HgSubrepoLocation> res = new LinkedList<HgSubrepoLocation>();
+			while ((line = br.readLine()) != null) {
+				int sep = line.indexOf('=');
+				if (sep == -1) {
+					continue;
+				}
+				// since both key and value are referenced from HgSubrepoLocation, doesn't make sense
+				// to have separate String instances (new String(line.substring()))
+				String key = line.substring(0, sep).trim();
+				String value = line.substring(sep + 1).trim();
+				if (value.length() == 0) {
+					// XXX log bad line?
+					continue;
+				}
+				HgSubrepoLocation.Kind kind = HgSubrepoLocation.Kind.Hg;
+				int kindEnd = value.indexOf(']', 1);
+				if (value.charAt(0) == '[' && kindEnd != -1) {
+					String kindStr = value.substring(1, kindEnd);
+					value = value.substring(kindEnd + 1);
+					if ("svn".equals(kindStr)) {
+						kind = HgSubrepoLocation.Kind.SVN;
+					} else if ("git".equals(kindStr)) {
+						kind = HgSubrepoLocation.Kind.Git;
+					}
+				}
+				// TODO respect paths mappings in config file
+				HgSubrepoLocation loc = new HgSubrepoLocation(repo, key, value, kind, substate.get(key));
+				res.add(loc);
+			}
+			return Arrays.asList(res.toArray(new HgSubrepoLocation[res.size()]));
+		} finally {
+			br.close();
+		}
+	}
+
+	private Map<String, String> readState(BufferedReader br) throws IOException {
+		HashMap<String, String> rv = new HashMap<String, String>();
+		try {
+			String line;
+			while ((line = br.readLine()) != null) {
+				int sep = line.trim().indexOf(' ');
+				if (sep != -1) {
+					rv.put(line.substring(sep+1).trim(), line.substring(0, sep).trim());
+				}
+			}
+		} finally {
+			br.close();
+		}
+		return rv;
+	}
+
+	public List<HgSubrepoLocation> all(/*int revision, or TIP|WC*/) {
+		if (subRepos == null) {
+			subRepos = readActualState();
+		}
+		return subRepos;
+	}
+}
--- a/src/org/tmatesoft/hg/repo/HgRepository.java	Wed Jun 15 18:06:39 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgRepository.java	Thu Jun 16 04:23:51 2011 +0200
@@ -36,6 +36,7 @@
 import org.tmatesoft.hg.internal.Filter;
 import org.tmatesoft.hg.internal.RequiresFile;
 import org.tmatesoft.hg.internal.RevlogStream;
+import org.tmatesoft.hg.internal.SubrepoManager;
 import org.tmatesoft.hg.util.CancelledException;
 import org.tmatesoft.hg.util.Pair;
 import org.tmatesoft.hg.util.Path;
@@ -75,6 +76,7 @@
 	private HgTags tags;
 	private HgBranches branches;
 	private HgMergeState mergeState;
+	private SubrepoManager subRepos;
 
 	// XXX perhaps, shall enable caching explicitly
 	private final HashMap<Path, SoftReference<RevlogStream>> streamsCache = new HashMap<Path, SoftReference<RevlogStream>>();
@@ -241,6 +243,18 @@
 	public File getWorkingDir() {
 		return workingDir;
 	}
+	
+	/**
+	 * Provides access to sub-repositories defined in this repository. Enumerated  sub-repositories are those directly
+	 * known, not recursive collection of all nested sub-repositories.
+	 * @return list of all known sub-repositories in this repository, or empty list if none found.
+	 */
+	public List<HgSubrepoLocation> getSubrepositories() {
+		if (subRepos == null) {
+			subRepos = new SubrepoManager(this);
+		}
+		return subRepos.all();
+	}
 
 	// shall be of use only for internal classes 
 	/*package-local*/ File getRepositoryRoot() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tmatesoft/hg/repo/HgSubrepoLocation.java	Thu Jun 16 04:23:51 2011 +0200
@@ -0,0 +1,95 @@
+/*
+ * 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.repo;
+
+import java.io.File;
+
+import org.tmatesoft.hg.core.HgBadStateException;
+import org.tmatesoft.hg.core.HgException;
+import org.tmatesoft.hg.internal.Experimental;
+import org.tmatesoft.hg.util.Path;
+
+/**
+ * WORK IN PROGRESS, DO NOT USE
+ * @author Artem Tikhomirov
+ * @author TMate Software Ltd.
+ */
+@Experimental(reason="Work in progress")
+public class HgSubrepoLocation {
+	
+	private final HgRepository owner;
+	private final Kind kind;
+	private final Path location;
+	private final String source;
+	private final String revInfo;
+
+	public enum Kind { Hg, SVN, Git, }
+	
+	public HgSubrepoLocation(HgRepository parentRepo, String repoLocation, String actualLocation, Kind type, String revision) {
+		owner = parentRepo;
+		location = Path.create(repoLocation);
+		source = actualLocation;
+		kind = type;
+		revInfo = revision;
+	}
+	
+	// as defined in .hgsub, key value
+	public Path getLocation() {
+		return location;
+	}
+
+	// value from .hgsub
+	public String getSource() {
+		return source;
+	}
+	
+	public Kind getType() {
+		return kind;
+	}
+	
+	public String getRevision() {
+		return revInfo;
+	}
+
+	/**
+	 * @return whether this sub repository is known only locally
+	 */
+	public boolean isCommitted() {
+		return revInfo != null;
+	}
+	
+	/**
+	 * @return <code>true</code> when there are local changes in the sub repository
+	 */
+	public boolean hasChanges() {
+		throw HgRepository.notImplemented();
+	}
+	
+//	public boolean isLocal() {
+//	}
+	
+	public HgRepository getOwner() {
+		return owner;
+	}
+
+	public HgRepository getRepo() throws HgException {
+		if (kind != Kind.Hg) {
+			throw new HgBadStateException();
+		}
+		return new HgLookup().detect(new File(owner.getWorkingDir(), source));
+	}
+}