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