~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/http_transport.py

  • Committer: John Arbash Meinel
  • Date: 2005-07-11 21:24:27 UTC
  • mto: (1185.11.1)
  • mto: This revision was merged to the branch mainline in revision 1396.
  • Revision ID: john@arbash-meinel.com-20050711212426-1cd444606462f4ff
Adding http transport as a valid transport protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
"""\
 
3
An implementation of the Transport object for http access.
 
4
"""
 
5
 
 
6
from bzrlib.transport import Transport, protocol_handlers, TransportNotPossibleError
 
7
import os
 
8
from cStringIO import StringIO
 
9
import urllib2
 
10
 
 
11
from errors import BzrError, BzrCheckError
 
12
from branch import Branch, BZR_BRANCH_FORMAT
 
13
from trace import mutter
 
14
 
 
15
# velocitynet.com.au transparently proxies connections and thereby
 
16
# breaks keep-alive -- sucks!
 
17
 
 
18
 
 
19
ENABLE_URLGRABBER = True
 
20
 
 
21
 
 
22
if ENABLE_URLGRABBER:
 
23
    import urlgrabber
 
24
    import urlgrabber.keepalive
 
25
    urlgrabber.keepalive.DEBUG = 0
 
26
    def get_url(path, compressed=False):
 
27
        try:
 
28
            url = path
 
29
            if compressed:
 
30
                url += '.gz'
 
31
            mutter("grab url %s" % url)
 
32
            url_f = urlgrabber.urlopen(url, keepalive=1, close_connection=0)
 
33
            if not compressed:
 
34
                return url_f
 
35
            else:
 
36
                return gzip.GzipFile(fileobj=StringIO(url_f.read()))
 
37
        except urllib2.URLError, e:
 
38
            raise BzrError("remote fetch failed: %r: %s" % (url, e))
 
39
else:
 
40
    def get_url(url, compressed=False):
 
41
        import urllib2
 
42
        if compressed:
 
43
            url += '.gz'
 
44
        mutter("get_url %s" % url)
 
45
        url_f = urllib2.urlopen(url)
 
46
        if compressed:
 
47
            return gzip.GzipFile(fileobj=StringIO(url_f.read()))
 
48
        else:
 
49
            return url_f
 
50
 
 
51
def _find_remote_root(url):
 
52
    """Return the prefix URL that corresponds to the branch root."""
 
53
    orig_url = url
 
54
    while True:
 
55
        try:
 
56
            ff = get_url(url + '/.bzr/branch-format')
 
57
 
 
58
            fmt = ff.read()
 
59
            ff.close()
 
60
 
 
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"
 
64
                               % (fmt, url))
 
65
            
 
66
            return url
 
67
        except urllib2.URLError:
 
68
            pass
 
69
 
 
70
        try:
 
71
            idx = url.rindex('/')
 
72
        except ValueError:
 
73
            raise BzrError('no branch root found for URL %s' % orig_url)
 
74
 
 
75
        url = url[:idx]        
 
76
        
 
77
 
 
78
class HttpTransport(Transport):
 
79
    """This is the transport agent for local filesystem access."""
 
80
 
 
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
 
88
 
 
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.
 
93
        """
 
94
        if offset is None:
 
95
            return HttpTransport(self.base)
 
96
        else:
 
97
            return HttpTransport(self.abspath(offset))
 
98
 
 
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
 
102
        """
 
103
        if isinstance(relpath, basestring):
 
104
            relpath = [relpath]
 
105
        return '/'.join(self.base, *relpath)
 
106
 
 
107
    def has(self, relpath):
 
108
        try:
 
109
            f = get_url(self.abspath(relpath))
 
110
            return True
 
111
        except urllib2.URLError:
 
112
            return False
 
113
 
 
114
    def get(self, relpath, decode=False):
 
115
        """Get the file at the given relative path.
 
116
 
 
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
 
120
        """
 
121
        if decode:
 
122
            import codecs
 
123
            return codecs.get_reader('utf-8')(get_url(self.abspath(relpath)))
 
124
        else:
 
125
            return get_url(self.abspath(relpath))
 
126
 
 
127
    def put(self, relpath, f, encode=False):
 
128
        """Copy the file-like or string object into the location.
 
129
 
 
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.
 
133
        """
 
134
        raise TransportNotPossibleError('http does not support put()')
 
135
 
 
136
    def mkdir(self, relpath):
 
137
        """Create a directory at the given path."""
 
138
        raise TransportNotPossibleError('http does not support mkdir()')
 
139
 
 
140
    def append(self, relpath, f):
 
141
        """Append the text in the file-like object into the final
 
142
        location.
 
143
        """
 
144
        raise TransportNotPossibleError('http does not support append()')
 
145
 
 
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()')
 
149
 
 
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()')
 
153
 
 
154
    def delete(self, relpath):
 
155
        """Delete the item at relpath"""
 
156
        raise TransportNotPossibleError('http does not support delete()')
 
157
 
 
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.
 
161
 
 
162
        :rtype: AsyncFile
 
163
        """
 
164
        raise NotImplementedError
 
165
 
 
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.
 
170
        """
 
171
        raise TransportNotPossibleError('http does not support list_dir()')
 
172
 
 
173
    def stat(self, relpath):
 
174
        """Return the stat information for a file.
 
175
        """
 
176
        raise TransportNotPossibleError('http does not support stat()')
 
177
 
 
178
# If nothing else matches, try the LocalTransport
 
179
protocol_handlers['http://'] = HttpTransport
 
180
protocol_handlers['https://'] = HttpTransport
 
181