Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java @ 423:9c9c442b5f2e
Major refactoring of exception handling. Low-level API uses RuntimeExceptions, while checked are left for higher level
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Fri, 23 Mar 2012 22:51:18 +0100 |
| parents | ee8264d80747 |
| children | 48f993aa2f41 |
comparison
equal
deleted
inserted
replaced
| 422:5d1cc7366d04 | 423:9c9c442b5f2e |
|---|---|
| 29 import java.util.NoSuchElementException; | 29 import java.util.NoSuchElementException; |
| 30 import java.util.Set; | 30 import java.util.Set; |
| 31 import java.util.TreeSet; | 31 import java.util.TreeSet; |
| 32 | 32 |
| 33 import org.tmatesoft.hg.core.HgException; | 33 import org.tmatesoft.hg.core.HgException; |
| 34 import org.tmatesoft.hg.core.HgInvalidControlFileException; | |
| 35 import org.tmatesoft.hg.core.HgInvalidFileException; | |
| 36 import org.tmatesoft.hg.core.Nodeid; | 34 import org.tmatesoft.hg.core.Nodeid; |
| 37 import org.tmatesoft.hg.internal.ByteArrayChannel; | 35 import org.tmatesoft.hg.internal.ByteArrayChannel; |
| 38 import org.tmatesoft.hg.internal.Experimental; | 36 import org.tmatesoft.hg.internal.Experimental; |
| 39 import org.tmatesoft.hg.internal.FilterByteChannel; | 37 import org.tmatesoft.hg.internal.FilterByteChannel; |
| 40 import org.tmatesoft.hg.internal.Internals; | 38 import org.tmatesoft.hg.internal.Internals; |
| 41 import org.tmatesoft.hg.internal.ManifestRevision; | 39 import org.tmatesoft.hg.internal.ManifestRevision; |
| 42 import org.tmatesoft.hg.internal.PathScope; | 40 import org.tmatesoft.hg.internal.PathScope; |
| 43 import org.tmatesoft.hg.internal.Preview; | 41 import org.tmatesoft.hg.internal.Preview; |
| 44 import org.tmatesoft.hg.util.Adaptable; | 42 import org.tmatesoft.hg.util.Adaptable; |
| 45 import org.tmatesoft.hg.util.ByteChannel; | 43 import org.tmatesoft.hg.util.ByteChannel; |
| 44 import org.tmatesoft.hg.util.CancelSupport; | |
| 46 import org.tmatesoft.hg.util.CancelledException; | 45 import org.tmatesoft.hg.util.CancelledException; |
| 47 import org.tmatesoft.hg.util.FileInfo; | 46 import org.tmatesoft.hg.util.FileInfo; |
| 48 import org.tmatesoft.hg.util.FileIterator; | 47 import org.tmatesoft.hg.util.FileIterator; |
| 49 import org.tmatesoft.hg.util.FileWalker; | 48 import org.tmatesoft.hg.util.FileWalker; |
| 50 import org.tmatesoft.hg.util.Path; | 49 import org.tmatesoft.hg.util.Path; |
| 149 // In such case, we need to compare local files not to their TIP content, but to specific version at the time of selected revision | 148 // In such case, we need to compare local files not to their TIP content, but to specific version at the time of selected revision |
| 150 private ManifestRevision getDirstateParentManifest() { | 149 private ManifestRevision getDirstateParentManifest() { |
| 151 return dirstateParentManifest; | 150 return dirstateParentManifest; |
| 152 } | 151 } |
| 153 | 152 |
| 154 // may be invoked few times, TIP or WORKING_COPY indicate comparison shall be run against working copy parent | 153 /** |
| 155 // NOTE, use of TIP constant requires certain care. TIP here doesn't mean latest cset, but actual working copy parent. | 154 * may be invoked few times, TIP or WORKING_COPY indicate comparison shall be run against working copy parent |
| 156 public void walk(int baseRevision, HgStatusInspector inspector) throws HgInvalidControlFileException, IOException { | 155 * XXX NOTE, use of TIP constant requires certain care. TIP here doesn't mean latest cset, but actual working copy parent. |
| 156 * | |
| 157 * @param baseRevision | |
| 158 * @param inspector | |
| 159 * @throws IOException to propagate IO errors from {@link FileIterator} | |
| 160 * @throws CancelledException if operation execution was cancelled | |
| 161 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | |
| 162 */ | |
| 163 public void walk(int baseRevision, HgStatusInspector inspector) throws IOException, CancelledException, HgRuntimeException { | |
| 157 if (HgInternals.wrongRevisionIndex(baseRevision) || baseRevision == BAD_REVISION) { | 164 if (HgInternals.wrongRevisionIndex(baseRevision) || baseRevision == BAD_REVISION) { |
| 158 throw new IllegalArgumentException(String.valueOf(baseRevision)); | 165 throw new IllegalArgumentException(String.valueOf(baseRevision)); |
| 159 } | 166 } |
| 160 if (getDirstateImpl() == null) { | 167 if (getDirstateImpl() == null) { |
| 161 getDirstate(); | 168 getDirstate(); |
| 182 } else { | 189 } else { |
| 183 rev1 = baseRevision; | 190 rev1 = baseRevision; |
| 184 } | 191 } |
| 185 ((HgStatusCollector.Record) inspector).init(rev1, rev2, sc); | 192 ((HgStatusCollector.Record) inspector).init(rev1, rev2, sc); |
| 186 } | 193 } |
| 194 final CancelSupport cs = CancelSupport.Factory.get(inspector); | |
| 187 final HgIgnore hgIgnore = repo.getIgnore(); | 195 final HgIgnore hgIgnore = repo.getIgnore(); |
| 188 repoWalker.reset(); | 196 repoWalker.reset(); |
| 189 TreeSet<Path> processed = new TreeSet<Path>(); // names of files we handled as they known to Dirstate (not FileIterator) | 197 TreeSet<Path> processed = new TreeSet<Path>(); // names of files we handled as they known to Dirstate (not FileIterator) |
| 190 final HgDirstate ds = getDirstateImpl(); | 198 final HgDirstate ds = getDirstateImpl(); |
| 191 TreeSet<Path> knownEntries = ds.all(); // here just to get dirstate initialized | 199 TreeSet<Path> knownEntries = ds.all(); // here just to get dirstate initialized |
| 192 while (repoWalker.hasNext()) { | 200 while (repoWalker.hasNext()) { |
| 201 cs.checkCancelled(); | |
| 193 repoWalker.next(); | 202 repoWalker.next(); |
| 194 final Path fname = getPathPool().path(repoWalker.name()); | 203 final Path fname = getPathPool().path(repoWalker.name()); |
| 195 FileInfo f = repoWalker.file(); | 204 FileInfo f = repoWalker.file(); |
| 196 Path knownInDirstate; | 205 Path knownInDirstate; |
| 197 if (!f.exists()) { | 206 if (!f.exists()) { |
| 248 } | 257 } |
| 249 if (collect != null) { | 258 if (collect != null) { |
| 250 for (Path fromBase : baseRevFiles) { | 259 for (Path fromBase : baseRevFiles) { |
| 251 if (repoWalker.inScope(fromBase)) { | 260 if (repoWalker.inScope(fromBase)) { |
| 252 inspector.removed(fromBase); | 261 inspector.removed(fromBase); |
| 262 cs.checkCancelled(); | |
| 253 } | 263 } |
| 254 } | 264 } |
| 255 } | 265 } |
| 256 knownEntries.removeAll(processed); | 266 knownEntries.removeAll(processed); |
| 257 for (Path m : knownEntries) { | 267 for (Path m : knownEntries) { |
| 258 if (!repoWalker.inScope(m)) { | 268 if (!repoWalker.inScope(m)) { |
| 259 // do not report as missing/removed those FileIterator doesn't care about. | 269 // do not report as missing/removed those FileIterator doesn't care about. |
| 260 continue; | 270 continue; |
| 261 } | 271 } |
| 272 cs.checkCancelled(); | |
| 262 // missing known file from a working dir | 273 // missing known file from a working dir |
| 263 if (ds.checkRemoved(m) == null) { | 274 if (ds.checkRemoved(m) == null) { |
| 264 // not removed from the repository = 'deleted' | 275 // not removed from the repository = 'deleted' |
| 265 inspector.missing(m); | 276 inspector.missing(m); |
| 266 } else { | 277 } else { |
| 271 } | 282 } |
| 272 } | 283 } |
| 273 } | 284 } |
| 274 } | 285 } |
| 275 | 286 |
| 276 public HgStatusCollector.Record status(int baseRevision) throws HgInvalidControlFileException, IOException { | 287 /** |
| 288 * | |
| 289 * @param baseRevision | |
| 290 * @return information object that describes change between the revisions | |
| 291 * @throws IOException to propagate IO errors from {@link FileIterator} | |
| 292 * @throws CancelledException if operation execution was cancelled | |
| 293 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | |
| 294 */ | |
| 295 public HgStatusCollector.Record status(int baseRevision) throws IOException, HgRuntimeException { | |
| 277 HgStatusCollector.Record rv = new HgStatusCollector.Record(); | 296 HgStatusCollector.Record rv = new HgStatusCollector.Record(); |
| 278 walk(baseRevision, rv); | 297 try { |
| 298 walk(baseRevision, rv); | |
| 299 } catch (CancelledException ex) { | |
| 300 // can't happen as long our Record class doesn't implement CancelSupport | |
| 301 HgInvalidStateException t = new HgInvalidStateException("Internal error"); | |
| 302 t.initCause(ex); | |
| 303 throw t; | |
| 304 } | |
| 279 return rv; | 305 return rv; |
| 280 } | 306 } |
| 281 | 307 |
| 282 //******************************************** | 308 //******************************************** |
| 283 | 309 |
| 428 // changeset nodeid + hash(actual content) => entry (Nodeid) in the next Manifest | 454 // changeset nodeid + hash(actual content) => entry (Nodeid) in the next Manifest |
| 429 // then it's sufficient to check parents from dirstate, and if they do not match parents from file's baseRevision (non matching parents means different nodeids). | 455 // then it's sufficient to check parents from dirstate, and if they do not match parents from file's baseRevision (non matching parents means different nodeids). |
| 430 // The question is whether original Hg treats this case (same content, different parents and hence nodeids) as 'modified' or 'clean' | 456 // The question is whether original Hg treats this case (same content, different parents and hence nodeids) as 'modified' or 'clean' |
| 431 } | 457 } |
| 432 | 458 |
| 433 private boolean areTheSame(FileInfo f, HgDataFile dataFile, Nodeid revision) throws HgException { | 459 private boolean areTheSame(FileInfo f, HgDataFile dataFile, Nodeid revision) throws HgException, HgInvalidFileException { |
| 434 // XXX consider adding HgDataDile.compare(File/byte[]/whatever) operation to optimize comparison | 460 // XXX consider adding HgDataDile.compare(File/byte[]/whatever) operation to optimize comparison |
| 435 ByteArrayChannel bac = new ByteArrayChannel(); | 461 ByteArrayChannel bac = new ByteArrayChannel(); |
| 436 try { | 462 try { |
| 437 int fileRevisionIndex = dataFile.getRevisionIndex(revision); | 463 int fileRevisionIndex = dataFile.getRevisionIndex(revision); |
| 438 // need content with metadata striped off - although theoretically chances are metadata may be different, | 464 // need content with metadata striped off - although theoretically chances are metadata may be different, |
| 442 // silently ignore - can't happen, ByteArrayChannel is not cancellable | 468 // silently ignore - can't happen, ByteArrayChannel is not cancellable |
| 443 } | 469 } |
| 444 return areTheSame(f, bac.toArray(), dataFile.getPath()); | 470 return areTheSame(f, bac.toArray(), dataFile.getPath()); |
| 445 } | 471 } |
| 446 | 472 |
| 447 private boolean areTheSame(FileInfo f, final byte[] data, Path p) throws HgException { | 473 private boolean areTheSame(FileInfo f, final byte[] data, Path p) throws HgInvalidFileException { |
| 448 ReadableByteChannel is = null; | 474 ReadableByteChannel is = null; |
| 449 class Check implements ByteChannel { | 475 class Check implements ByteChannel { |
| 450 final boolean debug = repo.getContext().getLog().isDebug(); | 476 final boolean debug = repo.getContext().getLog().isDebug(); |
| 451 boolean sameSoFar = true; | 477 boolean sameSoFar = true; |
| 452 int x = 0; | 478 int x = 0; |
| 664 } | 690 } |
| 665 return false; | 691 return false; |
| 666 } | 692 } |
| 667 | 693 |
| 668 public boolean supportsExecFlag() { | 694 public boolean supportsExecFlag() { |
| 669 // TODO Auto-generated method stub | 695 return execCap; |
| 670 return false; | |
| 671 } | 696 } |
| 672 | 697 |
| 673 public boolean supportsLinkFlag() { | 698 public boolean supportsLinkFlag() { |
| 674 // TODO Auto-generated method stub | 699 return linkCap; |
| 675 return false; | |
| 676 } | 700 } |
| 677 } | 701 } |
| 678 | 702 |
| 679 private static class FileIteratorFilter implements FileIterator { | 703 private static class FileIteratorFilter implements FileIterator { |
| 680 private final Path.Matcher filter; | 704 private final Path.Matcher filter; |
