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); |