Rev 1989: Merge new subvertpy version. in file:///data/jelmer/bzr-svn/0.5/

Jelmer Vernooij jelmer at samba.org
Sun Nov 16 22:16:41 GMT 2008


At file:///data/jelmer/bzr-svn/0.5/

------------------------------------------------------------
revno: 1989
revision-id: jelmer at samba.org-20081116221638-x3kyt3f6fdzvhsio
parent: jelmer at samba.org-20081116184104-jbj6c53z96fpklr5
parent: jelmer at samba.org-20081116221228-a5l4r3gmehr911bq
committer: Jelmer Vernooij <jelmer at samba.org>
branch nick: 0.5
timestamp: Sun 2008-11-16 23:16:38 +0100
message:
  Merge new subvertpy version.
modified:
  subvertpy/subvertpy/marshall.py marshall.py-20081006140850-jzf2dbt55rwefdqm-1
  subvertpy/subvertpy/ra_svn.py  ra_svn.py-20081116165419-qplciag3b7ikc6ms-1
    ------------------------------------------------------------
    revno: 1925.2.25
    revision-id: jelmer at samba.org-20081116221228-a5l4r3gmehr911bq
    parent: jelmer at samba.org-20081116184018-na534bdv84jwy5aa
    committer: Jelmer Vernooij <jelmer at samba.org>
    branch nick: trunk
    timestamp: Sun 2008-11-16 23:12:28 +0100
    message:
      Support updating/switching and several other commands in python client.
    modified:
      subvertpy/marshall.py          marshall.py-20081006140850-jzf2dbt55rwefdqm-1
      subvertpy/ra_svn.py            ra_svn.py-20081116165419-qplciag3b7ikc6ms-1
=== modified file 'subvertpy/subvertpy/marshall.py'
--- a/subvertpy/subvertpy/marshall.py	2008-10-15 16:56:59 +0000
+++ b/subvertpy/subvertpy/marshall.py	2008-11-16 22:16:38 +0000
@@ -48,16 +48,21 @@
 
 
 def marshall(x):
-    if isinstance(x, int):
+    if type(x) is int:
         return "%d " % x
-    elif isinstance(x, list) or isinstance(x, tuple):
+    elif type(x) is list or type(x) is tuple:
         return "( " + "".join(map(marshall, x)) + ") "
     elif isinstance(x, literal):
         return "%s " % x
-    elif isinstance(x, str):
+    elif type(x) is str:
         return "%d:%s " % (len(x), x)
-    elif isinstance(x, unicode):
+    elif type(x) is unicode:
         return "%d:%s " % (len(x), x.encode("utf-8"))
+    elif type(x) is bool:
+        if x == True:
+            return "true "
+        elif x == False:
+            return "false "
     raise MarshallError("Unable to marshall type %s" % x)
 
 
@@ -65,7 +70,11 @@
     whitespace = ['\n', ' ']
     if len(x) == 0:
         raise NeedMoreData("Not enough data")
-    if x[0] == "(" and x[1] == " ": # list follows
+    if x[0] == "(": # list follows
+        if len(x) <= 1:
+            raise NeedMoreData("Missing whitespace")
+        if x[1] != " ": 
+            raise MarshallError("missing whitespace after list start")
         x = x[2:]
         ret = []
         try:
@@ -74,6 +83,9 @@
                 ret.append(n)
         except IndexError:
             raise NeedMoreData("List not terminated")
+
+        if len(x) <= 1:
+            raise NeedMoreData("Missing whitespace")
         
         if not x[1] in whitespace:
             raise MarshallError("Expected space, got %c" % x[1])
@@ -103,7 +115,7 @@
                 ret += x[0]
                 x = x[1:]
         except IndexError:
-            raise MarshallError("Expected literal")
+            raise NeedMoreData("Expected literal")
 
         if not x[0] in whitespace:
             raise MarshallError("Expected whitespace, got %c" % x[0])
@@ -111,3 +123,4 @@
         return (x[1:], ret)
     else:
         raise MarshallError("Unexpected character '%c'" % x[0])
+

=== modified file 'subvertpy/subvertpy/ra_svn.py'
--- a/subvertpy/subvertpy/ra_svn.py	2008-11-16 18:39:19 +0000
+++ b/subvertpy/subvertpy/ra_svn.py	2008-11-16 22:12:28 +0000
@@ -23,9 +23,10 @@
 import socket
 import time
 import urllib
