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;