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; |