-from subvertpy import SubversionException, ERR_RA_SVN_UNKNOWN_CMD, NODE_DIR, NODE_FILE, NODE_UNKNOWN, NODE_NONE, ERR_UNSUPPORTED_FEATURE
-from subvertpy.delta import pack_svndiff0_window, SVNDIFF0_HEADER
+from subvertpy import SubversionException, ERR_RA_SVN_UNKNOWN_CMD, NODE_DIR, NODE_FILE, NODE_UNKNOWN, NODE_NONE, ERR_UNSUPPORTED_FEATURE, properties
+from subvertpy.delta import pack_svndiff0_window, SVNDIFF0_HEADER, unpack_svndiff0
 from subvertpy.marshall import marshall, unmarshall, literal, MarshallError, NeedMoreData
+from subvertpy.ra import DIRENT_KIND, DIRENT_TIME, DIRENT_HAS_PROPS, DIRENT_SIZE, DIRENT_CREATED_REV, DIRENT_LAST_AUTHOR
 from subvertpy.server import generate_random_id
 
 class SVNConnection(object):
@@ -55,10 +56,123 @@
         self.send_msg([literal("success"), list(contents)])
 
 
-
-
 SVN_PORT = 3690
 
+class Reporter:
+
+    def __init__(self, conn, editor):
+        self.conn = conn
+        self.editor = editor
+
+    def set_path(self, path, rev, start_empty=False, lock_token=None, 
+                 depth=None):
+        args = [path, rev, start_empty]
+        if lock_token is not None:
+            args.append([lock_token])
+        else:
+            args.append([])
+        if depth is not None:
+            args.append(depth)
+
+        self.conn.send_msg([literal("set-path"), args])
+
+    def delete_path(self, path):
+        self.conn.send_msg([literal("delete-path"), [path]])
+
+    def link_path(self, path, url, rev, start_empty=False, lock_token=None, 
+                 depth=None):
+        args = [path, url, rev, start_empty]
+        if lock_token is not None:
+            args.append([lock_token])
+        else:
+            args.append([])
+        if depth is not None:
+            args.append(depth)
+
+        self.conn.send_msg([literal("link-path"), args])
+
+    def finish(self):
+        self.conn.send_msg([literal("finish-report"), []])
+        auth = self.conn.recv_msg()
+        tokens = {}
+        diff = {}
+        txdelta_handler = {}
+        # Process commands
+        while True:
+            command, args = self.conn.recv_msg()
+            if command == "target-rev":
+                self.editor.set_target_revision(args[0])
+            elif command == "open-root":
+                if len(args[0]) == 0:
+                    token = self.editor.open_root()
+                else:
+                    token = self.editor.open_root(args[0][0])
+                tokens[args[1]] = token
+            elif command == "delete-entry":
+                tokens[args[2]].delete_entry(args[0], args[1])
+            elif command == "add-dir":
+                if len(args[3]) == 0:
+                    token = tokens[args[1]].add_directory(args[0])
+                else:
+                    token = tokens[args[1]].add_directory(args[0], args[3][0], args[4][0])
+                tokens[args[2]] = token
+            elif command == "open-dir":
+                tokens[args[2]] = tokens[args[1]].open_directory(args[0], args[3])
+            elif command == "change-dir-prop":
+                if len(args[2]) == 0:
+                    tokens[args[0]].change_prop(args[1], None)
+                else:
+                    tokens[args[0]].change_prop(args[1], args[2][0])
+            elif command == "close-dir":
+                tokens[args[0]].close()
+            elif command == "absent-dir":
+                tokens[args[1]].absent(args[0])
+            elif command == "add-file":
+                if len(args[3]) == 0:
+                    token = tokens[args[1]].add_file(args[0])
+                else:
+                    token = tokens[args[1]].add_file(args[0], args[3][0], args[4][0])
+                tokens[args[2]] = token
+            elif command == "open-file":
+                tokens[args[2]] = tokens[args[1]].open_file(args[0], args[3])
+            elif command == "apply-textdelta":
+                if len(args[1]) == 0:
+                    txdelta_handler[args[0]] = tokens[args[0]].apply_textdelta(None)
+                else:
+                    txdelta_handler[args[0]] = tokens[args[0]].apply_textdelta(args[1][0])
+                diff[args[0]] = ""
+            elif command == "textdelta-chunk":
+                diff[args[0]] += args[1]
+            elif command == "textdelta-end":
+                for w in unpack_svndiff0(diff[args[0]]):
+                    txdelta_handler[args[0]](w)
+                txdelta_handler[args[0]](None)
+            elif command == "change-file-prop":
+                if len(args[2]) == 0:
+                    tokens[args[0]].change_prop(args[1], None)
+                else:
+                    tokens[args[0]].change_prop(args[1], args[2][0])
+            elif command == "close-file":
+                if len(args[1]) == 0:
+                    tokens[args[0]].close()
+                else:
+                    tokens[args[0]].close(args[1][0])
+            elif command == "close-edit":
+                self.editor.close()
+                break
+            elif command == "abort-edit":
+                self.editor.abort()
+                break
+
+        self.conn.send_success()
+        self.conn._unpack()
+        self.conn.busy = False
+
+    def abort(self):
+        self.conn.send_msg([literal("abort-report"), []])
+        self.conn.busy = False
+
+
 class Editor:
 
     def __init__(self, conn):
