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 }