ignore build output.
[jelmer/subvertpy.git] / transport.py
diff --git a/transport.py b/transport.py
deleted file mode 100644 (file)
index 93d884c..0000000
+++ /dev/null
@@ -1,558 +0,0 @@
-# Copyright (C) 2006 Jelmer Vernooij <jelmer@samba.org>
-# -*- coding: utf-8 -*-
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-"""Simple transport for accessing Subversion smart servers."""
-
-import bzrlib
-from bzrlib import debug, urlutils
-from bzrlib.errors import (NoSuchFile, TransportNotPossible, 
-                           FileExists, NotLocalUrl, InvalidURL, RedirectRequested)
-from bzrlib.trace import mutter, warning
-from bzrlib.transport import Transport
-
-import bzrlib.plugins.svn
-from bzrlib.plugins.svn.auth import create_auth_baton
-from bzrlib.plugins.svn.subvertpy.client import get_config
-from bzrlib.plugins.svn.subvertpy import SubversionException, ra, ERR_BAD_URL, ERR_RA_SVN_REPOS_NOT_FOUND, ERR_FS_ALREADY_EXISTS, ERR_FS_NOT_DIRECTORY, ERR_RA_DAV_RELOCATED, ERR_RA_DAV_PATH_NOT_FOUND, ERR_UNKNOWN_CAPABILITY
-from bzrlib.plugins.svn.errors import convert_svn_error, NoSvnRepositoryPresent
-import urlparse
-import urllib
-
-svn_config = get_config()
-
-def get_client_string():
-    """Return a string that can be send as part of the User Agent string."""
-    return "bzr%s+bzr-svn%s" % (bzrlib.__version__, bzrlib.plugins.svn.__version__)
-
-# Don't run any tests on SvnTransport as it is not intended to be 
-# a full implementation of Transport
-def get_test_permutations():
-    return []
-
-
-def get_svn_ra_transport(bzr_transport):
-    """Obtain corresponding SvnRaTransport for a stock Bazaar transport."""
-    if isinstance(bzr_transport, SvnRaTransport):
-        return bzr_transport
-
-    ra_transport = getattr(bzr_transport, "_svn_ra", None)
-    if ra_transport is not None:
-        return ra_transport
-
-    # Save _svn_ra transport here so we don't have to connect again next time
-    # we try to use bzr svn on this transport
-    ra_transport = SvnRaTransport(bzr_transport.base)
-    bzr_transport._svn_ra = ra_transport
-    return ra_transport
-
-
-def _url_unescape_uri(url):
-    (scheme, netloc, path, query, fragment) = urlparse.urlsplit(url)
-    if scheme in ("http", "https"):
-        # Without this, URLs with + in them break
-        path = urllib.unquote(path)
-    return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
-
-
-def _url_escape_uri(url):
-    (scheme, netloc, path, query, fragment) = urlparse.urlsplit(url)
-    if scheme in ("http", "https"):
-        # Without this, URLs with + in them break
-        path = urllib.quote(path)
-    return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
-
-
-svnplus_warning_showed = False
-
-def warn_svnplus(url):
-    global svnplus_warning_showed
-    if not svnplus_warning_showed:
-        warning("The svn+ syntax is deprecated, use %s instead.", url)
-        svnplus_warning_showed = True
-
-
-def bzr_to_svn_url(url):
-    """Convert a Bazaar URL to a URL understood by Subversion.
-
-    This will possibly remove the svn+ prefix.
-    """
-    if (url.startswith("svn+http://") or 
-        url.startswith("svn+file://") or
-        url.startswith("svn+https://")):
-        url = url[len("svn+"):] # Skip svn+
-        warn_svnplus(url)
-
-    url = _url_unescape_uri(url)
-
-    # The SVN libraries don't like trailing slashes...
-    url = url.rstrip('/')
-
-    return url
-
-
-def Connection(url):
-    try:
-        mutter('opening SVN RA connection to %r' % url)
-        ret = ra.RemoteAccess(url.encode('utf8'), 
-                auth=create_auth_baton(url),
-                client_string_func=get_client_string)
-        if 'transport' in debug.debug_flags:
-            ret = MutteringRemoteAccess(ret)
-    except SubversionException, (msg, num):
-        if num in (ERR_RA_SVN_REPOS_NOT_FOUND,):
-            raise NoSvnRepositoryPresent(url=url)
-        if num == ERR_BAD_URL:
-            raise InvalidURL(url)
-        if num == ERR_RA_DAV_PATH_NOT_FOUND:
-            raise NoSuchFile(url)
-        if num == ERR_RA_DAV_RELOCATED:
-            # Try to guess the new url
-            if "'" in msg:
-                new_url = msg.split("'")[1]
-            elif "«" in msg:
-                new_url = msg[msg.index("»")+2:msg.index("«")]
-            else:
-                raise AssertionError("Unable to parse error message: %s" % msg)
-            raise RedirectRequested(source=url, target=new_url, 
-                                    is_permanent=True)
-        raise
-
-    from bzrlib.plugins.svn import lazy_check_versions
-    lazy_check_versions()
-
-    return ret
-
-
-class ConnectionPool(object):
-    """Collection of connections to a Subversion repository."""
-    def __init__(self):
-        self.connections = set()
-
-    def get(self, url):
-        # Check if there is an existing connection we can use
-        for c in self.connections:
-            assert not c.busy, "busy connection in pool"
-            if c.url == url:
-                self.connections.remove(c)
-                return c
-        # Nothing available? Just pick an existing one and reparent:
-        if len(self.connections) == 0:
-            return Connection(url)
-        c = self.connections.pop()
-        try:
-            c.reparent(_url_escape_uri(url))
-            return c
-        except NotImplementedError:
-            self.connections.add(c)
-            return Connection(url)
-        except:
-            self.connections.add(c)
-            raise
-
-    def add(self, connection):
-        assert not connection.busy, "adding busy connection in pool"
-        self.connections.add(connection)
-    
-
-class SvnRaTransport(Transport):
-    """Fake transport for Subversion-related namespaces.
-    
-    This implements just as much of Transport as is necessary 
-    to fool Bazaar. """
-    @convert_svn_error
-    def __init__(self, url="", pool=None, _uuid=None, _repos_root=None):
-        bzr_url = url
-        self.svn_url = bzr_to_svn_url(url)
-        Transport.__init__(self, bzr_url)
-
-        if pool is None:
-            self.connections = ConnectionPool()
-
-            # Make sure that the URL is valid by connecting to it.
-            self.connections.add(self.connections.get(self.svn_url))
-        else:
-            self.connections = pool
-
-        self._repos_root = _repos_root
-        self._uuid = _uuid
-        self.capabilities = {}
-
-        from bzrlib.plugins.svn import lazy_check_versions
-        lazy_check_versions()
-
-    def get_connection(self, repos_path=None):
-        if repos_path is not None:
-            return self.connections.get(urlutils.join(self.get_svn_repos_root(), 
-                                        repos_path))
-        else:
-            return self.connections.get(self.svn_url)
-
-    def add_connection(self, conn):
-        self.connections.add(conn)
-
-    def has(self, relpath):
-        """See Transport.has()."""
-        # TODO: Raise TransportNotPossible here instead and 
-        # catch it in bzrdir.py
-        return False
-
-    def get(self, relpath):
-        """See Transport.get()."""
-        # TODO: Raise TransportNotPossible here instead and 
-        # catch it in bzrdir.py
-        raise NoSuchFile(path=relpath)
-
-    def stat(self, relpath):
-        """See Transport.stat()."""
-        raise TransportNotPossible('stat not supported on Subversion')
-
-    def put_file(self, name, file, mode=0):
-        raise TransportNotPossible("put_file not supported on Subversion")
-
-    def get_uuid(self):
-        if self._uuid is None:
-            conn = self.get_connection()
-            try:
-                return conn.get_uuid()
-            finally:
-                self.add_connection(conn)
-        return self._uuid
-
-    def get_repos_root(self):
-        root = self.get_svn_repos_root()
-        if (self.base.startswith("svn+http:") or 
-            self.base.startswith("svn+https:")):
-            return "svn+%s" % root
-        return root
-
-    def get_svn_repos_root(self):
-        if self._repos_root is None:
-            conn = self.get_connection()
-            try:
-                self._repos_root = conn.get_repos_root()
-            finally:
-                self.add_connection(conn)
-        return self._repos_root
-
-    def get_latest_revnum(self):
-        conn = self.get_connection()
-        try:
-            return conn.get_latest_revnum()
-        finally:
-            self.add_connection(conn)
-
-    def iter_log(self, paths, from_revnum, to_revnum, limit, discover_changed_paths, 
-                 strict_node_history, include_merged_revisions, revprops):
-        assert paths is None or isinstance(paths, list)
-        assert isinstance(from_revnum, int) and isinstance(to_revnum, int)
-        assert isinstance(limit, int)
-        from threading import Thread, Semaphore
-
-        class logfetcher(Thread):
-            def __init__(self, transport, *args, **kwargs):
-                Thread.__init__(self)
-                self.setDaemon(True)
-                self.transport = transport
-                self.args = args
-                self.kwargs = kwargs
-                self.pending = []
-                self.conn = self.transport.get_connection()
-                self.semaphore = Semaphore(0)
-                self.busy = False
-
-            def next(self):
-                self.semaphore.acquire()
-                ret = self.pending.pop(0)
-                if isinstance(ret, Exception):
-                    raise ret
-                return ret
-
-            def run(self):
-                assert not self.busy, "already running"
-                self.busy = True
-                def rcvr(orig_paths, revision, revprops, has_children=None):
-                    self.pending.append((orig_paths, revision, revprops, has_children))
-                    self.semaphore.release()
-                try:
-                    try:
-                        self.conn.get_log(rcvr, *self.args, **self.kwargs)
-                        self.pending.append(None)
-                    except Exception, e:
-                        self.pending.append(e)
-                finally:
-                    self.pending.append(Exception("Some exception was not handled"))
-                    self.semaphore.release()
-                    self.transport.add_connection(self.conn)
-
-        if paths is None:
-            newpaths = None
-        else:
-            newpaths = [p.rstrip("/") for p in paths]
-
-        fetcher = logfetcher(self, newpaths, from_revnum, to_revnum, limit, discover_changed_paths=discover_changed_paths, strict_node_history=strict_node_history, include_merged_revisions=include_merged_revisions, revprops=revprops)
-        fetcher.start()
-        return iter(fetcher.next, None)
-
-    def get_log(self, rcvr, paths, from_revnum, to_revnum, limit, discover_changed_paths, 
-                strict_node_history, include_merged_revisions, revprops):
-        assert paths is None or isinstance(paths, list), "Invalid paths"
-
-        all_true = True
-        for item in [isinstance(x, str) for x in paths]:
-            if not item:
-                all_true = False
-                break
-        
-        assert paths is None or all_true
-
-        if paths is None:
-            newpaths = None
-        else:
-            newpaths = [p.rstrip("/") for p in paths]
-
-        conn = self.get_connection()
-        try:
-            return conn.get_log(rcvr, newpaths, 
-                    from_revnum, to_revnum,
-                    limit, discover_changed_paths, strict_node_history, 
-                    include_merged_revisions,
-                    revprops)
-        finally:
-            self.add_connection(conn)
-
-    def change_rev_prop(self, revnum, name, value):
-        conn = self.get_connection()
-        try:
-            return conn.change_rev_prop(revnum, name, value)
-        finally:
-            self.add_connection(conn)
-
-    def get_dir(self, path, revnum, kind=False):
-        conn = self.get_connection()
-        try:
-            return conn.get_dir(path, revnum, kind)
-        finally:
-            self.add_connection(conn)
-
-    def get_file(self, path, stream, revnum):
-        conn = self.get_connection()
-        try:
-            return conn.get_file(path, stream, revnum)
-        finally:
-            self.add_connection(conn)
-
-    def list_dir(self, relpath):
-        assert len(relpath) == 0 or relpath[0] != "/"
-        if relpath == ".":
-            relpath = ""
-        try:
-            (dirents, _, _) = self.get_dir(relpath, self.get_latest_revnum())
-        except SubversionException, (msg, num):
-            if num == ERR_FS_NOT_DIRECTORY:
-                raise NoSuchFile(relpath)
-            raise
-        return dirents.keys()
-
-    def check_path(self, path, revnum):
-        conn = self.get_connection()
-        try:
-            return conn.check_path(path, revnum)
-        finally:
-            self.add_connection(conn)
-
-    @convert_svn_error
-    def mkdir(self, relpath, message="Creating directory"):
-        conn = self.get_connection()
-        try:
-            ce = conn.get_commit_editor({"svn:log": message})
-            try:
-                node = ce.open_root(-1)
-                batons = relpath.split("/")
-                toclose = [node]
-                for i in range(len(batons)):
-                    node = node.open_directory("/".join(batons[:i]), -1)
-                    toclose.append(node)
-                toclose.append(node.add_directory(relpath, None, -1))
-                for c in reversed(toclose):
-                    c.close()
-                ce.close()
-            except SubversionException, (msg, num):
-                ce.abort()
-                if num == ERR_FS_NOT_DIRECTORY:
-                    raise NoSuchFile(msg)
-                if num == ERR_FS_ALREADY_EXISTS:
-                    raise FileExists(msg)
-                raise
-        finally:
-            self.add_connection(conn)
-
-    def has_capability(self, cap):
-        if cap in self.capabilities:
-            return self.capabilities[cap]
-        conn = self.get_connection()
-        try:
-            try:
-                self.capabilities[cap] = conn.has_capability(cap)
-            except SubversionException, (msg, num):
-                if num != ERR_UNKNOWN_CAPABILITY:
-                    raise
-                self.capabilities[cap] = None
-            except NotImplementedError:
-                self.capabilities[cap] = None # None for unknown
-            return self.capabilities[cap]
-        finally:
-            self.add_connection(conn)
-
-    def revprop_list(self, revnum):
-        conn = self.get_connection()
-        try:
-            return conn.rev_proplist(revnum)
-        finally:
-            self.add_connection(conn)
-
-    def get_locations(self, path, peg_revnum, revnums):
-        conn = self.get_connection()
-        try:
-            return conn.get_locations(path, peg_revnum, revnums)
-        finally:
-            self.add_connection(conn)
-
-    def listable(self):
-        """See Transport.listable().
-        """
-        return True
-
-    # There is no real way to do locking directly on the transport 
-    # nor is there a need to as the remote server will take care of 
-    # locking
-    class PhonyLock(object):
-        def unlock(self):
-            pass
-
-    def lock_read(self, relpath):
-        """See Transport.lock_read()."""
-        return self.PhonyLock()
-
-    def lock_write(self, path_revs, comment=None, steal_lock=False):
-        return self.PhonyLock() # FIXME
-
-    def _is_http_transport(self):
-        return False
-        return (self.svn_url.startswith("http://") or 
-                self.svn_url.startswith("https://"))
-
-    def clone_root(self):
-        if self._is_http_transport():
-            return SvnRaTransport(self.get_repos_root(), 
-                                  bzr_to_svn_url(self.base),
-                                  pool=self.connections)
-        return SvnRaTransport(self.get_repos_root(),
-                              pool=self.connections)
-
-    def clone(self, offset=None):
-        """See Transport.clone()."""
-        if offset is None:
-            newurl = self.base
-        else:
-            newurl = urlutils.join(self.base, offset)
-
-        return SvnRaTransport(newurl, pool=self.connections)
-
-    def local_abspath(self, relpath):
-        """See Transport.local_abspath()."""
-        absurl = self.abspath(relpath)
-        if self.base.startswith("file:///"):
-            return urlutils.local_path_from_url(absurl)
-        raise NotLocalUrl(absurl)
-
-    def abspath(self, relpath):
-        """See Transport.abspath()."""
-        return urlutils.join(self.base, relpath)
-
-
-class MutteringRemoteAccess(object):
-
-    busy = property(lambda self: self.actual.busy)
-    url = property(lambda self: self.actual.url)
-
-    def __init__(self, actual):
-        self.actual = actual
-
-    def check_path(self, path, revnum):
-        mutter('svn check-path -r%d %s' % (revnum, path))
-        return self.actual.check_path(path, revnum)
-
-    def has_capability(self, cap):
-        mutter('svn has-capability %s' % (cap,))
-        return self.actual.has_capability(cap)
-
-    def get_uuid(self):
-        mutter('svn get-uuid')
-        return self.actual.get_uuid()
-
-    def get_repos_root(self):
-        mutter('svn get-repos-root')
-        return self.actual.get_repos_root()
-
-    def get_latest_revnum(self):
-        mutter('svn get-latest-revnum')
-        return self.actual.get_latest_revnum()
-
-    def get_log(self, callback, paths, from_revnum, to_revnum, *args, **kwargs):
-        mutter('svn log -r%d:%d %r' % (from_revnum, to_revnum, paths))
-        return self.actual.get_log(callback, paths, 
-                    from_revnum, to_revnum, *args, **kwargs)
-
-    def change_rev_prop(self, revnum, name, value):
-        mutter('svn change-revprop -r%d %s=%s' % (revnum, name, value))
-        return self.actual.change_rev_prop(revnum, name, value)
-
-    def get_dir(self, path, revnum=-1, fields=0):
-        mutter('svn get-dir -r%d %s' % (revnum, path))
-        return self.actual.get_dir(path, revnum, fields)
-
-    def get_file(self, path, revnum):
-        mutter('svn get-file -r%d %s' % (revnum, path))
-        return self.actual.get_file(path, revnum)
-
-    def revprop_list(self, revnum):
-        mutter('svn revprop-list -r%d' % (revnum,))
-        return self.actual.revprop_list(revnum)
-
-    def get_locations(self, path, peg_revnum, revnums):
-        mutter('svn get_locations -r%d %s (%r)' % (peg_revnum, path, revnums))
-        return self.actual.get_locations(path, peg_revnum, revnums)
-
-    def do_update(self, revnum, path, start_empty, editor):
-        mutter("svn update -r%d %s" % (revnum, path))
-        return self.actual.do_update(revnum, path, start_empty, editor)
-
-    def do_switch(self, revnum, path, start_empty, to_url, editor):
-        mutter("svn switch -r%d %s -> %s" % (revnum, path, to_url))
-        return self.actual.do_switch(revnum, path, start_empty, to_url, editor)
-
-    def reparent(self, url):
-        mutter("svn reparent %s" % url)
-        return self.actual.reparent(url)
-
-    def get_commit_editor(self, *args, **kwargs):
-        mutter("svn commit")
-        return self.actual.get_commit_editor(*args, **kwargs)
-
-    def rev_proplist(self, revnum):
-        mutter("svn rev-proplist -r%d" % revnum)
-        return self.actual.rev_proplist(revnum)