@@ -195,6 +309,10 @@
             self.busy = False
         return ret
 
+    convert.__doc__ = unbound.__doc__
+    convert.__name__ = unbound.__name__
+    return convert
+
 
 class SVNClient(SVNConnection):
 
@@ -219,14 +337,18 @@
             # FIXME: Support other mechanisms as well
             self.send_msg([literal("ANONYMOUS"), [base64.b64encode("anonymous@%s" % socket.gethostname())]])
             self.recv_msg()
-        (self._uuid, self._root_url, other_caps) = self._unpack()
-        self._server_capabilities += other_caps
+        msg = self._unpack()
+        if len(msg) > 2:
+            self._server_capabilities += msg[2]
+        (self._uuid, self._root_url) = msg[0:2]
         self.busy = False
 
     def _unpack(self):
         msg = self.recv_msg()
         if msg[0] == "failure":
-            raise SubversionException(*msg[1])
+            if isinstance(msg[1], str):
+                raise SubversionException(*msg[1])
+            raise SubversionException(msg[1][0][1], msg[1][0][0])
         assert msg[0] == "success"
         assert len(msg) == 2
         return msg[1]
@@ -279,17 +401,69 @@
         raise NotImplementedError(self.get_location_segments)
 
     def has_capability(self, capability):
-        raise NotImplementedError(self.has_capability)
+        return capability in self._server_capabilities
 
-    def check_path(self, path, revision):
-        raise NotImplementedError(self.check_path)
+    @mark_busy
+    def check_path(self, path, revision=None):
+        args = [path]
+        if revision is None or revision == -1:
+            args.append([])
+        else:
+            args.append([revision])
+        self.send_msg([literal("check-path"), args])
+        self._recv_ack()
+        ret = self._unpack()[0]
+        return {"dir": NODE_DIR, "file": NODE_FILE, "unknown": NODE_UNKNOWN, "none": NODE_NONE}[ret]
 
     def get_lock(self, path):
         raise NotImplementedError(self.get_lock)
 
-    def get_dir(self, path, revision=-1, dirent_fields=0):
-        raise NotImplementedError(self.get_dir)
-
+    @mark_busy
+    def get_dir(self, path, revision=-1, dirent_fields=0, want_props=True, want_contents=True):
+        args = [path]
+        if revision is None or revision == -1:
+            args.append([])
+        else:
+            args.append([revision])
+        
+        args += [want_props, want_contents]
+
+        fields = []
+        if dirent_fields & DIRENT_KIND:
+            fields.append(literal("kind"))
+        if dirent_fields & DIRENT_SIZE:
+            fields.append(literal("size"))
+        if dirent_fields & DIRENT_HAS_PROPS:
+            fields.append(literal("has-props"))
+        if dirent_fields & DIRENT_CREATED_REV:
+            fields.append(literal("created-rev"))
+        if dirent_fields & DIRENT_TIME:
+            fields.append(literal("time"))
+        if dirent_fields & DIRENT_LAST_AUTHOR:
+            fields.append(literal("last-author"))
+        args.append(fields)
+
+        self.send_msg([literal("get-dir"), args])
+        self._recv_ack()
+        ret = self._unpack()
+        fetch_rev = ret[0]
+        props = dict(ret[1])
+        dirents = {}
+        for d in ret[2]:
+            name = d[0]
+            dirents[name] = {}
+            dirents[name]["kind"] = d[1]
+            dirents[name]["size"] = d[2]
+            dirents[name]["has-props"] = bool(d[3])
+            dirents[name]["created-rev"] = d[4]
+            if d[5] != []:
+                dirents[name]["created-date"] = d[5]
+            if d[6] != []:
+                dirents[name]["last-author"] = d[6]
+
+        return (dirents, fetch_rev, props)
+
+    @mark_busy
     def get_file(self, path, stream, revision=-1):
         raise NotImplementedError(self.get_file)
 
@@ -301,7 +475,9 @@
         raise NotImplementedError(self.get_commit_editor)
 
     def rev_proplist(self, revision):
