Mercurial > jhg
comparison src/org/tmatesoft/hg/core/HgChangeset.java @ 471:7bcfbc255f48
Merge changes from smartgit3 branch into 1.1 stream
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Wed, 11 Jul 2012 20:40:47 +0200 |
parents | 1fc0da631200 03fd8d079e9c |
children | ba36f66c32b4 |
comparison
equal
deleted
inserted
replaced
470:31bd09da0dcf | 471:7bcfbc255f48 |
---|---|
19 import java.util.ArrayList; | 19 import java.util.ArrayList; |
20 import java.util.Collections; | 20 import java.util.Collections; |
21 import java.util.List; | 21 import java.util.List; |
22 import java.util.Map; | 22 import java.util.Map; |
23 | 23 |
24 import org.tmatesoft.hg.internal.PhasesHelper; | |
24 import org.tmatesoft.hg.repo.HgChangelog; | 25 import org.tmatesoft.hg.repo.HgChangelog; |
25 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; | 26 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; |
27 import org.tmatesoft.hg.repo.HgPhase; | |
26 import org.tmatesoft.hg.repo.HgInvalidStateException; | 28 import org.tmatesoft.hg.repo.HgInvalidStateException; |
27 import org.tmatesoft.hg.repo.HgRepository; | 29 import org.tmatesoft.hg.repo.HgRepository; |
28 import org.tmatesoft.hg.repo.HgRuntimeException; | 30 import org.tmatesoft.hg.repo.HgRuntimeException; |
29 import org.tmatesoft.hg.repo.HgStatusCollector; | 31 import org.tmatesoft.hg.repo.HgStatusCollector; |
30 import org.tmatesoft.hg.repo.HgParentChildMap; | 32 import org.tmatesoft.hg.repo.HgParentChildMap; |
39 * | 41 * |
40 * @author Artem Tikhomirov | 42 * @author Artem Tikhomirov |
41 * @author TMate Software Ltd. | 43 * @author TMate Software Ltd. |
42 */ | 44 */ |
43 public class HgChangeset implements Cloneable { | 45 public class HgChangeset implements Cloneable { |
44 private final HgStatusCollector statusHelper; | 46 |
45 private final Path.Source pathHelper; | 47 // these get initialized |
46 | |
47 private HgParentChildMap<HgChangelog> parentHelper; | |
48 | |
49 // | |
50 private RawChangeset changeset; | 48 private RawChangeset changeset; |
49 private int revNumber; | |
51 private Nodeid nodeid; | 50 private Nodeid nodeid; |
52 | 51 |
53 // | 52 class ShareDataStruct { |
53 ShareDataStruct(HgStatusCollector statusCollector, Path.Source pathFactory) { | |
54 statusHelper = statusCollector; | |
55 pathHelper = pathFactory; | |
56 } | |
57 public final HgStatusCollector statusHelper; | |
58 public final Path.Source pathHelper; | |
59 | |
60 public HgParentChildMap<HgChangelog> parentHelper; | |
61 public PhasesHelper phaseHelper; | |
62 }; | |
63 | |
64 // Helpers/utilities shared among few instances of HgChangeset | |
65 private final ShareDataStruct shared; | |
66 | |
67 // these are built on demand | |
54 private List<HgFileRevision> modifiedFiles, addedFiles; | 68 private List<HgFileRevision> modifiedFiles, addedFiles; |
55 private List<Path> deletedFiles; | 69 private List<Path> deletedFiles; |
56 private int revNumber; | |
57 private byte[] parent1, parent2; | 70 private byte[] parent1, parent2; |
71 | |
58 | 72 |
59 // XXX consider CommandContext with StatusCollector, PathPool etc. Commands optionally get CC through a cons or create new | 73 // XXX consider CommandContext with StatusCollector, PathPool etc. Commands optionally get CC through a cons or create new |
60 // and pass it around | 74 // and pass it around |
61 /*package-local*/HgChangeset(HgStatusCollector statusCollector, Path.Source pathFactory) { | 75 /*package-local*/HgChangeset(HgStatusCollector statusCollector, Path.Source pathFactory) { |
62 statusHelper = statusCollector; | 76 shared = new ShareDataStruct(statusCollector, pathFactory); |
63 pathHelper = pathFactory; | |
64 } | 77 } |
65 | 78 |
66 /*package-local*/ void init(int localRevNumber, Nodeid nid, RawChangeset rawChangeset) { | 79 /*package-local*/ void init(int localRevNumber, Nodeid nid, RawChangeset rawChangeset) { |
67 revNumber = localRevNumber; | 80 revNumber = localRevNumber; |
68 nodeid = nid; | 81 nodeid = nid; |
69 changeset = rawChangeset.clone(); | 82 changeset = rawChangeset.clone(); |
70 modifiedFiles = addedFiles = null; | 83 modifiedFiles = addedFiles = null; |
71 deletedFiles = null; | 84 deletedFiles = null; |
72 parent1 = parent2 = null; | 85 parent1 = parent2 = null; |
73 // keep references to parentHelper, statusHelper and pathHelper | 86 // keep references to shared (and everything in there: parentHelper, statusHelper, phaseHelper and pathHelper) |
74 } | 87 } |
75 | 88 |
76 /*package-local*/ void setParentHelper(HgParentChildMap<HgChangelog> pw) { | 89 /*package-local*/ void setParentHelper(HgParentChildMap<HgChangelog> pw) { |
77 parentHelper = pw; | 90 if (pw != null) { |
78 if (parentHelper != null) { | 91 if (pw.getRepo() != shared.statusHelper.getRepo()) { |
79 if (parentHelper.getRepo() != statusHelper.getRepo()) { | |
80 throw new IllegalArgumentException(); | 92 throw new IllegalArgumentException(); |
81 } | 93 } |
82 } | 94 } |
95 shared.parentHelper = pw; | |
83 } | 96 } |
84 | 97 |
85 /** | 98 /** |
86 * Index of the changeset in local repository. Note, this number is relevant only for local repositories/operations, use | 99 * Index of the changeset in local repository. Note, this number is relevant only for local repositories/operations, use |
87 * {@link Nodeid nodeid} to uniquely identify a revision. | 100 * {@link Nodeid nodeid} to uniquely identify a revision. |
155 // files listed, and thus this method would return empty list, while | 168 // files listed, and thus this method would return empty list, while |
156 // #getModifiedFiles() would return list with merged file(s) (because it uses status to get 'em, not | 169 // #getModifiedFiles() would return list with merged file(s) (because it uses status to get 'em, not |
157 // what #files() gives). | 170 // what #files() gives). |
158 ArrayList<Path> rv = new ArrayList<Path>(changeset.files().size()); | 171 ArrayList<Path> rv = new ArrayList<Path>(changeset.files().size()); |
159 for (String name : changeset.files()) { | 172 for (String name : changeset.files()) { |
160 rv.add(pathHelper.path(name)); | 173 rv.add(shared.pathHelper.path(name)); |
161 } | 174 } |
162 return rv; | 175 return rv; |
163 } | 176 } |
164 | 177 |
165 /** | 178 /** |
209 /** | 222 /** |
210 * @return never <code>null</code> | 223 * @return never <code>null</code> |
211 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | 224 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> |
212 */ | 225 */ |
213 public Nodeid getFirstParentRevision() throws HgRuntimeException { | 226 public Nodeid getFirstParentRevision() throws HgRuntimeException { |
214 if (parentHelper != null) { | 227 if (shared.parentHelper != null) { |
215 return parentHelper.safeFirstParent(nodeid); | 228 return shared.parentHelper.safeFirstParent(nodeid); |
216 } | 229 } |
217 // read once for both p1 and p2 | 230 // read once for both p1 and p2 |
218 if (parent1 == null) { | 231 if (parent1 == null) { |
219 parent1 = new byte[20]; | 232 parent1 = new byte[20]; |
220 parent2 = new byte[20]; | 233 parent2 = new byte[20]; |
221 statusHelper.getRepo().getChangelog().parents(revNumber, new int[2], parent1, parent2); | 234 getRepo().getChangelog().parents(revNumber, new int[2], parent1, parent2); |
222 } | 235 } |
223 return Nodeid.fromBinary(parent1, 0); | 236 return Nodeid.fromBinary(parent1, 0); |
224 } | 237 } |
225 | 238 |
226 /** | 239 /** |
227 * @return never <code>null</code> | 240 * @return never <code>null</code> |
228 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | 241 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> |
229 */ | 242 */ |
230 public Nodeid getSecondParentRevision() throws HgRuntimeException { | 243 public Nodeid getSecondParentRevision() throws HgRuntimeException { |
231 if (parentHelper != null) { | 244 if (shared.parentHelper != null) { |
232 return parentHelper.safeSecondParent(nodeid); | 245 return shared.parentHelper.safeSecondParent(nodeid); |
233 } | 246 } |
234 if (parent2 == null) { | 247 if (parent2 == null) { |
235 parent1 = new byte[20]; | 248 parent1 = new byte[20]; |
236 parent2 = new byte[20]; | 249 parent2 = new byte[20]; |
237 statusHelper.getRepo().getChangelog().parents(revNumber, new int[2], parent1, parent2); | 250 getRepo().getChangelog().parents(revNumber, new int[2], parent1, parent2); |
238 } | 251 } |
239 return Nodeid.fromBinary(parent2, 0); | 252 return Nodeid.fromBinary(parent2, 0); |
253 } | |
254 | |
255 /** | |
256 * Tells the phase this changeset belongs to. | |
257 * @return one of {@link HgPhase} values | |
258 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | |
259 */ | |
260 public HgPhase getPhase() throws HgRuntimeException { | |
261 if (shared.phaseHelper == null) { | |
262 // XXX would be handy to obtain ProgressSupport (perhaps, from statusHelper?) | |
263 // and pass it to #init(), so that there could be indication of file being read and cache being built | |
264 synchronized (shared) { | |
265 // ensure field is initialized only once | |
266 if (shared.phaseHelper == null) { | |
267 shared.phaseHelper = new PhasesHelper(getRepo(), shared.parentHelper); | |
268 } | |
269 } | |
270 } | |
271 return shared.phaseHelper.getPhase(this); | |
240 } | 272 } |
241 | 273 |
242 /** | 274 /** |
243 * Create a copy of this changeset | 275 * Create a copy of this changeset |
244 */ | 276 */ |
250 return copy; | 282 return copy; |
251 } catch (CloneNotSupportedException ex) { | 283 } catch (CloneNotSupportedException ex) { |
252 throw new InternalError(ex.toString()); | 284 throw new InternalError(ex.toString()); |
253 } | 285 } |
254 } | 286 } |
287 | |
288 private HgRepository getRepo() { | |
289 return shared.statusHelper.getRepo(); | |
290 } | |
255 | 291 |
256 private /*synchronized*/ void initFileChanges() throws HgRuntimeException { | 292 private /*synchronized*/ void initFileChanges() throws HgRuntimeException { |
257 ArrayList<Path> deleted = new ArrayList<Path>(); | 293 ArrayList<Path> deleted = new ArrayList<Path>(); |
258 ArrayList<HgFileRevision> modified = new ArrayList<HgFileRevision>(); | 294 ArrayList<HgFileRevision> modified = new ArrayList<HgFileRevision>(); |
259 ArrayList<HgFileRevision> added = new ArrayList<HgFileRevision>(); | 295 ArrayList<HgFileRevision> added = new ArrayList<HgFileRevision>(); |
260 HgStatusCollector.Record r = new HgStatusCollector.Record(); | 296 HgStatusCollector.Record r = new HgStatusCollector.Record(); |
261 try { | 297 try { |
262 statusHelper.change(revNumber, r); | 298 shared.statusHelper.change(revNumber, r); |
263 } catch (CancelledException ex) { | 299 } catch (CancelledException ex) { |
264 // Record can't cancel | 300 // Record can't cancel |
265 throw new HgInvalidStateException("Internal error"); | 301 throw new HgInvalidStateException("Internal error"); |
266 } | 302 } |
267 final HgRepository repo = statusHelper.getRepo(); | 303 final HgRepository repo = getRepo(); |
268 for (Path s : r.getModified()) { | 304 for (Path s : r.getModified()) { |
269 Nodeid nid = r.nodeidAfterChange(s); | 305 Nodeid nid = r.nodeidAfterChange(s); |
270 if (nid == null) { | 306 if (nid == null) { |
271 throw new HgInvalidStateException(String.format("For the file %s recorded as modified in changeset %d couldn't find revision after change", s, revNumber)); | 307 throw new HgInvalidStateException(String.format("For the file %s recorded as modified in changeset %d couldn't find revision after change", s, revNumber)); |
272 } | 308 } |