19
19
from bzrlib.transport import Transport, register_transport
20
20
from bzrlib.errors import (TransportNotPossible, NoSuchFile,
21
NonRelativePath, TransportError, ConnectionError)
21
NonRelativePath, TransportError)
23
23
from cStringIO import StringIO
28
28
from bzrlib.branch import Branch
29
29
from bzrlib.trace import mutter
31
# velocitynet.com.au transparently proxies connections and thereby
32
# breaks keep-alive -- sucks!
34
mutter("get_url %s", url)
37
mutter("get_url %s" % url)
35
38
url_f = urllib2.urlopen(url)
74
77
"""Return the full url to the given relative path.
75
78
This can be supplied with a string or a list
77
assert isinstance(relpath, basestring)
78
80
if isinstance(relpath, basestring):
79
relpath_parts = relpath.split('/')
81
# TODO: Don't call this with an array - no magic interfaces
82
relpath_parts = relpath[:]
83
if len(relpath_parts) > 1:
84
if relpath_parts[0] == '':
85
raise ValueError("path %r within branch %r seems to be absolute"
86
% (relpath, self._path))
87
if relpath_parts[-1] == '':
88
raise ValueError("path %r within branch %r seems to be a directory"
89
% (relpath, self._path))
90
82
basepath = self._path.split('/')
91
83
if len(basepath) > 0 and basepath[-1] == '':
92
84
basepath = basepath[:-1]
93
for p in relpath_parts:
95
if len(basepath) == 0:
96
89
# In most filesystems, a request for the parent
97
90
# of root, just returns root.
100
elif p == '.' or p == '':
103
97
basepath.append(p)
104
99
# Possibly, we could use urlparse.urljoin() here, but
105
100
# I'm concerned about when it chooses to strip the last
106
101
# portion of the path, and when it doesn't.
108
103
return urlparse.urlunparse((self._proto,
109
104
self._host, path, '', '', ''))
106
def relpath(self, abspath):
107
if not abspath.startswith(self.base):
108
raise NonRelativePath('path %r is not under base URL %r'
109
% (abspath, self.base))
111
return abspath[pl:].lstrip('/')
111
113
def has(self, relpath):
112
114
"""Does the target location exist?
144
146
return get_url(self.abspath(relpath))
145
except urllib2.HTTPError, e:
147
raise NoSuchFile(msg = "Error retrieving %s: %s"
148
% (self.abspath(relpath), str(e)),
151
except (BzrError, IOError), e:
152
raise ConnectionError(msg = "Error retrieving %s: %s"
153
% (self.abspath(relpath), str(e)),
147
except (BzrError, urllib2.URLError, IOError), e:
148
raise NoSuchFile(msg = "Error retrieving %s"
149
% self.abspath(relpath),
152
def get_partial(self, relpath, start, length=None):
153
"""Get just part of a file.
155
:param relpath: Path to the file, relative to base
156
:param start: The starting position to read from
157
:param length: The length to read. A length of None indicates
158
read to the end of the file.
159
:return: A file-like object containing at least the specified bytes.
160
Some implementations may return objects which can be read
161
past this length, but this is not guaranteed.
163
# TODO: You can make specialized http requests for just
164
# a portion of the file. Figure out how to do that.
165
# For now, urllib2 returns files that cannot seek() so
166
# we just read bytes off the beginning, until we
167
# get to the point that we care about.
168
f = self.get(relpath)
169
# TODO: read in smaller chunks, in case things are
170
# buffered internally.
156
174
def put(self, relpath, f):
157
175
"""Copy the file-like or string object into the location.
228
246
:return: A lock object, which should be passed to Transport.unlock()
230
248
raise TransportNotPossible('http does not support lock_write()')
250
register_transport('http://', HttpTransport)
251
register_transport('https://', HttpTransport)