3
An implementation of the Transport object for http access.
6
from bzrlib.transport import Transport, protocol_handlers, TransportNotPossibleError
8
from cStringIO import StringIO
11
from errors import BzrError, BzrCheckError
12
from branch import Branch, BZR_BRANCH_FORMAT
13
from trace import mutter
15
# velocitynet.com.au transparently proxies connections and thereby
16
# breaks keep-alive -- sucks!
19
ENABLE_URLGRABBER = True
24
import urlgrabber.keepalive
25
urlgrabber.keepalive.DEBUG = 0
26
def get_url(path, compressed=False):
31
mutter("grab url %s" % url)
32
url_f = urlgrabber.urlopen(url, keepalive=1, close_connection=0)
36
return gzip.GzipFile(fileobj=StringIO(url_f.read()))
37
except urllib2.URLError, e:
38
raise BzrError("remote fetch failed: %r: %s" % (url, e))
40
def get_url(url, compressed=False):
44
mutter("get_url %s" % url)
45
url_f = urllib2.urlopen(url)
47
return gzip.GzipFile(fileobj=StringIO(url_f.read()))
51
def _find_remote_root(url):
52
"""Return the prefix URL that corresponds to the branch root."""
56
ff = get_url(url + '/.bzr/branch-format')
61
fmt = fmt.rstrip('\r\n')
62
if fmt != BZR_BRANCH_FORMAT.rstrip('\r\n'):
63
raise BzrError("sorry, branch format %r not supported at url %s"
67
except urllib2.URLError:
73
raise BzrError('no branch root found for URL %s' % orig_url)
78
class HttpTransport(Transport):
79
"""This is the transport agent for local filesystem access."""
81
def __init__(self, base):
82
"""Set the base path where files will be stored."""
83
assert base.startswith('http://') or base.startswith('https://')
84
super(HttpTransport, self).__init__(base)
85
# In the future we might actually connect to the remote host
86
# rather than using get_url
87
# self._connection = None
89
def clone(self, offset=None):
90
"""Return a new HttpTransport with root at self.base + offset
91
For now HttpTransport does not actually connect, so just return
92
a new HttpTransport object.
95
return HttpTransport(self.base)
97
return HttpTransport(self.abspath(offset))
99
def abspath(self, relpath):
100
"""Return the full url to the given relative path.
101
This can be supplied with a string or a list
103
if isinstance(relpath, basestring):
105
return '/'.join(self.base, *relpath)
107
def has(self, relpath):
109
f = get_url(self.abspath(relpath))
111
except urllib2.URLError:
114
def get(self, relpath, decode=False):
115
"""Get the file at the given relative path.
117
:param relpath: The relative path to the file
118
:param decode: If True, assume the file is utf-8 encoded and
119
decode it into Unicode
123
return codecs.get_reader('utf-8')(get_url(self.abspath(relpath)))
125
return get_url(self.abspath(relpath))
127
def put(self, relpath, f, encode=False):
128
"""Copy the file-like or string object into the location.
130
:param relpath: Location to put the contents, relative to base.
131
:param f: File-like or string object.
132
:param encode: If True, translate the contents into utf-8 encoded text.
134
raise TransportNotPossibleError('http does not support put()')
136
def mkdir(self, relpath):
137
"""Create a directory at the given path."""
138
raise TransportNotPossibleError('http does not support mkdir()')
140
def append(self, relpath, f):
141
"""Append the text in the file-like object into the final
144
raise TransportNotPossibleError('http does not support append()')
146
def copy(self, rel_from, rel_to):
147
"""Copy the item at rel_from to the location at rel_to"""
148
raise TransportNotPossibleError('http does not support copy()')
150
def move(self, rel_from, rel_to):
151
"""Move the item at rel_from to the location at rel_to"""
152
raise TransportNotPossibleError('http does not support move()')
154
def delete(self, relpath):
155
"""Delete the item at relpath"""
156
raise TransportNotPossibleError('http does not support delete()')
158
def async_get(self, relpath):
159
"""Make a request for an file at the given location, but
160
don't worry about actually getting it yet.
164
raise NotImplementedError
166
def list_dir(self, relpath):
167
"""Return a list of all files at the given location.
168
WARNING: many transports do not support this, so trying avoid using
169
it if at all possible.
171
raise TransportNotPossibleError('http does not support list_dir()')
173
def stat(self, relpath):
174
"""Return the stat information for a file.
176
raise TransportNotPossibleError('http does not support stat()')
178
# If nothing else matches, try the LocalTransport
179
protocol_handlers['http://'] = HttpTransport
180
protocol_handlers['https://'] = HttpTransport