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 {