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 } |