Mercurial > hg4j
comparison cmdline/org/tmatesoft/hg/console/Outgoing.java @ 181:cd3371670f0b
Refactor incoming and outgoing code to be shared with RepositoryComparator. Placeholders for in/out commands. Refactor common remote lookup code
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Tue, 12 Apr 2011 19:10:38 +0200 |
| parents | 62665d8f0686 |
| children | c6fa4dbfc458 |
comparison
equal
deleted
inserted
replaced
| 180:42fe9a94b9d0 | 181:cd3371670f0b |
|---|---|
| 14 * the terms of a license other than GNU General Public License | 14 * the terms of a license other than GNU General Public License |
| 15 * contact TMate Software at support@hg4j.com | 15 * contact TMate Software at support@hg4j.com |
| 16 */ | 16 */ |
| 17 package org.tmatesoft.hg.console; | 17 package org.tmatesoft.hg.console; |
| 18 | 18 |
| 19 import static org.tmatesoft.hg.core.Nodeid.NULL; | |
| 20 | |
| 21 import java.io.File; | |
| 22 import java.net.URL; | |
| 23 import java.util.Collection; | 19 import java.util.Collection; |
| 24 import java.util.Collections; | |
| 25 import java.util.LinkedList; | |
| 26 import java.util.List; | 20 import java.util.List; |
| 27 | 21 |
| 28 import org.tmatesoft.hg.core.HgException; | 22 import org.tmatesoft.hg.core.HgException; |
| 29 import org.tmatesoft.hg.core.Nodeid; | 23 import org.tmatesoft.hg.core.Nodeid; |
| 30 import org.tmatesoft.hg.internal.ConfigFile; | 24 import org.tmatesoft.hg.internal.RepositoryComparator; |
| 31 import org.tmatesoft.hg.internal.Internals; | |
| 32 import org.tmatesoft.hg.repo.HgChangelog; | 25 import org.tmatesoft.hg.repo.HgChangelog; |
| 33 import org.tmatesoft.hg.repo.HgLookup; | 26 import org.tmatesoft.hg.repo.HgLookup; |
| 34 import org.tmatesoft.hg.repo.HgRemoteRepository; | 27 import org.tmatesoft.hg.repo.HgRemoteRepository; |
| 35 import org.tmatesoft.hg.repo.HgRemoteRepository.RemoteBranch; | |
| 36 import org.tmatesoft.hg.repo.HgRepository; | 28 import org.tmatesoft.hg.repo.HgRepository; |
| 37 | 29 |
| 38 | 30 |
| 39 /** | 31 /** |
| 40 * WORK IN PROGRESS, DO NOT USE | 32 * WORK IN PROGRESS, DO NOT USE |
| 50 HgRepository hgRepo = cmdLineOpts.findRepository(); | 42 HgRepository hgRepo = cmdLineOpts.findRepository(); |
| 51 if (hgRepo.isInvalid()) { | 43 if (hgRepo.isInvalid()) { |
| 52 System.err.printf("Can't find repository in: %s\n", hgRepo.getLocation()); | 44 System.err.printf("Can't find repository in: %s\n", hgRepo.getLocation()); |
| 53 return; | 45 return; |
| 54 } | 46 } |
| 55 String key = "hg4j-gc"; | 47 HgRemoteRepository hgRemote = new HgLookup().detectRemote("hg4j-gc", hgRepo); |
| 56 ConfigFile cfg = new Internals().newConfigFile(); | 48 if (hgRemote.isInvalid()) { |
| 57 cfg.addLocation(new File(System.getProperty("user.home"), ".hgrc")); | 49 System.err.printf("Remote repository %s is not valid", hgRemote.getLocation()); |
| 58 String server = cfg.getSection("paths").get(key); | 50 return; |
| 59 if (server == null) { | |
| 60 throw new HgException(String.format("Can't find server %s specification in the config", key)); | |
| 61 } | 51 } |
| 62 HgRemoteRepository hgRemote = new HgLookup().detect(new URL(server)); | |
| 63 | 52 |
| 64 HgChangelog.ParentWalker pw = hgRepo.getChangelog().new ParentWalker(); | 53 HgChangelog.ParentWalker pw = hgRepo.getChangelog().new ParentWalker(); |
| 65 pw.init(); | 54 pw.init(); |
| 66 | 55 |
| 67 List<Nodeid> commonKnown = findCommonWithRemote(pw, hgRemote); | 56 RepositoryComparator repoCompare = new RepositoryComparator(pw, hgRemote); |
| 57 repoCompare.compare(null); | |
| 58 List<Nodeid> commonKnown = repoCompare.getCommon(); | |
| 68 dump("Nodes known to be both locally and at remote server", commonKnown); | 59 dump("Nodes known to be both locally and at remote server", commonKnown); |
| 69 // sanity check | 60 // sanity check |
| 70 for (Nodeid n : commonKnown) { | 61 for (Nodeid n : commonKnown) { |
| 71 if (!pw.knownNode(n)) { | 62 if (!pw.knownNode(n)) { |
| 72 throw new HgException("Unknown node reported as common:" + n); | 63 throw new HgException("Unknown node reported as common:" + n); |
| 75 // find all local children of commonKnown | 66 // find all local children of commonKnown |
| 76 List<Nodeid> result = pw.childrenOf(commonKnown); | 67 List<Nodeid> result = pw.childrenOf(commonKnown); |
| 77 dump("Result", result); | 68 dump("Result", result); |
| 78 } | 69 } |
| 79 | 70 |
| 80 private static List<Nodeid> findCommonWithRemote(HgChangelog.ParentWalker pwLocal, HgRemoteRepository hgRemote) throws HgException { | |
| 81 List<Nodeid> remoteHeads = hgRemote.heads(); | |
| 82 LinkedList<Nodeid> common = new LinkedList<Nodeid>(); // these remotes are known in local | |
| 83 LinkedList<Nodeid> toQuery = new LinkedList<Nodeid>(); // these need further queries to find common | |
| 84 for (Nodeid rh : remoteHeads) { | |
| 85 if (pwLocal.knownNode(rh)) { | |
| 86 common.add(rh); | |
| 87 } else { | |
| 88 toQuery.add(rh); | |
| 89 } | |
| 90 } | |
| 91 if (toQuery.isEmpty()) { | |
| 92 return common; | |
| 93 } | |
| 94 LinkedList<RemoteBranch> checkUp2Head = new LinkedList<RemoteBranch>(); // branch.root and branch.head are of interest only. | |
| 95 // these are branches with unknown head but known root, which might not be the last common known, | |
| 96 // i.e. there might be children changeset that are also available at remote, [..?..common-head..remote-head] - need to | |
| 97 // scroll up to common head. | |
| 98 while (!toQuery.isEmpty()) { | |
| 99 List<RemoteBranch> remoteBranches = hgRemote.branches(toQuery); //head, root, first parent, second parent | |
| 100 toQuery.clear(); | |
| 101 while(!remoteBranches.isEmpty()) { | |
| 102 RemoteBranch rb = remoteBranches.remove(0); | |
| 103 // I assume branches remote call gives branches with head equal to what I pass there, i.e. | |
| 104 // that I don't need to check whether rb.head is unknown. | |
| 105 if (pwLocal.knownNode(rb.root)) { | |
| 106 // we known branch start, common head is somewhere in its descendants line | |
| 107 checkUp2Head.add(rb); | |
| 108 } else { | |
| 109 // dig deeper in the history, if necessary | |
| 110 if (!NULL.equals(rb.p1) && !pwLocal.knownNode(rb.p1)) { | |
| 111 toQuery.add(rb.p1); | |
| 112 } | |
| 113 if (!NULL.equals(rb.p2) && !pwLocal.knownNode(rb.p2)) { | |
| 114 toQuery.add(rb.p2); | |
| 115 } | |
| 116 } | |
| 117 } | |
| 118 } | |
| 119 // can't check nodes between checkUp2Head element and local heads, remote might have distinct descendants sequence | |
| 120 for (RemoteBranch rb : checkUp2Head) { | |
| 121 // rb.root is known locally | |
| 122 List<Nodeid> remoteRevisions = hgRemote.between(rb.head, rb.root); | |
| 123 if (remoteRevisions.isEmpty()) { | |
| 124 // head is immediate child | |
| 125 common.add(rb.root); | |
| 126 } else { | |
| 127 // between gives result from head to root, I'd like to go in reverse direction | |
| 128 Collections.reverse(remoteRevisions); | |
| 129 Nodeid root = rb.root; | |
| 130 while(!remoteRevisions.isEmpty()) { | |
| 131 Nodeid n = remoteRevisions.remove(0); | |
| 132 if (pwLocal.knownNode(n)) { | |
| 133 if (remoteRevisions.isEmpty()) { | |
| 134 // this is the last known node before an unknown | |
| 135 common.add(n); | |
| 136 break; | |
| 137 } | |
| 138 if (remoteRevisions.size() == 1) { | |
| 139 // there's only one left between known n and unknown head | |
| 140 // this check is to save extra between query, not really essential | |
| 141 Nodeid last = remoteRevisions.remove(0); | |
| 142 common.add(pwLocal.knownNode(last) ? last : n); | |
| 143 break; | |
| 144 } | |
| 145 // might get handy for next between query, to narrow search down | |
| 146 root = n; | |
| 147 } else { | |
| 148 remoteRevisions = hgRemote.between(n, root); | |
| 149 Collections.reverse(remoteRevisions); | |
| 150 if (remoteRevisions.isEmpty()) { | |
| 151 common.add(root); | |
| 152 } | |
| 153 } | |
| 154 } | |
| 155 } | |
| 156 } | |
| 157 // TODO ensure unique elements in the list | |
| 158 return common; | |
| 159 } | |
| 160 | 71 |
| 161 private static void dump(String s, Collection<Nodeid> c) { | 72 private static void dump(String s, Collection<Nodeid> c) { |
| 162 System.out.println(s); | 73 System.out.println(s); |
| 163 for (Nodeid n : c) { | 74 for (Nodeid n : c) { |
| 164 System.out.println(n); | 75 System.out.println(n); |
