28
26
from cStringIO import StringIO
31
from errors import BzrError, BzrCheckError
32
from branch import Branch, BZR_BRANCH_FORMAT
33
from trace import mutter
31
from bzrlib.errors import BzrError, BzrCheckError
32
from bzrlib.branch import Branch, LocalBranch, BZR_BRANCH_FORMAT_5
33
from bzrlib.trace import mutter
34
from bzrlib.weavestore import WeaveStore
35
from bzrlib.xml5 import serializer_v5
35
38
# velocitynet.com.au transparently proxies connections and thereby
36
39
# breaks keep-alive -- sucks!
39
ENABLE_URLGRABBER = True
42
ENABLE_URLGRABBER = False
41
from bzrlib.errors import BzrError
44
from bzrlib.errors import BzrError, NoSuchRevision
43
46
class GetFailed(BzrError):
44
47
def __init__(self, url, status):
47
50
self.status = status
49
52
if ENABLE_URLGRABBER:
51
import urlgrabber.keepalive
52
urlgrabber.keepalive.DEBUG = 0
53
import util.urlgrabber
54
import util.urlgrabber.keepalive
55
util.urlgrabber.keepalive.DEBUG = 0
53
56
def get_url(path, compressed=False):
58
61
mutter("grab url %s" % url)
59
url_f = urlgrabber.urlopen(url, keepalive=1, close_connection=0)
62
url_f = util.urlgrabber.urlopen(url, keepalive=1, close_connection=0)
60
63
if url_f.status != 200:
61
64
raise GetFailed(url, url_f.status)
82
84
def _find_remote_root(url):
83
85
"""Return the prefix URL that corresponds to the branch root."""
87
ff = get_url(url + '/.bzr/branch-format')
89
fmt_url = url + '/.bzr/branch-format'
92
fmt = fmt.rstrip('\r\n')
93
if fmt != BZR_BRANCH_FORMAT.rstrip('\r\n'):
94
if fmt != BZR_BRANCH_FORMAT_5:
94
95
raise BzrError("sorry, branch format %r not supported at url %s"
98
99
except urllib2.URLError:
102
idx = url.rindex('/')
104
raise BzrError('no branch root found for URL %s' % orig_url)
110
class RemoteBranch(Branch):
102
scheme, host, path = list(urlparse.urlparse(url))[:3]
103
# discard params, query, fragment
105
# strip off one component of the path component
106
idx = path.rfind('/')
107
if idx == -1 or path == '/':
108
raise BzrError('no branch root found for URL %s'
109
' or enclosing directories'
112
url = urlparse.urlunparse((scheme, host, path, '', '', ''))
116
class RemoteBranch(LocalBranch):
111
118
def __init__(self, baseurl, find_root=True):
112
119
"""Create new proxy for a remote branch."""
120
# circular import protection
121
from bzrlib.store import RemoteStore
114
self.baseurl = _find_remote_root(baseurl)
123
self.base = _find_remote_root(baseurl)
116
self.baseurl = baseurl
126
self._check_format(False)
127
# is guaranteed to be a v5 store
119
self.inventory_store = RemoteStore(baseurl + '/.bzr/inventory-store/')
120
self.text_store = RemoteStore(baseurl + '/.bzr/text-store/')
121
self.revision_store = RemoteStore(baseurl + '/.bzr/revision-store/')
129
cfn = self.controlfilename
130
assert self._branch_format == 5
131
self.control_weaves = WeaveStore(cfn([]), get_url)
132
self.weave_store = WeaveStore(cfn('weaves'), get_url)
133
self.revision_store = RemoteStore(cfn('revision-store'))
123
135
def __str__(self):
124
136
b = getattr(self, 'baseurl', 'undefined')
127
139
__repr__ = __str__
141
def setup_caching(self, cache_root):
142
"""Set up cached stores located under cache_root"""
143
from bzrlib.meta_store import CachedStore
144
for store_name in ('revision_store',):
145
if not isinstance(getattr(self, store_name), CachedStore):
146
cache_path = os.path.join(cache_root, store_name)
148
new_store = CachedStore(getattr(self, store_name), cache_path)
149
setattr(self, store_name, new_store)
129
151
def controlfile(self, filename, mode):
130
152
if mode not in ('rb', 'rt', 'r'):
131
153
raise BzrError("file mode %r not supported for remote branches" % mode)
132
return get_url(self.baseurl + '/.bzr/' + filename, False)
154
return get_url(self.base + '/.bzr/' + filename, False)
135
157
def lock_read(self):
139
161
def lock_write(self):
140
162
from errors import LockError
141
163
raise LockError("write lock not supported for remote branch %s"
144
166
def unlock(self):
148
170
def relpath(self, path):
149
if not path.startswith(self.baseurl):
171
if not path.startswith(self.base):
150
172
raise BzrError('path %r is not under base URL %r'
151
% (path, self.baseurl))
152
pl = len(self.baseurl)
153
175
return path[pl:].lstrip('/')
156
178
def get_revision(self, revision_id):
157
from bzrlib.revision import Revision
158
from bzrlib.xml import unpack_xml
159
revf = self.revision_store[revision_id]
160
r = unpack_xml(Revision, revf)
180
revf = self.revision_store[revision_id]
182
raise NoSuchRevision(self, revision_id)
183
r = serializer_v5.read_revision(revf)
161
184
if r.revision_id != revision_id:
162
185
raise BzrCheckError('revision stored as {%s} actually contains {%s}'
163
186
% (revision_id, r.revision_id))
167
class RemoteStore(object):
168
def __init__(self, baseurl):
169
self._baseurl = baseurl
172
def _path(self, name):
174
raise ValueError('invalid store id', name)
175
return self._baseurl + '/' + name
177
def __getitem__(self, fileid):
178
p = self._path(fileid)
180
return get_url(p, compressed=True)
182
raise KeyError(fileid)