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 }