Mercurial > jhg
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 { |
