Mercurial > jhg
comparison src/org/tmatesoft/hg/internal/RepositoryComparator.java @ 202:706bcc7cfee4
Basic test for HgIncomingCommand. Fix RepositoryComparator for cases when whole repository is unknown. Respect freshly initialized (empty) repositories in general.
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Tue, 26 Apr 2011 02:50:06 +0200 |
| parents | e5407b5a586a |
| children | 66fd2c73c56f |
comparison
equal
deleted
inserted
replaced
| 201:a736f42ed75b | 202:706bcc7cfee4 |
|---|---|
| 25 import java.util.LinkedList; | 25 import java.util.LinkedList; |
| 26 import java.util.List; | 26 import java.util.List; |
| 27 import java.util.ListIterator; | 27 import java.util.ListIterator; |
| 28 import java.util.Map; | 28 import java.util.Map; |
| 29 import java.util.Map.Entry; | 29 import java.util.Map.Entry; |
| 30 import java.util.Set; | |
| 30 | 31 |
| 31 import org.tmatesoft.hg.core.HgBadStateException; | 32 import org.tmatesoft.hg.core.HgBadStateException; |
| 32 import org.tmatesoft.hg.core.HgException; | 33 import org.tmatesoft.hg.core.HgException; |
| 33 import org.tmatesoft.hg.core.Nodeid; | 34 import org.tmatesoft.hg.core.Nodeid; |
| 34 import org.tmatesoft.hg.repo.HgChangelog; | 35 import org.tmatesoft.hg.repo.HgChangelog; |
| 235 // we known branch start, common head is somewhere in its descendants line | 236 // we known branch start, common head is somewhere in its descendants line |
| 236 checkUp2Head.add(rb); | 237 checkUp2Head.add(rb); |
| 237 } else { | 238 } else { |
| 238 chainElement.branchRoot = rb.root; | 239 chainElement.branchRoot = rb.root; |
| 239 // dig deeper in the history, if necessary | 240 // dig deeper in the history, if necessary |
| 240 if (!NULL.equals(rb.p1) && !localRepo.knownNode(rb.p1)) { | 241 boolean hasP1 = !NULL.equals(rb.p1), hasP2 = !NULL.equals(rb.p2); |
| 242 if (hasP1 && !localRepo.knownNode(rb.p1)) { | |
| 241 toQuery.add(rb.p1); | 243 toQuery.add(rb.p1); |
| 242 head2chain.put(rb.p1, chainElement.p1 = new BranchChain(rb.p1)); | 244 head2chain.put(rb.p1, chainElement.p1 = new BranchChain(rb.p1)); |
| 243 } | 245 } |
| 244 if (!NULL.equals(rb.p2) && !localRepo.knownNode(rb.p2)) { | 246 if (hasP2 && !localRepo.knownNode(rb.p2)) { |
| 245 toQuery.add(rb.p2); | 247 toQuery.add(rb.p2); |
| 246 head2chain.put(rb.p2, chainElement.p2 = new BranchChain(rb.p2)); | 248 head2chain.put(rb.p2, chainElement.p2 = new BranchChain(rb.p2)); |
| 249 } | |
| 250 if (!hasP1 && !hasP2) { | |
| 251 // special case, when we do incoming against blank repository, chainElement.branchRoot | |
| 252 // is first unknown element (revision 0). We need to add another fake BranchChain | |
| 253 // to fill the promise that terminal BranchChain has branchRoot that is known both locally and remotely | |
| 254 BranchChain fake = new BranchChain(NULL); | |
| 255 fake.branchRoot = NULL; | |
| 256 chainElement.p1 = chainElement.p2 = fake; | |
| 247 } | 257 } |
| 248 } | 258 } |
| 249 } | 259 } |
| 250 } | 260 } |
| 251 for (RemoteBranch rb : checkUp2Head) { | 261 for (RemoteBranch rb : checkUp2Head) { |
| 289 } | 299 } |
| 290 } | 300 } |
| 291 return branches2load; | 301 return branches2load; |
| 292 } | 302 } |
| 293 | 303 |
| 304 // root and head (and all between) are unknown for each chain element but last (terminal), which has known root (revision | |
| 305 // known to be locally and at remote server | |
| 306 // alternative would be to keep only unknown elements (so that promise of calculateMissingBranches would be 100% true), but that | |
| 307 // seems to complicate the method, while being useful only for the case when we ask incoming for an empty repository (i.e. | |
| 308 // where branch chain return all nodes, -1..tip. | |
| 294 public static final class BranchChain { | 309 public static final class BranchChain { |
| 295 // when we construct a chain, we know head which is missing locally, hence init it right away. | 310 // when we construct a chain, we know head which is missing locally, hence init it right away. |
| 296 // as for root (branch unknown start), we might happen to have one locally, and need further digging to find out right branch start | 311 // as for root (branch unknown start), we might happen to have one locally, and need further digging to find out right branch start |
| 297 public final Nodeid branchHead; | 312 public final Nodeid branchHead; |
| 298 public Nodeid branchRoot; | 313 public Nodeid branchRoot; |
| 305 public BranchChain(Nodeid head) { | 320 public BranchChain(Nodeid head) { |
| 306 assert head != null; | 321 assert head != null; |
| 307 branchHead = head; | 322 branchHead = head; |
| 308 } | 323 } |
| 309 public boolean isTerminal() { | 324 public boolean isTerminal() { |
| 310 return p1 == null || p2 == null; | 325 return p1 == null && p2 == null; // either can be null, see comment above. Terminal is only when no way to descent |
| 311 } | 326 } |
| 312 | 327 |
| 328 // true when this BranchChain is a branch that spans up to very start of the repository | |
| 329 // Thus, the only common revision is NULL, recorded in a fake BranchChain object shared between p1 and p2 | |
| 330 /*package-local*/ boolean isRepoStart() { | |
| 331 return p1 == p2 && p1 != null && p1.branchHead == p1.branchRoot && NULL.equals(p1.branchHead); | |
| 332 } | |
| 333 | |
| 313 @Override | 334 @Override |
| 314 public String toString() { | 335 public String toString() { |
| 315 return String.format("BranchChain [%s, %s]", branchRoot, branchHead); | 336 return String.format("BranchChain [%s, %s]", branchRoot, branchHead); |
| 316 } | 337 } |
| 317 | 338 |
| 458 public List<Nodeid> visitBranches(BranchChain bc) throws HgException { | 479 public List<Nodeid> visitBranches(BranchChain bc) throws HgException { |
| 459 if (bc == null) { | 480 if (bc == null) { |
| 460 return Collections.emptyList(); | 481 return Collections.emptyList(); |
| 461 } | 482 } |
| 462 List<Nodeid> mine = completeBranch(bc.branchRoot, bc.branchHead); | 483 List<Nodeid> mine = completeBranch(bc.branchRoot, bc.branchHead); |
| 463 if (bc.isTerminal()) { | 484 if (bc.isTerminal() || bc.isRepoStart()) { |
| 464 return mine; | 485 return mine; |
| 465 } | 486 } |
| 466 List<Nodeid> parentBranch1 = visitBranches(bc.p1); | 487 List<Nodeid> parentBranch1 = visitBranches(bc.p1); |
| 467 List<Nodeid> parentBranch2 = visitBranches(bc.p2); | 488 List<Nodeid> parentBranch2 = visitBranches(bc.p2); |
| 468 // merge | 489 // merge |
| 493 rv.addAll(merged); | 514 rv.addAll(merged); |
| 494 rv.addAll(mine); | 515 rv.addAll(mine); |
| 495 return rv; | 516 return rv; |
| 496 } | 517 } |
| 497 | 518 |
| 519 public void collectKnownRoots(BranchChain bc, Set<Nodeid> result) { | |
| 520 if (bc == null) { | |
| 521 return; | |
| 522 } | |
| 523 if (bc.isTerminal()) { | |
| 524 result.add(bc.branchRoot); | |
| 525 return; | |
| 526 } | |
| 527 if (bc.isRepoStart()) { | |
| 528 return; | |
| 529 } | |
| 530 collectKnownRoots(bc.p1, result); | |
| 531 collectKnownRoots(bc.p2, result); | |
| 532 } | |
| 498 } | 533 } |
