Mercurial > hg4j
comparison src/org/tmatesoft/hg/core/HgStatusCommand.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 | 7f136a3fa671 |
children | 6437d261048a |
comparison
equal
deleted
inserted
replaced
422:5d1cc7366d04 | 423:9c9c442b5f2e |
---|---|
20 import static org.tmatesoft.hg.repo.HgInternals.wrongRevisionIndex; | 20 import static org.tmatesoft.hg.repo.HgInternals.wrongRevisionIndex; |
21 import static org.tmatesoft.hg.repo.HgRepository.*; | 21 import static org.tmatesoft.hg.repo.HgRepository.*; |
22 | 22 |
23 import java.io.IOException; | 23 import java.io.IOException; |
24 import java.util.ConcurrentModificationException; | 24 import java.util.ConcurrentModificationException; |
25 import java.util.concurrent.CancellationException; | |
26 | 25 |
27 import org.tmatesoft.hg.internal.ChangelogHelper; | 26 import org.tmatesoft.hg.internal.ChangelogHelper; |
28 import org.tmatesoft.hg.repo.HgRepository; | 27 import org.tmatesoft.hg.repo.HgRepository; |
29 import org.tmatesoft.hg.repo.HgStatusCollector; | 28 import org.tmatesoft.hg.repo.HgStatusCollector; |
30 import org.tmatesoft.hg.repo.HgStatusInspector; | 29 import org.tmatesoft.hg.repo.HgStatusInspector; |
31 import org.tmatesoft.hg.repo.HgWorkingCopyStatusCollector; | 30 import org.tmatesoft.hg.repo.HgWorkingCopyStatusCollector; |
31 import org.tmatesoft.hg.util.CancelSupport; | |
32 import org.tmatesoft.hg.util.CancelledException; | |
32 import org.tmatesoft.hg.util.Path; | 33 import org.tmatesoft.hg.util.Path; |
33 import org.tmatesoft.hg.util.Status; | 34 import org.tmatesoft.hg.util.Status; |
34 | 35 |
35 /** | 36 /** |
36 * Command to obtain file status information, 'hg status' counterpart. | 37 * Command to obtain file status information, 'hg status' counterpart. |
159 | 160 |
160 /** | 161 /** |
161 * Perform status operation according to parameters set. | 162 * Perform status operation according to parameters set. |
162 * | 163 * |
163 * @param statusHandler callback to get status information | 164 * @param statusHandler callback to get status information |
164 * @throws IOException if there are (further unspecified) errors while walking working copy | 165 * @throws HgCallbackTargetException wrapper for any exception user callback code may produce |
166 * @throws CancelledException if execution of the command was cancelled | |
167 * @throws IOException FIXME EXCEPTIONS WTF it's doing here if there are (further unspecified) errors while walking working copy | |
165 * @throws IllegalArgumentException if handler is <code>null</code> | 168 * @throws IllegalArgumentException if handler is <code>null</code> |
166 * @throws ConcurrentModificationException if this command already runs (i.e. being used from another thread) | 169 * @throws ConcurrentModificationException if this command already runs (i.e. being used from another thread) |
167 */ | 170 */ |
168 public void execute(HgStatusHandler statusHandler) throws CancellationException, HgException, IOException { | 171 public void execute(HgStatusHandler statusHandler) throws HgCallbackTargetException, CancelledException, HgException, IOException { |
169 if (statusHandler == null) { | 172 if (statusHandler == null) { |
170 throw new IllegalArgumentException(); | 173 throw new IllegalArgumentException(); |
171 } | 174 } |
172 if (mediator.busy()) { | 175 if (mediator.busy()) { |
173 throw new ConcurrentModificationException(); | 176 throw new ConcurrentModificationException(); |
175 HgStatusCollector sc = new HgStatusCollector(repo); // TODO from CommandContext | 178 HgStatusCollector sc = new HgStatusCollector(repo); // TODO from CommandContext |
176 // PathPool pathHelper = new PathPool(repo.getPathHelper()); // TODO from CommandContext | 179 // PathPool pathHelper = new PathPool(repo.getPathHelper()); // TODO from CommandContext |
177 try { | 180 try { |
178 // XXX if I need a rough estimation (for ProgressMonitor) of number of work units, | 181 // XXX if I need a rough estimation (for ProgressMonitor) of number of work units, |
179 // I may use number of files in either rev1 or rev2 manifest edition | 182 // I may use number of files in either rev1 or rev2 manifest edition |
180 mediator.start(statusHandler, new ChangelogHelper(repo, startRevision)); | 183 mediator.start(statusHandler, getCancelSupport(statusHandler, true), new ChangelogHelper(repo, startRevision)); |
181 if (endRevision == WORKING_COPY) { | 184 if (endRevision == WORKING_COPY) { |
182 HgWorkingCopyStatusCollector wcsc = scope != null ? HgWorkingCopyStatusCollector.create(repo, scope) : new HgWorkingCopyStatusCollector(repo); | 185 HgWorkingCopyStatusCollector wcsc = scope != null ? HgWorkingCopyStatusCollector.create(repo, scope) : new HgWorkingCopyStatusCollector(repo); |
183 wcsc.setBaseRevisionCollector(sc); | 186 wcsc.setBaseRevisionCollector(sc); |
184 wcsc.walk(startRevision, mediator); | 187 wcsc.walk(startRevision, mediator); |
185 } else { | 188 } else { |
188 sc.change(endRevision, mediator); | 191 sc.change(endRevision, mediator); |
189 } else { | 192 } else { |
190 sc.walk(startRevision, endRevision, mediator); | 193 sc.walk(startRevision, endRevision, mediator); |
191 } | 194 } |
192 } | 195 } |
193 } catch (HgCallbackTargetException.Wrap ex) { | 196 } catch (CancelledException ex) { |
194 // seems too general to catch RuntimeException, i.e. | 197 // this is our exception, thrown from Mediator. |
195 // unless catch is for very narrow piece of code, it's better not to catch any RTE (which may happen elsewhere, not only in handler) | 198 // next check shall throw original cause of the stop - either HgCallbackTargetException or original CancelledException |
196 // XXX Perhaps, need more detailed explanation in handlers that are expected to throw Wrap/RTE (i.e. HgChangesetHandler) | 199 mediator.checkFailure(); |
197 throw new HgCallbackTargetException(ex).setRevisionIndex(endRevision); | |
198 } finally { | 200 } finally { |
199 mediator.done(); | 201 mediator.done(); |
200 } | 202 } |
201 } | 203 } |
202 | 204 |
206 @Deprecated | 208 @Deprecated |
207 public interface Handler extends HgStatusHandler{ | 209 public interface Handler extends HgStatusHandler{ |
208 void handleStatus(HgStatus s); | 210 void handleStatus(HgStatus s); |
209 } | 211 } |
210 | 212 |
211 private class Mediator implements HgStatusInspector { | 213 private class Mediator implements HgStatusInspector, CancelSupport { |
212 boolean needModified; | 214 boolean needModified; |
213 boolean needAdded; | 215 boolean needAdded; |
214 boolean needRemoved; | 216 boolean needRemoved; |
215 boolean needUnknown; | 217 boolean needUnknown; |
216 boolean needMissing; | 218 boolean needMissing; |
217 boolean needClean; | 219 boolean needClean; |
218 boolean needIgnored; | 220 boolean needIgnored; |
219 boolean needCopies; | 221 boolean needCopies; |
220 HgStatusHandler handler; | 222 HgStatusHandler handler; |
221 private ChangelogHelper logHelper; | 223 private ChangelogHelper logHelper; |
224 private CancelSupport handlerCancelSupport; | |
225 private HgCallbackTargetException failure; | |
226 private CancelledException cancellation; | |
222 | 227 |
223 Mediator() { | 228 Mediator() { |
224 } | 229 } |
225 | 230 |
226 public void start(HgStatusHandler h, ChangelogHelper changelogHelper) { | 231 public void start(HgStatusHandler h, CancelSupport hcs, ChangelogHelper changelogHelper) { |
227 handler = h; | 232 handler = h; |
233 handlerCancelSupport = hcs; | |
228 logHelper = changelogHelper; | 234 logHelper = changelogHelper; |
229 } | 235 } |
230 | 236 |
231 public void done() { | 237 public void done() { |
232 handler = null; | 238 handler = null; |
239 handlerCancelSupport = null; | |
233 logHelper = null; | 240 logHelper = null; |
241 failure = null; | |
242 cancellation = null; | |
234 } | 243 } |
235 | 244 |
236 public boolean busy() { | 245 public boolean busy() { |
237 return handler != null; | 246 return handler != null; |
238 } | 247 } |
239 | 248 |
249 // XXX copy from ChangesetTransformer. Perhaps, can share the code? | |
250 public void checkFailure() throws HgCallbackTargetException, CancelledException { | |
251 // do not forget to clear exceptions for reuse of this instance | |
252 if (failure != null) { | |
253 HgCallbackTargetException toThrow = failure; | |
254 failure = null; | |
255 throw toThrow; | |
256 } | |
257 if (cancellation != null) { | |
258 CancelledException toThrow = cancellation; | |
259 cancellation = null; | |
260 throw toThrow; | |
261 } | |
262 } | |
263 | |
264 // XXX copy from ChangesetTransformer. code sharing note above applies | |
265 public void checkCancelled() throws CancelledException { | |
266 if (failure != null || cancellation != null) { | |
267 // stop status iteration. Our exception is for the purposes of cancellation only, | |
268 // the one we have stored (this.cancellation) is for user | |
269 throw new CancelledException(); | |
270 } | |
271 } | |
272 | |
273 private void dispatch(HgStatus s) { | |
274 try { | |
275 handler.handleStatus(s); | |
276 handlerCancelSupport.checkCancelled(); | |
277 } catch (HgCallbackTargetException ex) { | |
278 failure = ex; | |
279 } catch (CancelledException ex) { | |
280 cancellation = ex; | |
281 } | |
282 } | |
283 | |
240 public void modified(Path fname) { | 284 public void modified(Path fname) { |
241 if (needModified) { | 285 if (needModified) { |
242 handler.handleStatus(new HgStatus(Modified, fname, logHelper)); | 286 dispatch(new HgStatus(Modified, fname, logHelper)); |
243 } | 287 } |
244 } | 288 } |
245 public void added(Path fname) { | 289 public void added(Path fname) { |
246 if (needAdded) { | 290 if (needAdded) { |
247 handler.handleStatus(new HgStatus(Added, fname, logHelper)); | 291 dispatch(new HgStatus(Added, fname, logHelper)); |
248 } | 292 } |
249 } | 293 } |
250 public void removed(Path fname) { | 294 public void removed(Path fname) { |
251 if (needRemoved) { | 295 if (needRemoved) { |
252 handler.handleStatus(new HgStatus(Removed, fname, logHelper)); | 296 dispatch(new HgStatus(Removed, fname, logHelper)); |
253 } | 297 } |
254 } | 298 } |
255 public void copied(Path fnameOrigin, Path fnameAdded) { | 299 public void copied(Path fnameOrigin, Path fnameAdded) { |
256 if (needCopies) { | 300 if (needCopies) { |
257 // TODO post-1.0 in fact, merged files may report 'copied from' as well, correct status kind thus may differ from Added | 301 // TODO post-1.0 in fact, merged files may report 'copied from' as well, correct status kind thus may differ from Added |
258 handler.handleStatus(new HgStatus(Added, fnameAdded, fnameOrigin, logHelper)); | 302 dispatch(new HgStatus(Added, fnameAdded, fnameOrigin, logHelper)); |
259 } | 303 } |
260 } | 304 } |
261 public void missing(Path fname) { | 305 public void missing(Path fname) { |
262 if (needMissing) { | 306 if (needMissing) { |
263 handler.handleStatus(new HgStatus(Missing, fname, logHelper)); | 307 dispatch(new HgStatus(Missing, fname, logHelper)); |
264 } | 308 } |
265 } | 309 } |
266 public void unknown(Path fname) { | 310 public void unknown(Path fname) { |
267 if (needUnknown) { | 311 if (needUnknown) { |
268 handler.handleStatus(new HgStatus(Unknown, fname, logHelper)); | 312 dispatch(new HgStatus(Unknown, fname, logHelper)); |
269 } | 313 } |
270 } | 314 } |
271 public void clean(Path fname) { | 315 public void clean(Path fname) { |
272 if (needClean) { | 316 if (needClean) { |
273 handler.handleStatus(new HgStatus(Clean, fname, logHelper)); | 317 dispatch(new HgStatus(Clean, fname, logHelper)); |
274 } | 318 } |
275 } | 319 } |
276 public void ignored(Path fname) { | 320 public void ignored(Path fname) { |
277 if (needIgnored) { | 321 if (needIgnored) { |
278 handler.handleStatus(new HgStatus(Ignored, fname, logHelper)); | 322 dispatch(new HgStatus(Ignored, fname, logHelper)); |
279 } | 323 } |
280 } | 324 } |
281 | 325 |
282 public void invalid(Path fname, Exception ex) { | 326 public void invalid(Path fname, Exception err) { |
283 handler.handleError(fname, new Status(Status.Kind.ERROR, "Failed to get file status", ex)); | 327 try { |
328 handler.handleError(fname, new Status(Status.Kind.ERROR, "Failed to get file status", err)); | |
329 handlerCancelSupport.checkCancelled(); | |
330 } catch (HgCallbackTargetException ex) { | |
331 failure = ex; | |
332 } catch (CancelledException ex) { | |
333 cancellation = ex; | |
334 } | |
284 } | 335 } |
285 } | 336 } |
286 } | 337 } |