-        raise NotImplementedError(self.rev_proplist)
+        self.send_msg([literal("rev-proplist"), [revision]])
+        self._recv_ack()
+        return dict(self._unpack()[0])
 
     def replay(self, revision, low_water_mark, update_editor, send_deltas=True):
         raise NotImplementedError(self.replay)
@@ -311,12 +487,39 @@
         raise NotImplementedError(self.replay_range)
 
     def do_switch(self, revision_to_update_to, update_target, recurse, 
-                  switch_url, update_editor):
-        raise NotImplementedError(self.do_switch)
+                  switch_url, update_editor, depth=None):
+        args = []
+        if revision_to_update_to is None or revision_to_update_to == -1:
+            args.append([])
+        else:
+            args.append([revision_to_update_to])
+        args.append(update_target)
+        args.append(recurse)
+        args.append(switch_url)
+        if depth is not None:
+            args.append(literal(depth))
+
+        self.busy = True
+        self.send_msg([literal("switch"), args])
+        self._recv_ack()
+        return Reporter(self, update_editor)
 
     def do_update(self, revision_to_update_to, update_target, recurse, 
-                  update_editor):
-        raise NotImplementedError(self.do_update)
+                  update_editor, depth=None):
+        args = []
+        if revision_to_update_to is None or revision_to_update_to == -1:
+            args.append([])
+        else:
+            args.append([revision_to_update_to])
+        args.append(update_target)
+        args.append(recurse)
+        if depth is not None:
+            args.append(literal(depth))
+
+        self.busy = True
+        self.send_msg([literal("update"), args])
+        self._recv_ack()
+        return Reporter(self, update_editor)
 
     def do_diff(self, revision_to_update, diff_target, versus_url, diff_editor,
                 recurse=True, ignore_ancestry=False, text_deltas=False):
@@ -335,19 +538,80 @@
         self.send_msg([literal("reparent"), [url]])
         self._recv_ack()
         self._unpack()
+        self.url = url
 
-    def get_uuid(self, uuid):
+    def get_uuid(self):
         return self._uuid
 
-    def get_log(self, callback, paths, start, end, limit, 
-                discover_changed_paths, strict_node_history, 
-                include_merged_revisions, revprops):
-        raise NotImplementedError(self.get_log)
+    @mark_busy
+    def log(self, paths, start, end, limit=0, 
+                discover_changed_paths=True, strict_node_history=True, 
+                include_merged_revisions=True, revprops=None):
+        args = [paths]
+        if start is None or start == -1:
+            args.append([])
+        else:
+            args.append([start])
+        if end is None or end == -1:
+            args.append([])
+        else:
+            args.append([end])
+        args.append(discover_changed_paths)
+        args.append(strict_node_history)
+        args.append(limit)
+        args.append(include_merged_revisions)
+        if revprops is None:
+            args.append(literal("all-revprops"))
+            args.append([])
+        else:
+            args.append(literal("revprops"))
+            args.append(revprops)
+
+        self.send_msg([literal("log"), args])
+        self._recv_ack()
+        while True:
+            msg = self.recv_msg()
+            if msg == "done":
+                break
+            paths = {}
+            for p, action, cfd in msg[0]:
+                if len(cfd) == 0:
+                    paths[p] = (str(action), None, -1)
+                else:
+                    paths[p] = (str(action), cfd[0], cfd[1])
+
+            if len(msg) > 5:
+                has_children = msg[5]
+            else:
+                has_children = None
+            if len(msg) > 6 and msg[6]:
+                revno = None
+            else:
+                revno = msg[1]
+            revprops = {}
+            if len(msg[2]) != 0:
+                revprops[properties.PROP_REVISION_AUTHOR] = msg[2][0]
+            if len(msg[3]) != 0:
+                revprops[properties.PROP_REVISION_DATE] = msg[3][0]
+            if len(msg[4]) != 0:
+                revprops[properties.PROP_REVISION_LOG] = msg[4][0]
+            if len(msg) > 8:
+                revprops.update(dict(msg[8]))
+            yield paths, msg[1], revprops, has_children
+
+        self._unpack()
+
+    def get_log(self, callback, *args, **kwargs):
+        for (paths, rev, props, has_children) in self.log(*args, **kwargs):
+            if has_children is None:
+                callback(paths, rev, props)
+            else:
+                callback(paths, rev, props, has_children)
     
 
 MIN_VERSION = 2
 MAX_VERSION = 2
-CAPABILITIES = ["edit-pipeline", "bazaar"]
+CAPABILITIES = ["edit-pipeline", "bazaar", "log-revprops"]
 MECHANISMS = ["ANONYMOUS"]
 
 




More information about the bazaar-commits mailing list