22
22
At the moment remote branches are only for HTTP and only for read
28
30
from cStringIO import StringIO
31
32
from errors import BzrError, BzrCheckError
32
from branch import Branch, BZR_BRANCH_FORMAT
33
from trace import mutter
33
from branch import Branch
35
35
# velocitynet.com.au transparently proxies connections and thereby
36
36
# breaks keep-alive -- sucks!
39
ENABLE_URLGRABBER = True
41
from bzrlib.errors import BzrError
43
class GetFailed(BzrError):
44
def __init__(self, url, status):
45
BzrError.__init__(self, "Get %s failed with status %s" % (url, status))
40
ENABLE_URLGRABBER = False
42
def get_url(url, compressed=False):
46
url_f = urllib2.urlopen(url)
48
return gzip.GzipFile(fileobj=StringIO(url_f.read()))
49
52
if ENABLE_URLGRABBER:
58
mutter("grab url %s" % url)
59
61
url_f = urlgrabber.urlopen(url, keepalive=1, close_connection=0)
60
if url_f.status != 200:
61
raise GetFailed(url, url_f.status)
65
65
return gzip.GzipFile(fileobj=StringIO(url_f.read()))
66
66
except urllib2.URLError, e:
67
67
raise BzrError("remote fetch failed: %r: %s" % (url, e))
69
def get_url(url, compressed=False):
73
mutter("get_url %s" % url)
74
url_f = urllib2.urlopen(url)
76
return gzip.GzipFile(fileobj=StringIO(url_f.read()))
82
def _find_remote_root(url):
83
"""Return the prefix URL that corresponds to the branch root."""
87
ff = get_url(url + '/.bzr/branch-format')
92
fmt = fmt.rstrip('\r\n')
93
if fmt != BZR_BRANCH_FORMAT.rstrip('\r\n'):
94
raise BzrError("sorry, branch format %r not supported at url %s"
98
except urllib2.URLError:
102
idx = url.rindex('/')
104
raise BzrError('no branch root found for URL %s' % orig_url)
110
70
class RemoteBranch(Branch):
111
def __init__(self, baseurl, find_root=True):
71
def __init__(self, baseurl):
112
72
"""Create new proxy for a remote branch."""
114
self.baseurl = _find_remote_root(baseurl)
116
self.baseurl = baseurl
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/')
124
b = getattr(self, 'baseurl', 'undefined')
125
return '%s(%r)' % (self.__class__.__name__, b)
73
self.baseurl = baseurl
129
76
def controlfile(self, filename, mode):
130
77
if mode not in ('rb', 'rt', 'r'):
131
78
raise BzrError("file mode %r not supported for remote branches" % mode)
132
79
return get_url(self.baseurl + '/.bzr/' + filename, False)
136
# no locking for remote branches yet
139
def lock_write(self):
140
from errors import LockError
141
raise LockError("write lock not supported for remote branch %s"
148
def relpath(self, path):
149
if not path.startswith(self.baseurl):
150
raise BzrError('path %r is not under base URL %r'
151
% (path, self.baseurl))
152
pl = len(self.baseurl)
153
return path[pl:].lstrip('/')
81
def _need_readlock(self):
82
# remote branch always safe for read
85
def _need_writelock(self):
86
raise BzrError("cannot get write lock on HTTP remote branch")
156
88
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)
89
from revision import Revision
90
revf = get_url(self.baseurl + '/.bzr/revision-store/' + revision_id,
92
r = Revision.read_xml(revf)
161
93
if r.revision_id != revision_id:
162
94
raise BzrCheckError('revision stored as {%s} actually contains {%s}'
163
95
% (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)
100
from revision import Revision
101
from branch import Branch
102
from inventory import Inventory
108
history = get_url('/.bzr/revision-history').readlines()
109
num_revs = len(history)
110
for i, rev_id in enumerate(history):
111
rev_id = rev_id.rstrip()
112
print 'read revision %d/%d' % (i, num_revs)
114
# python gzip needs a seekable file (!!) but the HTTP response
115
# isn't, so we need to buffer it
117
rev_f = get_url('/.bzr/revision-store/%s' % rev_id,
120
rev = Revision.read_xml(rev_f)
122
inv_id = rev.inventory_id
123
if inv_id not in got_invs:
124
print 'get inventory %s' % inv_id
125
inv_f = get_url('/.bzr/inventory-store/%s' % inv_id,
127
inv = Inventory.read_xml(inv_f)
128
print '%4d inventory entries' % len(inv)
130
for path, ie in inv.iter_entries():
134
if text_id in got_texts:
136
print ' fetch %s text {%s}' % (path, text_id)
137
text_f = get_url('/.bzr/text-store/%s' % text_id,
139
got_texts.add(text_id)
147
BASE_URL = 'http://bazaar-ng.org/bzr/bzr.dev/'
148
b = RemoteBranch(BASE_URL)
149
## print '\n'.join(b.revision_history())
150
from log import show_log
154
if __name__ == '__main__':