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