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