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