Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java @ 348:a0864b2892cd
Expose errors reading mercurial control files with exception
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 24 Nov 2011 02:57:03 +0100 |
| parents | f377f833b780 |
| children | 33eaed1ad130 |
comparison
equal
deleted
inserted
replaced
| 347:8da7ade36c57 | 348:a0864b2892cd |
|---|---|
| 31 import java.util.TreeSet; | 31 import java.util.TreeSet; |
| 32 | 32 |
| 33 import org.tmatesoft.hg.core.HgBadStateException; | 33 import org.tmatesoft.hg.core.HgBadStateException; |
| 34 import org.tmatesoft.hg.core.HgDataStreamException; | 34 import org.tmatesoft.hg.core.HgDataStreamException; |
| 35 import org.tmatesoft.hg.core.HgException; | 35 import org.tmatesoft.hg.core.HgException; |
| 36 import org.tmatesoft.hg.core.HgInvalidControlFileException; | |
| 36 import org.tmatesoft.hg.core.Nodeid; | 37 import org.tmatesoft.hg.core.Nodeid; |
| 37 import org.tmatesoft.hg.internal.ByteArrayChannel; | 38 import org.tmatesoft.hg.internal.ByteArrayChannel; |
| 38 import org.tmatesoft.hg.internal.Experimental; | 39 import org.tmatesoft.hg.internal.Experimental; |
| 39 import org.tmatesoft.hg.internal.FilterByteChannel; | 40 import org.tmatesoft.hg.internal.FilterByteChannel; |
| 40 import org.tmatesoft.hg.internal.ManifestRevision; | 41 import org.tmatesoft.hg.internal.ManifestRevision; |
| 98 | 99 |
| 99 /** | 100 /** |
| 100 * Access to directory state information this collector uses. | 101 * Access to directory state information this collector uses. |
| 101 * @return directory state holder, never <code>null</code> | 102 * @return directory state holder, never <code>null</code> |
| 102 */ | 103 */ |
| 103 public HgDirstate getDirstate() { | 104 public HgDirstate getDirstate() throws HgInvalidControlFileException { |
| 104 if (dirstate == null) { | 105 if (dirstate == null) { |
| 105 dirstate = repo.loadDirstate(getPathPool()); | 106 dirstate = repo.loadDirstate(getPathPool()); |
| 106 } | 107 } |
| 108 return dirstate; | |
| 109 } | |
| 110 | |
| 111 private HgDirstate getDirstateImpl() { | |
| 107 return dirstate; | 112 return dirstate; |
| 108 } | 113 } |
| 109 | 114 |
| 110 private ManifestRevision getManifest(int changelogLocalRev) { | 115 private ManifestRevision getManifest(int changelogLocalRev) { |
| 111 assert changelogLocalRev >= 0; | 116 assert changelogLocalRev >= 0; |
| 121 | 126 |
| 122 private ManifestRevision getDirstateParentManifest() { | 127 private ManifestRevision getDirstateParentManifest() { |
| 123 // WC not necessarily points to TIP, but may be result of update to any previous revision. | 128 // WC not necessarily points to TIP, but may be result of update to any previous revision. |
| 124 // In such case, we need to compare local files not to their TIP content, but to specific version at the time of selected revision | 129 // In such case, we need to compare local files not to their TIP content, but to specific version at the time of selected revision |
| 125 if (dirstateParentManifest == null) { | 130 if (dirstateParentManifest == null) { |
| 126 Nodeid dirstateParent = getDirstate().parents().first(); | 131 Nodeid dirstateParent = getDirstateImpl().parents().first(); |
| 127 if (dirstateParent.isNull()) { | 132 if (dirstateParent.isNull()) { |
| 128 dirstateParentManifest = baseRevisionCollector != null ? baseRevisionCollector.raw(-1) : HgStatusCollector.createEmptyManifestRevision(); | 133 dirstateParentManifest = baseRevisionCollector != null ? baseRevisionCollector.raw(-1) : HgStatusCollector.createEmptyManifestRevision(); |
| 129 } else { | 134 } else { |
| 130 int changelogLocalRev = repo.getChangelog().getLocalRevision(dirstateParent); | 135 int changelogLocalRev = repo.getChangelog().getLocalRevision(dirstateParent); |
| 131 dirstateParentManifest = getManifest(changelogLocalRev); | 136 dirstateParentManifest = getManifest(changelogLocalRev); |
| 137 // may be invoked few times, TIP or WORKING_COPY indicate comparison shall be run against working copy parent | 142 // may be invoked few times, TIP or WORKING_COPY indicate comparison shall be run against working copy parent |
| 138 // NOTE, use of TIP constant requires certain care. TIP here doesn't mean latest cset, but actual working copy parent. | 143 // NOTE, use of TIP constant requires certain care. TIP here doesn't mean latest cset, but actual working copy parent. |
| 139 public void walk(int baseRevision, HgStatusInspector inspector) { | 144 public void walk(int baseRevision, HgStatusInspector inspector) { |
| 140 if (HgInternals.wrongLocalRevision(baseRevision) || baseRevision == BAD_REVISION) { | 145 if (HgInternals.wrongLocalRevision(baseRevision) || baseRevision == BAD_REVISION) { |
| 141 throw new IllegalArgumentException(String.valueOf(baseRevision)); | 146 throw new IllegalArgumentException(String.valueOf(baseRevision)); |
| 147 } | |
| 148 if (getDirstateImpl() == null) { | |
| 149 // XXX this is a hack to avoid declaring throws for the #walk() at the moment | |
| 150 // once I decide whether to have mediator that collects errors or to use exceptions here | |
| 151 // this hack shall be removed in favor of either severe error in mediator or a re-thrown exception. | |
| 152 try { | |
| 153 getDirstate(); | |
| 154 } catch (HgInvalidControlFileException ex) { | |
| 155 repo.getContext().getLog().error(getClass(), ex, "Can't read dirstate"); | |
| 156 return; | |
| 157 } | |
| 142 } | 158 } |
| 143 ManifestRevision collect = null; // non null indicates we compare against base revision | 159 ManifestRevision collect = null; // non null indicates we compare against base revision |
| 144 Set<Path> baseRevFiles = Collections.emptySet(); // files from base revision not affected by status calculation | 160 Set<Path> baseRevFiles = Collections.emptySet(); // files from base revision not affected by status calculation |
| 145 if (baseRevision != TIP && baseRevision != WORKING_COPY) { | 161 if (baseRevision != TIP && baseRevision != WORKING_COPY) { |
| 146 collect = getManifest(baseRevision); | 162 collect = getManifest(baseRevision); |
| 162 ((HgStatusCollector.Record) inspector).init(rev1, rev2, sc); | 178 ((HgStatusCollector.Record) inspector).init(rev1, rev2, sc); |
| 163 } | 179 } |
| 164 final HgIgnore hgIgnore = repo.getIgnore(); | 180 final HgIgnore hgIgnore = repo.getIgnore(); |
| 165 repoWalker.reset(); | 181 repoWalker.reset(); |
| 166 TreeSet<Path> processed = new TreeSet<Path>(); // names of files we handled as they known to Dirstate (not FileIterator) | 182 TreeSet<Path> processed = new TreeSet<Path>(); // names of files we handled as they known to Dirstate (not FileIterator) |
| 167 final HgDirstate ds = getDirstate(); | 183 final HgDirstate ds = getDirstateImpl(); |
| 168 TreeSet<Path> knownEntries = ds.all(); // here just to get dirstate initialized | 184 TreeSet<Path> knownEntries = ds.all(); // here just to get dirstate initialized |
| 169 while (repoWalker.hasNext()) { | 185 while (repoWalker.hasNext()) { |
| 170 repoWalker.next(); | 186 repoWalker.next(); |
| 171 final Path fname = getPathPool().path(repoWalker.name()); | 187 final Path fname = getPathPool().path(repoWalker.name()); |
| 172 FileInfo f = repoWalker.file(); | 188 FileInfo f = repoWalker.file(); |
| 259 //******************************************** | 275 //******************************************** |
| 260 | 276 |
| 261 | 277 |
| 262 private void checkLocalStatusAgainstFile(Path fname, FileInfo f, HgStatusInspector inspector) { | 278 private void checkLocalStatusAgainstFile(Path fname, FileInfo f, HgStatusInspector inspector) { |
| 263 HgDirstate.Record r; | 279 HgDirstate.Record r; |
| 264 if ((r = getDirstate().checkNormal(fname)) != null) { | 280 if ((r = getDirstateImpl().checkNormal(fname)) != null) { |
| 265 // either clean or modified | 281 // either clean or modified |
| 266 final boolean timestampEqual = f.lastModified() == r.modificationTime(), sizeEqual = r.size() == f.length(); | 282 final boolean timestampEqual = f.lastModified() == r.modificationTime(), sizeEqual = r.size() == f.length(); |
| 267 if (timestampEqual && sizeEqual) { | 283 if (timestampEqual && sizeEqual) { |
| 268 inspector.clean(fname); | 284 inspector.clean(fname); |
| 269 } else if (!sizeEqual && r.size() >= 0) { | 285 } else if (!sizeEqual && r.size() >= 0) { |
| 285 inspector.modified(df.getPath()); | 301 inspector.modified(df.getPath()); |
| 286 } else { | 302 } else { |
| 287 inspector.clean(df.getPath()); | 303 inspector.clean(df.getPath()); |
| 288 } | 304 } |
| 289 } | 305 } |
| 290 } else if ((r = getDirstate().checkAdded(fname)) != null) { | 306 } else if ((r = getDirstateImpl().checkAdded(fname)) != null) { |
| 291 if (r.copySource() == null) { | 307 if (r.copySource() == null) { |
| 292 inspector.added(fname); | 308 inspector.added(fname); |
| 293 } else { | 309 } else { |
| 294 inspector.copied(r.copySource(), fname); | 310 inspector.copied(r.copySource(), fname); |
| 295 } | 311 } |
| 296 } else if ((r = getDirstate().checkRemoved(fname)) != null) { | 312 } else if ((r = getDirstateImpl().checkRemoved(fname)) != null) { |
| 297 inspector.removed(fname); | 313 inspector.removed(fname); |
| 298 } else if ((r = getDirstate().checkMerged(fname)) != null) { | 314 } else if ((r = getDirstateImpl().checkMerged(fname)) != null) { |
| 299 inspector.modified(fname); | 315 inspector.modified(fname); |
| 300 } | 316 } |
| 301 } | 317 } |
| 302 | 318 |
| 303 // XXX refactor checkLocalStatus methods in more OO way | 319 // XXX refactor checkLocalStatus methods in more OO way |
| 308 HgDirstate.Record r; | 324 HgDirstate.Record r; |
| 309 if (nid1 == null) { | 325 if (nid1 == null) { |
| 310 // normal: added? | 326 // normal: added? |
| 311 // added: not known at the time of baseRevision, shall report | 327 // added: not known at the time of baseRevision, shall report |
| 312 // merged: was not known, report as added? | 328 // merged: was not known, report as added? |
| 313 if ((r = getDirstate().checkNormal(fname)) != null) { | 329 if ((r = getDirstateImpl().checkNormal(fname)) != null) { |
| 314 try { | 330 try { |
| 315 Path origin = HgStatusCollector.getOriginIfCopy(repo, fname, baseRevNames, baseRevision); | 331 Path origin = HgStatusCollector.getOriginIfCopy(repo, fname, baseRevNames, baseRevision); |
| 316 if (origin != null) { | 332 if (origin != null) { |
| 317 inspector.copied(getPathPool().path(origin), fname); | 333 inspector.copied(getPathPool().path(origin), fname); |
| 318 return; | 334 return; |
| 319 } | 335 } |
| 320 } catch (HgDataStreamException ex) { | 336 } catch (HgDataStreamException ex) { |
| 321 ex.printStackTrace(); | 337 ex.printStackTrace(); |
| 322 // FIXME report to a mediator, continue status collection | 338 // FIXME report to a mediator, continue status collection |
| 323 } | 339 } |
| 324 } else if ((r = getDirstate().checkAdded(fname)) != null) { | 340 } else if ((r = getDirstateImpl().checkAdded(fname)) != null) { |
| 325 if (r.copySource() != null && baseRevNames.contains(r.copySource())) { | 341 if (r.copySource() != null && baseRevNames.contains(r.copySource())) { |
| 326 baseRevNames.remove(r.copySource()); // XXX surely I shall not report rename source as Removed? | 342 baseRevNames.remove(r.copySource()); // XXX surely I shall not report rename source as Removed? |
| 327 inspector.copied(r.copySource(), fname); | 343 inspector.copied(r.copySource(), fname); |
| 328 return; | 344 return; |
| 329 } | 345 } |
| 330 // fall-through, report as added | 346 // fall-through, report as added |
| 331 } else if (getDirstate().checkRemoved(fname) != null) { | 347 } else if (getDirstateImpl().checkRemoved(fname) != null) { |
| 332 // removed: removed file was not known at the time of baseRevision, and we should not report it as removed | 348 // removed: removed file was not known at the time of baseRevision, and we should not report it as removed |
| 333 return; | 349 return; |
| 334 } | 350 } |
| 335 inspector.added(fname); | 351 inspector.added(fname); |
| 336 } else { | 352 } else { |
| 337 // was known; check whether clean or modified | 353 // was known; check whether clean or modified |
| 338 Nodeid nidFromDirstate = getDirstateParentManifest().nodeid(fname); | 354 Nodeid nidFromDirstate = getDirstateParentManifest().nodeid(fname); |
| 339 if ((r = getDirstate().checkNormal(fname)) != null && nid1.equals(nidFromDirstate)) { | 355 if ((r = getDirstateImpl().checkNormal(fname)) != null && nid1.equals(nidFromDirstate)) { |
| 340 // regular file, was the same up to WC initialization. Check if was modified since, and, if not, report right away | 356 // regular file, was the same up to WC initialization. Check if was modified since, and, if not, report right away |
| 341 // same code as in #checkLocalStatusAgainstFile | 357 // same code as in #checkLocalStatusAgainstFile |
| 342 final boolean timestampEqual = f.lastModified() == r.modificationTime(), sizeEqual = r.size() == f.length(); | 358 final boolean timestampEqual = f.lastModified() == r.modificationTime(), sizeEqual = r.size() == f.length(); |
| 343 boolean handled = false; | 359 boolean handled = false; |
| 344 if (timestampEqual && sizeEqual) { | 360 if (timestampEqual && sizeEqual) { |
| 358 } | 374 } |
| 359 // otherwise, shall check actual content (size not the same, or unknown (-1 or -2), or timestamp is different, | 375 // otherwise, shall check actual content (size not the same, or unknown (-1 or -2), or timestamp is different, |
| 360 // or nodeid in dirstate is different, but local change might have brought it back to baseRevision state) | 376 // or nodeid in dirstate is different, but local change might have brought it back to baseRevision state) |
| 361 // FALL THROUGH | 377 // FALL THROUGH |
| 362 } | 378 } |
| 363 if (r != null || (r = getDirstate().checkMerged(fname)) != null || (r = getDirstate().checkAdded(fname)) != null) { | 379 if (r != null || (r = getDirstateImpl().checkMerged(fname)) != null || (r = getDirstateImpl().checkAdded(fname)) != null) { |
| 364 // check actual content to see actual changes | 380 // check actual content to see actual changes |
| 365 // when added - seems to be the case of a file added once again, hence need to check if content is different | 381 // when added - seems to be the case of a file added once again, hence need to check if content is different |
| 366 // either clean or modified | 382 // either clean or modified |
| 367 HgDataFile fileNode = repo.getFileNode(fname); | 383 HgDataFile fileNode = repo.getFileNode(fname); |
| 368 if (areTheSame(f, fileNode, nid1)) { | 384 if (areTheSame(f, fileNode, nid1)) { |
| 369 inspector.clean(fname); | 385 inspector.clean(fname); |
| 370 } else { | 386 } else { |
| 371 inspector.modified(fname); | 387 inspector.modified(fname); |
| 372 } | 388 } |
| 373 baseRevNames.remove(fname); // consumed, processed, handled. | 389 baseRevNames.remove(fname); // consumed, processed, handled. |
| 374 } else if (getDirstate().checkRemoved(fname) != null) { | 390 } else if (getDirstateImpl().checkRemoved(fname) != null) { |
| 375 // was known, and now marked as removed, report it right away, do not rely on baseRevNames processing later | 391 // was known, and now marked as removed, report it right away, do not rely on baseRevNames processing later |
| 376 inspector.removed(fname); | 392 inspector.removed(fname); |
| 377 baseRevNames.remove(fname); // consumed, processed, handled. | 393 baseRevNames.remove(fname); // consumed, processed, handled. |
| 378 } | 394 } |
| 379 // only those left in baseRevNames after processing are reported as removed | 395 // only those left in baseRevNames after processing are reported as removed |
