Mercurial > hg4j
diff src/org/tmatesoft/hg/repo/HgTags.java @ 234:b2cfbe46f9b6
HgTags got TagInfo to access tags. Tags are read from all branches/revisions now, not only working copy
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Tue, 07 Jun 2011 04:28:32 +0200 |
parents | 54562de502f7 |
children | 981f9f50bb6c |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/HgTags.java Fri Jun 03 04:50:09 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgTags.java Tue Jun 07 04:28:32 2011 +0200 @@ -20,7 +20,9 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.io.Reader; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -39,13 +41,17 @@ // global tags come from ".hgtags" // local come from ".hg/localtags" + private final HgRepository repo; + private final Map<Nodeid, List<String>> globalToName; private final Map<Nodeid, List<String>> localToName; private final Map<String, List<Nodeid>> globalFromName; private final Map<String, List<Nodeid>> localFromName; + private Map<String, TagInfo> tags; - /*package-local*/ HgTags() { + /*package-local*/ HgTags(HgRepository hgRepo) { + repo = hgRepo; globalToName = new HashMap<Nodeid, List<String>>(); localToName = new HashMap<Nodeid, List<String>>(); globalFromName = new TreeMap<String, List<Nodeid>>(); @@ -65,6 +71,18 @@ } read(globalTags, globalToName, globalFromName); } + + /*package-local*/ void readGlobal(Reader globalTags) throws IOException { + BufferedReader r = null; + try { + r = new BufferedReader(globalTags); + read(r, globalToName, globalFromName); + } finally { + if (r != null) { + r.close(); + } + } + } private void read(File f, Map<Nodeid,List<String>> nid2name, Map<String, List<Nodeid>> name2nid) throws IOException { if (!f.canRead()) { @@ -101,19 +119,37 @@ List<Nodeid> nids = name2nid.get(tagName); if (nids == null) { nids = new LinkedList<Nodeid>(); + nids.add(nid); // tagName is substring of full line, thus need a copy to let the line be GC'ed // new String(tagName.toCharArray()) is more expressive, but results in 1 extra arraycopy tagName = new String(tagName); name2nid.put(tagName, nids); + } else if (!nid.equals(nids.get(0))) { + // Alternatively, !nids.contains(nid) might have come to mind. + // However, I guess that 'tag history' means we need to record each change of revision + // associated with the tag, i.e. imagine project evolution: + // tag1=r1, tag1=r2, tag1=r1. If we choose !contains, list top of tag1 would point to r2 + // while we need it to point to r1. + // In fact, there are still possible odd patterns in name2nid list, e.g. + // when tag was removed and added back(initially rev1 tag1, on removal *added* nullrev tag1), + // then added back (rev2 tag1). + // name2nid would list (rev2 nullrev rev1) as many times, as there were revisions of the .hgtags file + // See cpython "v2.4.3c1" revision for example. + // It doesn't seem to hurt (unless there are clients that care about tag history and depend on + // unique revisions there), XXX but better to be fixed (not sure how, though) + ((LinkedList<Nodeid>) nids).addFirst(nid); + // XXX repo.getNodeidCache().nodeid(nid); } - // XXX repo.getNodeidCache().nodeid(nid); - ((LinkedList<Nodeid>) nids).addFirst(nid); List<String> revTags = nid2name.get(nid); if (revTags == null) { revTags = new LinkedList<String>(); + revTags.add(tagName); nid2name.put(nid, revTags); + } else if (!revTags.contains(tagName)) { + // !contains because we don't care about order of the tags per revision + revTags.add(tagName); } - revTags.add(tagName); + } else { System.out.println("Bad tags line:" + line); // FIXME see above } @@ -147,4 +183,49 @@ } return rv; } + + public Map<String, TagInfo> getTags() { + if (tags == null) { + tags = new TreeMap<String, TagInfo>(); + for (String t : globalFromName.keySet()) { + tags.put(t, new TagInfo(t)); + } + for (String t : localFromName.keySet()) { + tags.put(t, new TagInfo(t)); + } + tags = Collections.unmodifiableMap(tags); + } + return tags; + } + + + public final class TagInfo { + private final String name; + private String branch; + + TagInfo(String tagName) { + this.name = tagName; + } + public String name() { + return name; + } + + public boolean isLocal() { + return localFromName.containsKey(name); + } + + public String branch() { + if (branch == null) { + int x = repo.getChangelog().getLocalRevision(revision()); + branch = repo.getChangelog().range(x, x).get(0).branch(); + } + return branch; + } + public Nodeid revision() { + if (isLocal()) { + return localFromName.get(name).get(0); + } + return globalFromName.get(name).get(0); + } + } }