Mercurial > hg4j
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 |