comparison src/org/tmatesoft/hg/repo/HgRemoteRepository.java @ 178:62665d8f0686

Complete logic to discover all branches missing locally. Most of wire protocol in HgRemoteRepository
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 06 Apr 2011 01:34:16 +0200
parents e10225daface
children da426c2fe1ec
comparison
equal deleted inserted replaced
177:e10225daface 178:62665d8f0686
25 import java.net.MalformedURLException; 25 import java.net.MalformedURLException;
26 import java.net.URL; 26 import java.net.URL;
27 import java.net.URLConnection; 27 import java.net.URLConnection;
28 import java.security.cert.CertificateException; 28 import java.security.cert.CertificateException;
29 import java.security.cert.X509Certificate; 29 import java.security.cert.X509Certificate;
30 import java.util.ArrayList;
30 import java.util.Collection; 31 import java.util.Collection;
31 import java.util.Collections; 32 import java.util.Collections;
32 import java.util.Iterator; 33 import java.util.Iterator;
33 import java.util.LinkedHashMap; 34 import java.util.LinkedHashMap;
34 import java.util.LinkedList; 35 import java.util.LinkedList;
57 public class HgRemoteRepository { 58 public class HgRemoteRepository {
58 59
59 private final URL url; 60 private final URL url;
60 private final SSLContext sslContext; 61 private final SSLContext sslContext;
61 private final String authInfo; 62 private final String authInfo;
63 private final boolean debug = Boolean.FALSE.booleanValue();
62 64
63 HgRemoteRepository(URL url) throws HgException { 65 HgRemoteRepository(URL url) throws HgException {
64 if (url == null) { 66 if (url == null) {
65 throw new IllegalArgumentException(); 67 throw new IllegalArgumentException();
66 } 68 }
102 } else { 104 } else {
103 authInfo = null; 105 authInfo = null;
104 } 106 }
105 } 107 }
106 108
107 public List<Nodeid> heads() { 109 public List<Nodeid> heads() throws HgException {
108 return Collections.singletonList(Nodeid.fromAscii("71ddbf8603e8e09d54ac9c5fe4bb5ae824589f1d")); 110 try {
109 // return Collections.emptyList(); 111 URL u = new URL(url, url.getPath() + "?cmd=heads");
112 HttpURLConnection c = setupConnection(u.openConnection());
113 c.connect();
114 if (debug) {
115 dumpResponseHeader(u, c);
116 }
117 InputStreamReader is = new InputStreamReader(c.getInputStream(), "US-ASCII");
118 StreamTokenizer st = new StreamTokenizer(is);
119 st.ordinaryChars('0', '9');
120 st.wordChars('0', '9');
121 st.eolIsSignificant(false);
122 LinkedList<Nodeid> parseResult = new LinkedList<Nodeid>();
123 while (st.nextToken() != StreamTokenizer.TT_EOF) {
124 parseResult.add(Nodeid.fromAscii(st.sval));
125 }
126 return parseResult;
127 } catch (MalformedURLException ex) {
128 throw new HgException(ex);
129 } catch (IOException ex) {
130 throw new HgException(ex);
131 }
110 } 132 }
111 133
112 public List<Nodeid> between(Nodeid tip, Nodeid base) throws HgException { 134 public List<Nodeid> between(Nodeid tip, Nodeid base) throws HgException {
113 Range r = new Range(base, tip); 135 Range r = new Range(base, tip);
114 // XXX shall handle errors like no range key in the returned map, not sure how. 136 // XXX shall handle errors like no range key in the returned map, not sure how.
153 os.flush(); 175 os.flush();
154 os.close(); 176 os.close();
155 } else { 177 } else {
156 c.connect(); 178 c.connect();
157 } 179 }
158 System.out.printf("%d ranges, method:%s \n", ranges.size(), c.getRequestMethod()); 180 if (debug) {
159 System.out.printf("Query (%d bytes):%s\n", u.getQuery().length(), u.getQuery()); 181 System.out.printf("%d ranges, method:%s \n", ranges.size(), c.getRequestMethod());
160 System.out.println("Response headers:"); 182 dumpResponseHeader(u, c);
161 final Map<String, List<String>> headerFields = c.getHeaderFields();
162 for (String s : headerFields.keySet()) {
163 System.out.printf("%s: %s\n", s, c.getHeaderField(s));
164 } 183 }
165 InputStreamReader is = new InputStreamReader(c.getInputStream(), "US-ASCII"); 184 InputStreamReader is = new InputStreamReader(c.getInputStream(), "US-ASCII");
166 StreamTokenizer st = new StreamTokenizer(is); 185 StreamTokenizer st = new StreamTokenizer(is);
167 st.ordinaryChars('0', '9'); 186 st.ordinaryChars('0', '9');
168 st.wordChars('0', '9'); 187 st.wordChars('0', '9');
211 } catch (IOException ex) { 230 } catch (IOException ex) {
212 throw new HgException(ex); 231 throw new HgException(ex);
213 } 232 }
214 } 233 }
215 234
216 public List<RemoteBranch> branches(List<Nodeid> nodes) { 235 public List<RemoteBranch> branches(List<Nodeid> nodes) throws HgException {
217 return Collections.emptyList(); 236 StringBuilder sb = new StringBuilder(20 + nodes.size() * 41);
237 sb.append("nodes=");
238 for (Nodeid n : nodes) {
239 sb.append(n.toString());
240 sb.append('+');
241 }
242 if (sb.charAt(sb.length() - 1) == '+') {
243 // strip last space
244 sb.setLength(sb.length() - 1);
245 }
246 try {
247 URL u = new URL(url, url.getPath() + "?cmd=branches&" + sb.toString());
248 HttpURLConnection c = setupConnection(u.openConnection());
249 c.connect();
250 if (debug) {
251 dumpResponseHeader(u, c);
252 }
253 InputStreamReader is = new InputStreamReader(c.getInputStream(), "US-ASCII");
254 StreamTokenizer st = new StreamTokenizer(is);
255 st.ordinaryChars('0', '9');
256 st.wordChars('0', '9');
257 st.eolIsSignificant(false);
258 ArrayList<Nodeid> parseResult = new ArrayList<Nodeid>(nodes.size() * 4);
259 while (st.nextToken() != StreamTokenizer.TT_EOF) {
260 parseResult.add(Nodeid.fromAscii(st.sval));
261 }
262 if (parseResult.size() != nodes.size() * 4) {
263 throw new HgException(String.format("Bad number of nodeids in result (shall be factor 4), expected %d, got %d", nodes.size()*4, parseResult.size()));
264 }
265 ArrayList<RemoteBranch> rv = new ArrayList<RemoteBranch>(nodes.size());
266 for (int i = 0; i < nodes.size(); i++) {
267 RemoteBranch rb = new RemoteBranch(parseResult.get(i*4), parseResult.get(i*4 + 1), parseResult.get(i*4 + 2), parseResult.get(i*4 + 3));
268 rv.add(rb);
269 }
270 return rv;
271 } catch (MalformedURLException ex) {
272 throw new HgException(ex);
273 } catch (IOException ex) {
274 throw new HgException(ex);
275 }
218 } 276 }
219 277
220 // WireProtocol wiki: roots = a list of the latest nodes on every service side changeset branch that both the client and server know about. 278 // WireProtocol wiki: roots = a list of the latest nodes on every service side changeset branch that both the client and server know about.
221 public HgBundle getChanges(List<Nodeid> roots) throws HgException { 279 public HgBundle getChanges(List<Nodeid> roots) throws HgException {
222 return new HgLookup().loadBundle(new File("/temp/hg/hg-bundle-000000000000-gz.tmp")); 280 return new HgLookup().loadBundle(new File("/temp/hg/hg-bundle-000000000000-gz.tmp"));
230 } 288 }
231 if (sslContext != null) { 289 if (sslContext != null) {
232 ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslContext.getSocketFactory()); 290 ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslContext.getSocketFactory());
233 } 291 }
234 return (HttpURLConnection) urlConnection; 292 return (HttpURLConnection) urlConnection;
293 }
294
295 private void dumpResponseHeader(URL u, HttpURLConnection c) {
296 System.out.printf("Query (%d bytes):%s\n", u.getQuery().length(), u.getQuery());
297 System.out.println("Response headers:");
298 final Map<String, List<String>> headerFields = c.getHeaderFields();
299 for (String s : headerFields.keySet()) {
300 System.out.printf("%s: %s\n", s, c.getHeaderField(s));
301 }
235 } 302 }
236 303
237 public static final class Range { 304 public static final class Range {
238 /** 305 /**
239 * Root of the range, earlier revision 306 * Root of the range, earlier revision