Mercurial > jhg
comparison src/org/tmatesoft/hg/core/HgManifestCommand.java @ 427:31a89587eb04
FIXMEs: consistent names, throws for commands and their handlers. Use of checked exceptions in hi-level api
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 29 Mar 2012 17:14:35 +0200 |
| parents | 6437d261048a |
| children | 12f668401613 |
comparison
equal
deleted
inserted
replaced
| 426:063b0663495a | 427:31a89587eb04 |
|---|---|
| 23 import java.util.ConcurrentModificationException; | 23 import java.util.ConcurrentModificationException; |
| 24 import java.util.LinkedHashMap; | 24 import java.util.LinkedHashMap; |
| 25 import java.util.LinkedList; | 25 import java.util.LinkedList; |
| 26 import java.util.List; | 26 import java.util.List; |
| 27 | 27 |
| 28 import org.tmatesoft.hg.internal.Callback; | |
| 29 import org.tmatesoft.hg.repo.HgManifest; | 28 import org.tmatesoft.hg.repo.HgManifest; |
| 30 import org.tmatesoft.hg.repo.HgRepository; | 29 import org.tmatesoft.hg.repo.HgRepository; |
| 31 import org.tmatesoft.hg.repo.HgManifest.Flags; | 30 import org.tmatesoft.hg.repo.HgManifest.Flags; |
| 31 import org.tmatesoft.hg.repo.HgRuntimeException; | |
| 32 import org.tmatesoft.hg.util.CancelSupport; | |
| 33 import org.tmatesoft.hg.util.CancelledException; | |
| 32 import org.tmatesoft.hg.util.Path; | 34 import org.tmatesoft.hg.util.Path; |
| 33 import org.tmatesoft.hg.util.PathPool; | 35 import org.tmatesoft.hg.util.PathPool; |
| 34 import org.tmatesoft.hg.util.PathRewrite; | 36 import org.tmatesoft.hg.util.PathRewrite; |
| 35 | 37 |
| 36 | 38 |
| 43 public class HgManifestCommand extends HgAbstractCommand<HgManifestCommand> { | 45 public class HgManifestCommand extends HgAbstractCommand<HgManifestCommand> { |
| 44 | 46 |
| 45 private final HgRepository repo; | 47 private final HgRepository repo; |
| 46 private Path.Matcher matcher; | 48 private Path.Matcher matcher; |
| 47 private int startRev = 0, endRev = TIP; | 49 private int startRev = 0, endRev = TIP; |
| 48 private Handler visitor; | 50 private HgManifestHandler visitor; |
| 49 private boolean needDirs = false; | 51 private boolean needDirs = false; |
| 50 | 52 |
| 51 private final Mediator mediator = new Mediator(); | 53 private final Mediator mediator = new Mediator(); |
| 52 | 54 |
| 53 public HgManifestCommand(HgRepository hgRepo) { | 55 public HgManifestCommand(HgRepository hgRepo) { |
| 95 matcher = pathMatcher; | 97 matcher = pathMatcher; |
| 96 return this; | 98 return this; |
| 97 } | 99 } |
| 98 | 100 |
| 99 /** | 101 /** |
| 100 * Runs the command. | 102 * With all parameters set, execute the command. |
| 103 * | |
| 101 * @param handler - callback to get the outcome | 104 * @param handler - callback to get the outcome |
| 105 * @throws HgCallbackTargetException propagated exception from the handler | |
| 106 * @throws HgException subclass thereof to indicate specific issue with the command arguments or repository state | |
| 107 * @throws CancelledException if execution of the command was cancelled | |
| 102 * @throws IllegalArgumentException if handler is <code>null</code> | 108 * @throws IllegalArgumentException if handler is <code>null</code> |
| 103 * @throws ConcurrentModificationException if this command is already in use (running) | 109 * @throws ConcurrentModificationException if this command is already in use (running) |
| 104 */ | 110 */ |
| 105 public void execute(Handler handler) throws HgException { | 111 public void execute(HgManifestHandler handler) throws HgCallbackTargetException, HgException, CancelledException { |
| 106 if (handler == null) { | 112 if (handler == null) { |
| 107 throw new IllegalArgumentException(); | 113 throw new IllegalArgumentException(); |
| 108 } | 114 } |
| 109 if (visitor != null) { | 115 if (visitor != null) { |
| 110 throw new ConcurrentModificationException(); | 116 throw new ConcurrentModificationException(); |
| 111 } | 117 } |
| 112 try { | 118 try { |
| 113 visitor = handler; | 119 visitor = handler; |
| 114 mediator.start(); | 120 mediator.start(getCancelSupport(handler, true)); |
| 115 repo.getManifest().walk(startRev, endRev, mediator); | 121 repo.getManifest().walk(startRev, endRev, mediator); |
| 122 mediator.checkFailure(); | |
| 123 } catch (HgRuntimeException ex) { | |
| 124 throw new HgLibraryFailureException(ex); | |
| 116 } finally { | 125 } finally { |
| 117 mediator.done(); | 126 mediator.done(); |
| 118 visitor = null; | 127 visitor = null; |
| 119 } | 128 } |
| 120 } | |
| 121 | |
| 122 /** | |
| 123 * Callback to walk file/directory tree of a revision | |
| 124 */ | |
| 125 @Callback | |
| 126 public interface Handler { // FIXME TLC | |
| 127 void begin(Nodeid manifestRevision); | |
| 128 void dir(Path p); // optionally invoked (if walker was configured to spit out directories) prior to any files from this dir and subdirs | |
| 129 void file(HgFileRevision fileRevision); // XXX allow to check p is invalid (df.exists()) | |
| 130 void end(Nodeid manifestRevision); | |
| 131 } | 129 } |
| 132 | 130 |
| 133 // I'd rather let HgManifestCommand implement HgManifest.Inspector directly, but this pollutes API alot | 131 // I'd rather let HgManifestCommand implement HgManifest.Inspector directly, but this pollutes API alot |
| 134 private class Mediator implements HgManifest.Inspector { | 132 private class Mediator implements HgManifest.Inspector { |
| 135 // file names are likely to repeat in each revision, hence caching of Paths. | 133 // file names are likely to repeat in each revision, hence caching of Paths. |
| 136 // However, once HgManifest.Inspector switches to Path objects, perhaps global Path pool | 134 // However, once HgManifest.Inspector switches to Path objects, perhaps global Path pool |
| 137 // might be more effective? | 135 // might be more effective? |
| 138 private PathPool pathPool; | 136 private PathPool pathPool; |
| 139 private List<HgFileRevision> manifestContent; | 137 private List<HgFileRevision> manifestContent; |
| 140 private Nodeid manifestNodeid; | 138 private Nodeid manifestNodeid; |
| 141 | 139 private Exception failure; |
| 142 public void start() { | 140 private CancelSupport cancelHelper; |
| 141 | |
| 142 public void start(CancelSupport cs) { | |
| 143 assert cs != null; | |
| 143 // Manifest keeps normalized paths | 144 // Manifest keeps normalized paths |
| 144 pathPool = new PathPool(new PathRewrite.Empty()); | 145 pathPool = new PathPool(new PathRewrite.Empty()); |
| 146 cancelHelper = cs; | |
| 145 } | 147 } |
| 146 | 148 |
| 147 public void done() { | 149 public void done() { |
| 148 manifestContent = null; | 150 manifestContent = null; |
| 149 pathPool = null; | 151 pathPool = null; |
| 150 } | 152 } |
| 153 | |
| 154 private void recordFailure(HgCallbackTargetException ex) { | |
| 155 failure = ex; | |
| 156 } | |
| 157 private void recordCancel(CancelledException ex) { | |
| 158 failure = ex; | |
| 159 } | |
| 160 | |
| 161 public void checkFailure() throws HgCallbackTargetException, CancelledException { | |
| 162 // TODO post-1.0 perhaps, can combine this code (record/checkFailure) for reuse in more classes (e.g. in Revlog) | |
| 163 if (failure instanceof HgCallbackTargetException) { | |
| 164 HgCallbackTargetException ex = (HgCallbackTargetException) failure; | |
| 165 failure = null; | |
| 166 throw ex; | |
| 167 } | |
| 168 if (failure instanceof CancelledException) { | |
| 169 CancelledException ex = (CancelledException) failure; | |
| 170 failure = null; | |
| 171 throw ex; | |
| 172 } | |
| 173 } | |
| 151 | 174 |
| 152 public boolean begin(int manifestRevision, Nodeid nid, int changelogRevision) { | 175 public boolean begin(int manifestRevision, Nodeid nid, int changelogRevision) { |
| 153 if (needDirs && manifestContent == null) { | 176 if (needDirs && manifestContent == null) { |
| 154 manifestContent = new LinkedList<HgFileRevision>(); | 177 manifestContent = new LinkedList<HgFileRevision>(); |
| 155 } | 178 } |
| 156 visitor.begin(manifestNodeid = nid); | 179 try { |
| 157 return true; | 180 visitor.begin(manifestNodeid = nid); |
| 181 cancelHelper.checkCancelled(); | |
| 182 return true; | |
| 183 } catch (HgCallbackTargetException ex) { | |
| 184 recordFailure(ex); | |
| 185 return false; | |
| 186 } catch (CancelledException ex) { | |
| 187 recordCancel(ex); | |
| 188 return false; | |
| 189 } | |
| 158 } | 190 } |
| 159 public boolean end(int revision) { | 191 public boolean end(int revision) { |
| 160 if (needDirs) { | 192 try { |
| 161 LinkedHashMap<Path, LinkedList<HgFileRevision>> breakDown = new LinkedHashMap<Path, LinkedList<HgFileRevision>>(); | 193 if (needDirs) { |
| 162 for (HgFileRevision fr : manifestContent) { | 194 LinkedHashMap<Path, LinkedList<HgFileRevision>> breakDown = new LinkedHashMap<Path, LinkedList<HgFileRevision>>(); |
| 163 Path filePath = fr.getPath(); | 195 for (HgFileRevision fr : manifestContent) { |
| 164 Path dirPath = pathPool.parent(filePath); | 196 Path filePath = fr.getPath(); |
| 165 LinkedList<HgFileRevision> revs = breakDown.get(dirPath); | 197 Path dirPath = pathPool.parent(filePath); |
| 166 if (revs == null) { | 198 LinkedList<HgFileRevision> revs = breakDown.get(dirPath); |
| 167 revs = new LinkedList<HgFileRevision>(); | 199 if (revs == null) { |
| 168 breakDown.put(dirPath, revs); | 200 revs = new LinkedList<HgFileRevision>(); |
| 201 breakDown.put(dirPath, revs); | |
| 202 } | |
| 203 revs.addLast(fr); | |
| 169 } | 204 } |
| 170 revs.addLast(fr); | 205 for (Path dir : breakDown.keySet()) { |
| 206 visitor.dir(dir); | |
| 207 cancelHelper.checkCancelled(); | |
| 208 for (HgFileRevision fr : breakDown.get(dir)) { | |
| 209 visitor.file(fr); | |
| 210 } | |
| 211 } | |
| 212 manifestContent.clear(); | |
| 171 } | 213 } |
| 172 for (Path dir : breakDown.keySet()) { | 214 visitor.end(manifestNodeid); |
| 173 visitor.dir(dir); | 215 cancelHelper.checkCancelled(); |
| 174 for (HgFileRevision fr : breakDown.get(dir)) { | 216 return true; |
| 175 visitor.file(fr); | 217 } catch (HgCallbackTargetException ex) { |
| 176 } | 218 recordFailure(ex); |
| 177 } | 219 return false; |
| 178 manifestContent.clear(); | 220 } catch (CancelledException ex) { |
| 179 } | 221 recordCancel(ex); |
| 180 visitor.end(manifestNodeid); | 222 return false; |
| 181 manifestNodeid = null; | 223 } finally { |
| 182 return true; | 224 manifestNodeid = null; |
| 225 } | |
| 183 } | 226 } |
| 184 | 227 |
| 185 public boolean next(Nodeid nid, Path fname, Flags flags) { | 228 public boolean next(Nodeid nid, Path fname, Flags flags) { |
| 186 if (matcher != null && !matcher.accept(fname)) { | 229 if (matcher != null && !matcher.accept(fname)) { |
| 187 return true; | 230 return true; |
| 188 } | 231 } |
| 189 HgFileRevision fr = new HgFileRevision(repo, nid, flags, fname); | 232 try { |
| 190 if (needDirs) { | 233 HgFileRevision fr = new HgFileRevision(repo, nid, flags, fname); |
| 191 manifestContent.add(fr); | 234 if (needDirs) { |
| 192 } else { | 235 manifestContent.add(fr); |
| 193 visitor.file(fr); | 236 } else { |
| 194 } | 237 visitor.file(fr); |
| 195 return true; | 238 } |
| 239 return true; | |
| 240 } catch (HgCallbackTargetException ex) { | |
| 241 recordFailure(ex); | |
| 242 return false; | |
| 243 } | |
| 196 } | 244 } |
| 197 } | 245 } |
| 198 } | 246 } |
