Mercurial > jhg
diff src/org/tmatesoft/hg/repo/HgRemoteRepository.java @ 649:e79cf9a8130b
Push: phase4 - update local and remote phase information
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Wed, 26 Jun 2013 20:52:38 +0200 |
parents | 3b7d51ed4c65 |
children | 3b275cc2d2aa |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/HgRemoteRepository.java Tue Jun 25 20:48:37 2013 +0200 +++ b/src/org/tmatesoft/hg/repo/HgRemoteRepository.java Wed Jun 26 20:52:38 2013 +0200 @@ -66,8 +66,10 @@ import org.tmatesoft.hg.internal.Internals; import org.tmatesoft.hg.internal.DataSerializer.OutputStreamSerializer; import org.tmatesoft.hg.internal.PropertyMarshal; +import org.tmatesoft.hg.util.Outcome; import org.tmatesoft.hg.util.Pair; import org.tmatesoft.hg.util.LogFacility.Severity; +import org.tmatesoft.hg.util.Outcome.Kind; /** * WORK IN PROGRESS, DO NOT USE @@ -450,7 +452,7 @@ } } - public List<Pair<String,Nodeid>> bookmarks() throws HgRemoteConnectionException, HgRuntimeException { + public Bookmarks getBookmarks() throws HgRemoteConnectionException, HgRuntimeException { final String actionName = "Get remote bookmarks"; final List<Pair<String, String>> values = listkeys("bookmarks", actionName); ArrayList<Pair<String, Nodeid>> rv = new ArrayList<Pair<String, Nodeid>>(); @@ -463,7 +465,7 @@ String bm = new String(l.first()); rv.add(new Pair<String, Nodeid>(bm, n)); } - return rv; + return new Bookmarks(rv); } public void updateBookmark(String name, Nodeid oldRev, Nodeid newRev) throws HgRemoteConnectionException, HgRuntimeException { @@ -488,21 +490,48 @@ } } - private void phases() throws HgRemoteConnectionException, HgRuntimeException { + public Phases getPhases() throws HgRemoteConnectionException, HgRuntimeException { + initCapabilities(); + if (!remoteCapabilities.contains("pushkey")) { + // old server defaults to publishing + return new Phases(true, Collections.<Nodeid>emptyList()); + } final List<Pair<String, String>> values = listkeys("phases", "Get remote phases"); + boolean publishing = true; + ArrayList<Nodeid> draftRoots = new ArrayList<Nodeid>(); for (Pair<String, String> l : values) { - System.out.printf("%s : %s\n", l.first(), l.second()); + if ("publishing".equalsIgnoreCase(l.first())) { + publishing = Boolean.parseBoolean(l.second()); + continue; + } + Nodeid root = Nodeid.fromAscii(l.first()); + int ph = Integer.parseInt(l.second()); + if (ph == HgPhase.Draft.mercurialOrdinal()) { + draftRoots.add(root); + } else { + assert false; + sessionContext.getLog().dump(getClass(), Severity.Error, "Unexpected phase value %d for revision %s", ph, root); + } } + return new Phases(publishing, draftRoots); } + public Outcome updatePhase(HgPhase from, HgPhase to, Nodeid n) throws HgRemoteConnectionException, HgRuntimeException { + if (pushkey("phases", n.toString(), String.valueOf(from.mercurialOrdinal()), String.valueOf(to.mercurialOrdinal()))) { + return new Outcome(Kind.Success, String.format("Phase of %s updated to %s", n.shortNotation(), to.name())); + } + return new Outcome(Kind.Failure, String.format("Phase update (%s: %s -> %s) failed", n.shortNotation(), from.name(), to.name())); + } + + public static void main(String[] args) throws Exception { final HgRemoteRepository r = new HgLookup().detectRemote("http://selenic.com/hg", null); if (r.isInvalid()) { return; } System.out.println(r.remoteCapabilities); - r.phases(); - final List<Pair<String, Nodeid>> bm = r.bookmarks(); + r.getPhases(); + final Iterable<Pair<String, Nodeid>> bm = r.getBookmarks(); for (Pair<String, Nodeid> pair : bm) { System.out.println(pair); } @@ -600,6 +629,35 @@ } } + private boolean pushkey(String namespace, String key, String oldValue, String newValue) throws HgRemoteConnectionException, HgRuntimeException { + HttpURLConnection c = null; + try { + final String p = String.format("%s?cmd=pushkey&namespace=%s&key=%s&old=%s&new=&s", url.getPath(), namespace, key, oldValue, newValue); + URL u = new URL(url, p); + c = setupConnection(u.openConnection()); + c.connect(); + if (debug) { + dumpResponseHeader(u, c); + } + checkResponseOk(c, key, "pushkey"); + final InputStream is = c.getInputStream(); + int rv = is.read(); + if (is.read() != -1) { + sessionContext.getLog().dump(getClass(), Severity.Error, "Unexpected data in response to pushkey"); + } + is.close(); + return rv == '1'; + } catch (MalformedURLException ex) { + throw new HgRemoteConnectionException("Bad URL", ex).setRemoteCommand("pushkey").setServerInfo(getLocation()); + } catch (IOException ex) { + throw new HgRemoteConnectionException("Communication failure", ex).setRemoteCommand("pushkey").setServerInfo(getLocation()); + } finally { + if (c != null) { + c.disconnect(); + } + } + } + private void checkResponseOk(HttpURLConnection c, String opName, String remoteCmd) throws HgRemoteConnectionException, IOException { if (c.getResponseCode() != 200) { String m = c.getResponseMessage() == null ? "unknown reason" : c.getResponseMessage(); @@ -712,4 +770,45 @@ return head.equals(o.head) && root.equals(o.root) && (p1 == null && o.p1 == null || p1.equals(o.p1)) && (p2 == null && o.p2 == null || p2.equals(o.p2)); } } + + public static final class Bookmarks implements Iterable<Pair<String, Nodeid>> { + private final List<Pair<String, Nodeid>> bm; + + private Bookmarks(List<Pair<String, Nodeid>> bookmarks) { + bm = bookmarks; + } + + public Iterator<Pair<String, Nodeid>> iterator() { + return bm.iterator(); + } + } + + public static final class Phases { + private final boolean pub; + private final List<Nodeid> droots; + + private Phases(boolean publishing, List<Nodeid> draftRoots) { + pub = publishing; + droots = draftRoots; + } + + /** + * Non-publishing servers may (shall?) respond with a list of draft roots. + * This method doesn't make sense when {@link #isPublishingServer()} is <code>true</code> + * + * @return list of draft roots on remote server + */ + public List<Nodeid> draftRoots() { + assert !pub; + return droots; + } + + /** + * @return <code>true</code> if revisions on remote server shall be deemed published (either + * old server w/o explicit setting, or a new one with <code>phases.publish == true</code>) + */ + public boolean isPublishingServer() { + return pub; + } + } }