Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/StatusCollector.java @ 93:d55d4eedfc57
Switch to Path instead of String in filenames returned by various status operations
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 27 Jan 2011 21:15:21 +0100 |
parents | a95c700408a9 |
children |
comparison
equal
deleted
inserted
replaced
92:bf304cb14247 | 93:d55d4eedfc57 |
---|---|
19 import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION; | 19 import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION; |
20 import static org.tmatesoft.hg.repo.HgRepository.TIP; | 20 import static org.tmatesoft.hg.repo.HgRepository.TIP; |
21 | 21 |
22 import java.util.Collection; | 22 import java.util.Collection; |
23 import java.util.Collections; | 23 import java.util.Collections; |
24 import java.util.HashMap; | |
25 import java.util.LinkedHashMap; | 24 import java.util.LinkedHashMap; |
26 import java.util.LinkedList; | 25 import java.util.LinkedList; |
27 import java.util.List; | 26 import java.util.List; |
28 import java.util.Map; | 27 import java.util.Map; |
29 import java.util.TreeMap; | 28 import java.util.TreeMap; |
30 import java.util.TreeSet; | 29 import java.util.TreeSet; |
31 | 30 |
32 import org.tmatesoft.hg.core.Nodeid; | 31 import org.tmatesoft.hg.core.Nodeid; |
33 import org.tmatesoft.hg.core.Path; | 32 import org.tmatesoft.hg.core.Path; |
33 import org.tmatesoft.hg.util.PathPool; | |
34 import org.tmatesoft.hg.util.PathRewrite; | |
34 | 35 |
35 | 36 |
36 /** | 37 /** |
37 * RevisionWalker? | 38 * RevisionWalker? |
38 * | 39 * |
41 */ | 42 */ |
42 public class StatusCollector { | 43 public class StatusCollector { |
43 | 44 |
44 private final HgRepository repo; | 45 private final HgRepository repo; |
45 private final Map<Integer, ManifestRevisionInspector> cache; // sparse array, in fact | 46 private final Map<Integer, ManifestRevisionInspector> cache; // sparse array, in fact |
47 private PathPool pathPool; | |
46 | 48 |
47 public StatusCollector(HgRepository hgRepo) { | 49 public StatusCollector(HgRepository hgRepo) { |
48 this.repo = hgRepo; | 50 this.repo = hgRepo; |
49 cache = new HashMap<Integer, ManifestRevisionInspector>(); | 51 cache = new TreeMap<Integer, ManifestRevisionInspector>(); |
50 ManifestRevisionInspector emptyFakeState = new ManifestRevisionInspector(); | 52 ManifestRevisionInspector emptyFakeState = new ManifestRevisionInspector(); |
51 emptyFakeState.begin(-1, null); | 53 emptyFakeState.begin(-1, null); |
52 emptyFakeState.end(-1); // FIXME HgRepo.TIP == -1 as well, need to distinguish fake "prior to first" revision from "the very last" | 54 emptyFakeState.end(-1); // FIXME HgRepo.TIP == -1 as well, need to distinguish fake "prior to first" revision from "the very last" |
53 cache.put(-1, emptyFakeState); | 55 cache.put(-1, emptyFakeState); |
54 } | 56 } |
68 } | 70 } |
69 | 71 |
70 /*package-local*/ ManifestRevisionInspector raw(int rev) { | 72 /*package-local*/ ManifestRevisionInspector raw(int rev) { |
71 return get(rev); | 73 return get(rev); |
72 } | 74 } |
75 /*package-local*/ PathPool getPathPool() { | |
76 if (pathPool == null) { | |
77 pathPool = new PathPool(new PathRewrite.Empty()); | |
78 } | |
79 return pathPool; | |
80 } | |
81 | |
82 public void setPathPool(PathPool pathPool) { | |
83 this.pathPool = pathPool; | |
84 } | |
85 | |
73 | 86 |
74 // hg status --change <rev> | 87 // hg status --change <rev> |
75 public void change(int rev, Inspector inspector) { | 88 public void change(int rev, HgStatusInspector inspector) { |
76 int[] parents = new int[2]; | 89 int[] parents = new int[2]; |
77 repo.getChangelog().parents(rev, parents, null, null); | 90 repo.getChangelog().parents(rev, parents, null, null); |
78 walk(parents[0], rev, inspector); | 91 walk(parents[0], rev, inspector); |
79 } | 92 } |
80 | 93 |
81 // I assume revision numbers are the same for changelog and manifest - here | 94 // I assume revision numbers are the same for changelog and manifest - here |
82 // user would like to pass changelog revision numbers, and I use them directly to walk manifest. | 95 // user would like to pass changelog revision numbers, and I use them directly to walk manifest. |
83 // if this assumption is wrong, fix this (lookup manifest revisions from changeset). | 96 // if this assumption is wrong, fix this (lookup manifest revisions from changeset). |
84 public void walk(int rev1, int rev2, Inspector inspector) { | 97 public void walk(int rev1, int rev2, HgStatusInspector inspector) { |
85 if (rev1 == rev2) { | 98 if (rev1 == rev2) { |
86 throw new IllegalArgumentException(); | 99 throw new IllegalArgumentException(); |
87 } | 100 } |
88 if (inspector == null) { | 101 if (inspector == null) { |
89 throw new IllegalArgumentException(); | 102 throw new IllegalArgumentException(); |
131 }); | 144 }); |
132 } | 145 } |
133 r1 = get(rev1); | 146 r1 = get(rev1); |
134 r2 = get(rev2); | 147 r2 = get(rev2); |
135 | 148 |
136 | 149 PathPool pp = getPathPool(); |
150 | |
137 TreeSet<String> r1Files = new TreeSet<String>(r1.files()); | 151 TreeSet<String> r1Files = new TreeSet<String>(r1.files()); |
138 for (String fname : r2.files()) { | 152 for (String fname : r2.files()) { |
139 if (r1Files.remove(fname)) { | 153 if (r1Files.remove(fname)) { |
140 Nodeid nidR1 = r1.nodeid(fname); | 154 Nodeid nidR1 = r1.nodeid(fname); |
141 Nodeid nidR2 = r2.nodeid(fname); | 155 Nodeid nidR2 = r2.nodeid(fname); |
142 String flagsR1 = r1.flags(fname); | 156 String flagsR1 = r1.flags(fname); |
143 String flagsR2 = r2.flags(fname); | 157 String flagsR2 = r2.flags(fname); |
144 if (nidR1.equals(nidR2) && ((flagsR2 == null && flagsR1 == null) || flagsR2.equals(flagsR1))) { | 158 if (nidR1.equals(nidR2) && ((flagsR2 == null && flagsR1 == null) || flagsR2.equals(flagsR1))) { |
145 inspector.clean(fname); | 159 inspector.clean(pp.path(fname)); |
146 } else { | 160 } else { |
147 inspector.modified(fname); | 161 inspector.modified(pp.path(fname)); |
148 } | 162 } |
149 } else { | 163 } else { |
150 String copyOrigin = getOriginIfCopy(repo, fname, r1Files, rev1); | 164 String copyOrigin = getOriginIfCopy(repo, fname, r1Files, rev1); |
151 if (copyOrigin != null) { | 165 if (copyOrigin != null) { |
152 inspector.copied(copyOrigin, fname); | 166 inspector.copied(pp.path(copyOrigin), pp.path(fname)); |
153 } else { | 167 } else { |
154 inspector.added(fname); | 168 inspector.added(pp.path(fname)); |
155 } | 169 } |
156 } | 170 } |
157 } | 171 } |
158 for (String left : r1Files) { | 172 for (String left : r1Files) { |
159 inspector.removed(left); | 173 inspector.removed(pp.path(left)); |
160 } | 174 } |
161 // inspector.done() if useful e.g. in UI client | |
162 } | 175 } |
163 | 176 |
164 public Record status(int rev1, int rev2) { | 177 public Record status(int rev1, int rev2) { |
165 Record rv = new Record(); | 178 Record rv = new Record(); |
166 walk(rev1, rev2, rv); | 179 walk(rev1, rev2, rv); |
186 df = hgRepo.getFileNode(original); // try more steps away | 199 df = hgRepo.getFileNode(original); // try more steps away |
187 } | 200 } |
188 return null; | 201 return null; |
189 } | 202 } |
190 | 203 |
191 public interface Inspector { | |
192 void modified(String fname); | |
193 void added(String fname); | |
194 // XXX need to specify whether StatusCollector invokes added() along with copied or not! | |
195 void copied(String fnameOrigin, String fnameAdded); // if copied files of no interest, should delegate to self.added(fnameAdded); | |
196 void removed(String fname); | |
197 void clean(String fname); | |
198 void missing(String fname); // aka deleted (tracked by Hg, but not available in FS any more | |
199 void unknown(String fname); // not tracked | |
200 void ignored(String fname); | |
201 } | |
202 | |
203 // XXX for r1..r2 status, only modified, added, removed (and perhaps, clean) make sense | 204 // XXX for r1..r2 status, only modified, added, removed (and perhaps, clean) make sense |
204 // XXX Need to specify whether copy targets are in added or not (@see Inspector#copied above) | 205 // XXX Need to specify whether copy targets are in added or not (@see Inspector#copied above) |
205 public static class Record implements Inspector { | 206 public static class Record implements HgStatusInspector { |
206 private List<String> modified, added, removed, clean, missing, unknown, ignored; | 207 private List<Path> modified, added, removed, clean, missing, unknown, ignored; |
207 private Map<String, String> copied; | 208 private Map<Path, Path> copied; |
208 | 209 |
209 private int startRev, endRev; | 210 private int startRev, endRev; |
210 private StatusCollector statusHelper; | 211 private StatusCollector statusHelper; |
211 | 212 |
212 // XXX StatusCollector may additionally initialize Record instance to speed lookup of changed file revisions | 213 // XXX StatusCollector may additionally initialize Record instance to speed lookup of changed file revisions |
220 startRev = startRevision; | 221 startRev = startRevision; |
221 endRev = endRevision; | 222 endRev = endRevision; |
222 statusHelper = self; | 223 statusHelper = self; |
223 } | 224 } |
224 | 225 |
225 public Nodeid nodeidBeforeChange(String fname) { | 226 public Nodeid nodeidBeforeChange(Path fname) { |
226 if (statusHelper == null || startRev == BAD_REVISION) { | 227 if (statusHelper == null || startRev == BAD_REVISION) { |
227 return null; | 228 return null; |
228 } | 229 } |
229 if ((modified == null || !modified.contains(fname)) && (removed == null || !removed.contains(fname))) { | 230 if ((modified == null || !modified.contains(fname)) && (removed == null || !removed.contains(fname))) { |
230 return null; | 231 return null; |
231 } | 232 } |
232 return statusHelper.raw(startRev).nodeid(fname); | 233 return statusHelper.raw(startRev).nodeid(fname.toString()); |
233 } | 234 } |
234 public Nodeid nodeidAfterChange(String fname) { | 235 public Nodeid nodeidAfterChange(Path fname) { |
235 if (statusHelper == null || endRev == BAD_REVISION) { | 236 if (statusHelper == null || endRev == BAD_REVISION) { |
236 return null; | 237 return null; |
237 } | 238 } |
238 if ((modified == null || !modified.contains(fname)) && (added == null || !added.contains(fname))) { | 239 if ((modified == null || !modified.contains(fname)) && (added == null || !added.contains(fname))) { |
239 return null; | 240 return null; |
240 } | 241 } |
241 return statusHelper.raw(endRev).nodeid(fname); | 242 return statusHelper.raw(endRev).nodeid(fname.toString()); |
242 } | 243 } |
243 | 244 |
244 public List<String> getModified() { | 245 public List<Path> getModified() { |
245 return proper(modified); | 246 return proper(modified); |
246 } | 247 } |
247 | 248 |
248 public List<String> getAdded() { | 249 public List<Path> getAdded() { |
249 return proper(added); | 250 return proper(added); |
250 } | 251 } |
251 | 252 |
252 public List<String> getRemoved() { | 253 public List<Path> getRemoved() { |
253 return proper(removed); | 254 return proper(removed); |
254 } | 255 } |
255 | 256 |
256 public Map<String,String> getCopied() { | 257 public Map<Path,Path> getCopied() { |
257 if (copied == null) { | 258 if (copied == null) { |
258 return Collections.emptyMap(); | 259 return Collections.emptyMap(); |
259 } | 260 } |
260 return Collections.unmodifiableMap(copied); | 261 return Collections.unmodifiableMap(copied); |
261 } | 262 } |
262 | 263 |
263 public List<String> getClean() { | 264 public List<Path> getClean() { |
264 return proper(clean); | 265 return proper(clean); |
265 } | 266 } |
266 | 267 |
267 public List<String> getMissing() { | 268 public List<Path> getMissing() { |
268 return proper(missing); | 269 return proper(missing); |
269 } | 270 } |
270 | 271 |
271 public List<String> getUnknown() { | 272 public List<Path> getUnknown() { |
272 return proper(unknown); | 273 return proper(unknown); |
273 } | 274 } |
274 | 275 |
275 public List<String> getIgnored() { | 276 public List<Path> getIgnored() { |
276 return proper(ignored); | 277 return proper(ignored); |
277 } | 278 } |
278 | 279 |
279 private List<String> proper(List<String> l) { | 280 private List<Path> proper(List<Path> l) { |
280 if (l == null) { | 281 if (l == null) { |
281 return Collections.emptyList(); | 282 return Collections.emptyList(); |
282 } | 283 } |
283 return Collections.unmodifiableList(l); | 284 return Collections.unmodifiableList(l); |
284 } | 285 } |
285 | 286 |
286 // | 287 // |
287 // | 288 // |
288 | 289 |
289 public void modified(String fname) { | 290 public void modified(Path fname) { |
290 modified = doAdd(modified, fname); | 291 modified = doAdd(modified, fname); |
291 } | 292 } |
292 | 293 |
293 public void added(String fname) { | 294 public void added(Path fname) { |
294 added = doAdd(added, fname); | 295 added = doAdd(added, fname); |
295 } | 296 } |
296 | 297 |
297 public void copied(String fnameOrigin, String fnameAdded) { | 298 public void copied(Path fnameOrigin, Path fnameAdded) { |
298 if (copied == null) { | 299 if (copied == null) { |
299 copied = new LinkedHashMap<String, String>(); | 300 copied = new LinkedHashMap<Path, Path>(); |
300 } | 301 } |
301 added(fnameAdded); | 302 added(fnameAdded); |
302 copied.put(fnameAdded, fnameOrigin); | 303 copied.put(fnameAdded, fnameOrigin); |
303 } | 304 } |
304 | 305 |
305 public void removed(String fname) { | 306 public void removed(Path fname) { |
306 removed = doAdd(removed, fname); | 307 removed = doAdd(removed, fname); |
307 } | 308 } |
308 | 309 |
309 public void clean(String fname) { | 310 public void clean(Path fname) { |
310 clean = doAdd(clean, fname); | 311 clean = doAdd(clean, fname); |
311 } | 312 } |
312 | 313 |
313 public void missing(String fname) { | 314 public void missing(Path fname) { |
314 missing = doAdd(missing, fname); | 315 missing = doAdd(missing, fname); |
315 } | 316 } |
316 | 317 |
317 public void unknown(String fname) { | 318 public void unknown(Path fname) { |
318 unknown = doAdd(unknown, fname); | 319 unknown = doAdd(unknown, fname); |
319 } | 320 } |
320 | 321 |
321 public void ignored(String fname) { | 322 public void ignored(Path fname) { |
322 ignored = doAdd(ignored, fname); | 323 ignored = doAdd(ignored, fname); |
323 } | 324 } |
324 | 325 |
325 private static List<String> doAdd(List<String> l, String s) { | 326 private static List<Path> doAdd(List<Path> l, Path p) { |
326 if (l == null) { | 327 if (l == null) { |
327 l = new LinkedList<String>(); | 328 l = new LinkedList<Path>(); |
328 } | 329 } |
329 l.add(s); | 330 l.add(p); |
330 return l; | 331 return l; |
331 } | 332 } |
332 } | 333 } |
333 | 334 |
334 /*package-local*/ static final class ManifestRevisionInspector implements HgManifest.Inspector { | 335 /*package-local*/ static final class ManifestRevisionInspector implements HgManifest.Inspector { |