hgext/convert/transport.py
changeset 4757 6a16ef0d1c7c
child 4920 4db03fa58bd5
equal deleted inserted replaced
4756:8e9d3faec270 4757:6a16ef0d1c7c
       
     1 # -*- coding: utf-8 -*-
       
     2 
       
     3 # Copyright (C) 2007 Daniel Holth <dholth@fastmail.fm>
       
     4 # This is a stripped-down version of the original bzr-svn transport.py,
       
     5 # Copyright (C) 2006 Jelmer Vernooij <jelmer@samba.org>
       
     6 
       
     7 # This program is free software; you can redistribute it and/or modify
       
     8 # it under the terms of the GNU General Public License as published by
       
     9 # the Free Software Foundation; either version 2 of the License, or
       
    10 # (at your option) any later version.
       
    11 
       
    12 # This program is distributed in the hope that it will be useful,
       
    13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    15 # GNU General Public License for more details.
       
    16 
       
    17 # You should have received a copy of the GNU General Public License
       
    18 # along with this program; if not, write to the Free Software
       
    19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    20 
       
    21 from cStringIO import StringIO
       
    22 import os
       
    23 from tempfile import mktemp
       
    24 
       
    25 from svn.core import SubversionException, Pool
       
    26 import svn.ra
       
    27 import svn.core
       
    28 
       
    29 # Some older versions of the Python bindings need to be 
       
    30 # explicitly initialized. But what we want to do probably
       
    31 # won't work worth a darn against those libraries anyway!
       
    32 svn.ra.initialize()
       
    33 
       
    34 svn_config = svn.core.svn_config_get_config(None)
       
    35 
       
    36 
       
    37 def _create_auth_baton(pool):
       
    38     """Create a Subversion authentication baton. """
       
    39     import svn.client
       
    40     # Give the client context baton a suite of authentication
       
    41     # providers.h
       
    42     providers = [
       
    43         svn.client.get_simple_provider(pool),
       
    44         svn.client.get_username_provider(pool),
       
    45         svn.client.get_ssl_client_cert_file_provider(pool),
       
    46         svn.client.get_ssl_client_cert_pw_file_provider(pool),
       
    47         svn.client.get_ssl_server_trust_file_provider(pool),
       
    48         ]
       
    49     return svn.core.svn_auth_open(providers, pool)
       
    50 
       
    51 
       
    52 #    # The SVN libraries don't like trailing slashes...
       
    53 #    return url.rstrip('/')
       
    54 
       
    55 
       
    56 class SvnRaCallbacks(svn.ra.callbacks2_t):
       
    57     """Remote access callbacks implementation for bzr-svn."""
       
    58     def __init__(self, pool):
       
    59         svn.ra.callbacks2_t.__init__(self)
       
    60         self.auth_baton = _create_auth_baton(pool)
       
    61         self.pool = pool
       
    62     
       
    63     def open_tmp_file(self, pool):
       
    64         return mktemp(prefix='tailor-svn')
       
    65 
       
    66 class NotBranchError(SubversionException):
       
    67     pass
       
    68 
       
    69 class SvnRaTransport(object):
       
    70     """
       
    71     Open an ra connection to a Subversion repository.
       
    72     """
       
    73     def __init__(self, url="", ra=None):
       
    74         self.pool = Pool()
       
    75         self.svn_url = url
       
    76 
       
    77         # Only Subversion 1.4 has reparent()
       
    78         if ra is None or not hasattr(svn.ra, 'reparent'):
       
    79             self.callbacks = SvnRaCallbacks(self.pool)
       
    80             try:
       
    81                 ver = svn.ra.version()
       
    82                 try: # Older SVN bindings
       
    83                     self.ra = svn.ra.open2(self.svn_url.encode('utf8'), self.callbacks, None, svn_config, None)
       
    84                 except TypeError, e:
       
    85                     self.ra = svn.ra.open2(self.svn_url.encode('utf8'), self.callbacks, svn_config, None)
       
    86             except SubversionException, (_, num):
       
    87                 if num == svn.core.SVN_ERR_RA_ILLEGAL_URL:
       
    88                     raise NotBranchError(url)
       
    89                 if num == svn.core.SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED:
       
    90                     raise NotBranchError(url)
       
    91                 if num == svn.core.SVN_ERR_BAD_URL:
       
    92                     raise NotBranchError(url)
       
    93                 raise
       
    94 
       
    95         else:
       
    96             self.ra = ra
       
    97             svn.ra.reparent(self.ra, self.svn_url.encode('utf8'))
       
    98 
       
    99     class Reporter:
       
   100         def __init__(self, (reporter, report_baton)):
       
   101             self._reporter = reporter
       
   102             self._baton = report_baton
       
   103 
       
   104         def set_path(self, path, revnum, start_empty, lock_token, pool=None):
       
   105             svn.ra.reporter2_invoke_set_path(self._reporter, self._baton,
       
   106                         path, revnum, start_empty, lock_token, pool)
       
   107 
       
   108         def delete_path(self, path, pool=None):
       
   109             svn.ra.reporter2_invoke_delete_path(self._reporter, self._baton,
       
   110                     path, pool)
       
   111 
       
   112         def link_path(self, path, url, revision, start_empty, lock_token,
       
   113                       pool=None):
       
   114             svn.ra.reporter2_invoke_link_path(self._reporter, self._baton,
       
   115                     path, url, revision, start_empty, lock_token,
       
   116                     pool)
       
   117 
       
   118         def finish_report(self, pool=None):
       
   119             svn.ra.reporter2_invoke_finish_report(self._reporter,
       
   120                     self._baton, pool)
       
   121 
       
   122         def abort_report(self, pool=None):
       
   123             svn.ra.reporter2_invoke_abort_report(self._reporter,
       
   124                     self._baton, pool)
       
   125 
       
   126     def do_update(self, revnum, path, *args, **kwargs):
       
   127         return self.Reporter(svn.ra.do_update(self.ra, revnum, path, *args, **kwargs))
       
   128 
       
   129     def clone(self, offset=None):
       
   130         """See Transport.clone()."""
       
   131         if offset is None:
       
   132             return self.__class__(self.base)
       
   133 
       
   134         return SvnRaTransport(urlutils.join(self.base, offset), ra=self.ra)