Mercurial > hg4j
comparison 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 |
comparison
equal
deleted
inserted
replaced
233:1d389c0cb0a5 | 234:b2cfbe46f9b6 |
---|---|
18 | 18 |
19 import java.io.BufferedReader; | 19 import java.io.BufferedReader; |
20 import java.io.File; | 20 import java.io.File; |
21 import java.io.FileReader; | 21 import java.io.FileReader; |
22 import java.io.IOException; | 22 import java.io.IOException; |
23 import java.io.Reader; | |
23 import java.util.ArrayList; | 24 import java.util.ArrayList; |
25 import java.util.Collections; | |
24 import java.util.HashMap; | 26 import java.util.HashMap; |
25 import java.util.LinkedList; | 27 import java.util.LinkedList; |
26 import java.util.List; | 28 import java.util.List; |
27 import java.util.Map; | 29 import java.util.Map; |
28 import java.util.TreeMap; | 30 import java.util.TreeMap; |
37 */ | 39 */ |
38 public class HgTags { | 40 public class HgTags { |
39 // global tags come from ".hgtags" | 41 // global tags come from ".hgtags" |
40 // local come from ".hg/localtags" | 42 // local come from ".hg/localtags" |
41 | 43 |
44 private final HgRepository repo; | |
45 | |
42 private final Map<Nodeid, List<String>> globalToName; | 46 private final Map<Nodeid, List<String>> globalToName; |
43 private final Map<Nodeid, List<String>> localToName; | 47 private final Map<Nodeid, List<String>> localToName; |
44 private final Map<String, List<Nodeid>> globalFromName; | 48 private final Map<String, List<Nodeid>> globalFromName; |
45 private final Map<String, List<Nodeid>> localFromName; | 49 private final Map<String, List<Nodeid>> localFromName; |
46 | 50 |
47 | 51 private Map<String, TagInfo> tags; |
48 /*package-local*/ HgTags() { | 52 |
53 /*package-local*/ HgTags(HgRepository hgRepo) { | |
54 repo = hgRepo; | |
49 globalToName = new HashMap<Nodeid, List<String>>(); | 55 globalToName = new HashMap<Nodeid, List<String>>(); |
50 localToName = new HashMap<Nodeid, List<String>>(); | 56 localToName = new HashMap<Nodeid, List<String>>(); |
51 globalFromName = new TreeMap<String, List<Nodeid>>(); | 57 globalFromName = new TreeMap<String, List<Nodeid>>(); |
52 localFromName = new TreeMap<String, List<Nodeid>>(); | 58 localFromName = new TreeMap<String, List<Nodeid>>(); |
53 } | 59 } |
62 /*package-local*/ void readGlobal(File globalTags) throws IOException { | 68 /*package-local*/ void readGlobal(File globalTags) throws IOException { |
63 if (globalTags == null || globalTags.isDirectory()) { | 69 if (globalTags == null || globalTags.isDirectory()) { |
64 throw new IllegalArgumentException(String.valueOf(globalTags)); | 70 throw new IllegalArgumentException(String.valueOf(globalTags)); |
65 } | 71 } |
66 read(globalTags, globalToName, globalFromName); | 72 read(globalTags, globalToName, globalFromName); |
73 } | |
74 | |
75 /*package-local*/ void readGlobal(Reader globalTags) throws IOException { | |
76 BufferedReader r = null; | |
77 try { | |
78 r = new BufferedReader(globalTags); | |
79 read(r, globalToName, globalFromName); | |
80 } finally { | |
81 if (r != null) { | |
82 r.close(); | |
83 } | |
84 } | |
67 } | 85 } |
68 | 86 |
69 private void read(File f, Map<Nodeid,List<String>> nid2name, Map<String, List<Nodeid>> name2nid) throws IOException { | 87 private void read(File f, Map<Nodeid,List<String>> nid2name, Map<String, List<Nodeid>> name2nid) throws IOException { |
70 if (!f.canRead()) { | 88 if (!f.canRead()) { |
71 return; | 89 return; |
99 Nodeid nid = Nodeid.fromAscii(nodeidBytes, 0, nodeidBytes.length); | 117 Nodeid nid = Nodeid.fromAscii(nodeidBytes, 0, nodeidBytes.length); |
100 String tagName = line.substring(spacePos+1); | 118 String tagName = line.substring(spacePos+1); |
101 List<Nodeid> nids = name2nid.get(tagName); | 119 List<Nodeid> nids = name2nid.get(tagName); |
102 if (nids == null) { | 120 if (nids == null) { |
103 nids = new LinkedList<Nodeid>(); | 121 nids = new LinkedList<Nodeid>(); |
122 nids.add(nid); | |
104 // tagName is substring of full line, thus need a copy to let the line be GC'ed | 123 // tagName is substring of full line, thus need a copy to let the line be GC'ed |
105 // new String(tagName.toCharArray()) is more expressive, but results in 1 extra arraycopy | 124 // new String(tagName.toCharArray()) is more expressive, but results in 1 extra arraycopy |
106 tagName = new String(tagName); | 125 tagName = new String(tagName); |
107 name2nid.put(tagName, nids); | 126 name2nid.put(tagName, nids); |
127 } else if (!nid.equals(nids.get(0))) { | |
128 // Alternatively, !nids.contains(nid) might have come to mind. | |
129 // However, I guess that 'tag history' means we need to record each change of revision | |
130 // associated with the tag, i.e. imagine project evolution: | |
131 // tag1=r1, tag1=r2, tag1=r1. If we choose !contains, list top of tag1 would point to r2 | |
132 // while we need it to point to r1. | |
133 // In fact, there are still possible odd patterns in name2nid list, e.g. | |
134 // when tag was removed and added back(initially rev1 tag1, on removal *added* nullrev tag1), | |
135 // then added back (rev2 tag1). | |
136 // name2nid would list (rev2 nullrev rev1) as many times, as there were revisions of the .hgtags file | |
137 // See cpython "v2.4.3c1" revision for example. | |
138 // It doesn't seem to hurt (unless there are clients that care about tag history and depend on | |
139 // unique revisions there), XXX but better to be fixed (not sure how, though) | |
140 ((LinkedList<Nodeid>) nids).addFirst(nid); | |
141 // XXX repo.getNodeidCache().nodeid(nid); | |
108 } | 142 } |
109 // XXX repo.getNodeidCache().nodeid(nid); | |
110 ((LinkedList<Nodeid>) nids).addFirst(nid); | |
111 List<String> revTags = nid2name.get(nid); | 143 List<String> revTags = nid2name.get(nid); |
112 if (revTags == null) { | 144 if (revTags == null) { |
113 revTags = new LinkedList<String>(); | 145 revTags = new LinkedList<String>(); |
146 revTags.add(tagName); | |
114 nid2name.put(nid, revTags); | 147 nid2name.put(nid, revTags); |
148 } else if (!revTags.contains(tagName)) { | |
149 // !contains because we don't care about order of the tags per revision | |
150 revTags.add(tagName); | |
115 } | 151 } |
116 revTags.add(tagName); | 152 |
117 } else { | 153 } else { |
118 System.out.println("Bad tags line:" + line); // FIXME see above | 154 System.out.println("Bad tags line:" + line); // FIXME see above |
119 } | 155 } |
120 } | 156 } |
121 } | 157 } |
145 if ((l = globalFromName.get(tagName)) != null) { | 181 if ((l = globalFromName.get(tagName)) != null) { |
146 rv.addAll(l); | 182 rv.addAll(l); |
147 } | 183 } |
148 return rv; | 184 return rv; |
149 } | 185 } |
186 | |
187 public Map<String, TagInfo> getTags() { | |
188 if (tags == null) { | |
189 tags = new TreeMap<String, TagInfo>(); | |
190 for (String t : globalFromName.keySet()) { | |
191 tags.put(t, new TagInfo(t)); | |
192 } | |
193 for (String t : localFromName.keySet()) { | |
194 tags.put(t, new TagInfo(t)); | |
195 } | |
196 tags = Collections.unmodifiableMap(tags); | |
197 } | |
198 return tags; | |
199 } | |
200 | |
201 | |
202 public final class TagInfo { | |
203 private final String name; | |
204 private String branch; | |
205 | |
206 TagInfo(String tagName) { | |
207 this.name = tagName; | |
208 } | |
209 public String name() { | |
210 return name; | |
211 } | |
212 | |
213 public boolean isLocal() { | |
214 return localFromName.containsKey(name); | |
215 } | |
216 | |
217 public String branch() { | |
218 if (branch == null) { | |
219 int x = repo.getChangelog().getLocalRevision(revision()); | |
220 branch = repo.getChangelog().range(x, x).get(0).branch(); | |
221 } | |
222 return branch; | |
223 } | |
224 public Nodeid revision() { | |
225 if (isLocal()) { | |
226 return localFromName.get(name).get(0); | |
227 } | |
228 return globalFromName.get(name).get(0); | |
229 } | |
230 } | |
150 } | 231 } |