annotate mercurial/byterange.py @ 14365:a8e3931e3fb5

revlog: linearize created changegroups in generaldelta revlogs This greatly improves the speed of the bundling process, and often reduces the bundle size considerably. (Although if the repository is already ordered, this has little effect on both time and bundle size.) For non-generaldelta clients, the reduced bundle size translates to a reduced repository size, similar to shrinking the revlogs (which uses the exact same algorithm). For generaldelta clients the difference is minor. When the new bundle format comes, reordering will not be necessary since we can then store the deltaparent relationsships directly. The eventual default behavior for clients and servers is presented in the table below, where "new" implies support for GD as well as the new bundle format: old client new client old server old bundle, no reorder old bundle, no reorder new server, non-GD old bundle, no reorder[1] old bundle, no reorder[2] new server, GD old bundle, reorder[3] new bundle, no reorder[4] [1] reordering is expensive on the server in this case, skip it [2] client can choose to do its own redelta here [3] reordering is needed because otherwise the pull does a lot of extra work on the server [4] reordering isn't needed because client can get deltabase in bundle format Currently, the default is to reorder on GD-servers, and not otherwise. A new setting, bundle.reorder, has been added to override the default reordering behavior. It can be set to either 'auto' (the default), or any true or false value as a standard boolean setting, to either force the reordering on or off regardless of generaldelta. Some timing data from a relatively branch test repository follows. All bundling is done with --all --type none options. Non-generaldelta, non-shrunk repo: ----------------------------------- Size: 276M Without reorder (default): Bundle time: 14.4 seconds Bundle size: 939M With reorder: Bundle time: 1 minute, 29.3 seconds Bundle size: 381M Generaldelta, non-shrunk repo: ----------------------------------- Size: 87M Without reorder: Bundle time: 2 minutes, 1.4 seconds Bundle size: 939M With reorder (default): Bundle time: 25.5 seconds Bundle size: 381M
author Sune Foldager <cryo@cyanite.org>
date Wed, 18 May 2011 23:26:26 +0200
parents 13a1b2fb7ef2
children a7d5816087a9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
1 # This library is free software; you can redistribute it and/or
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
2 # modify it under the terms of the GNU Lesser General Public
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
3 # License as published by the Free Software Foundation; either
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
4 # version 2.1 of the License, or (at your option) any later version.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
5 #
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
6 # This library is distributed in the hope that it will be useful,
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
9 # Lesser General Public License for more details.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
10 #
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
11 # You should have received a copy of the GNU Lesser General Public
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
12 # License along with this library; if not, write to the
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
13 # Free Software Foundation, Inc.,
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
14 # 59 Temple Place, Suite 330,
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
15 # Boston, MA 02111-1307 USA
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
16
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
17 # This file is part of urlgrabber, a high-level cross-protocol url-grabber
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
18 # Copyright 2002-2004 Michael D. Stenner, Ryan Tomayko
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
19
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
20 # $Id: byterange.py,v 1.9 2005/02/14 21:55:07 mstenner Exp $
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
21
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
22 import os
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
23 import stat
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
24 import urllib
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
25 import urllib2
8378
59acf64995d2 byterange: fix import error
Martin Geisler <mg@lazybytes.net>
parents: 8366
diff changeset
26 import email.Utils
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
27
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
28 class RangeError(IOError):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
29 """Error raised when an unsatisfiable range is requested."""
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
30 pass
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
31
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
32 class HTTPRangeHandler(urllib2.BaseHandler):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
33 """Handler that enables HTTP Range headers.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
34
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
35 This was extremely simple. The Range header is a HTTP feature to
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
36 begin with so all this class does is tell urllib2 that the
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
37 "206 Partial Content" reponse from the HTTP server is what we
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
38 expected.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
39
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
40 Example:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
41 import urllib2
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
42 import byterange
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
43
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
44 range_handler = range.HTTPRangeHandler()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
45 opener = urllib2.build_opener(range_handler)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
46
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
47 # install it
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
48 urllib2.install_opener(opener)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
49
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
50 # create Request and set Range header
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
51 req = urllib2.Request('http://www.python.org/')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
52 req.header['Range'] = 'bytes=30-50'
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
53 f = urllib2.urlopen(req)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
54 """
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
55
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
56 def http_error_206(self, req, fp, code, msg, hdrs):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
57 # 206 Partial Content Response
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
58 r = urllib.addinfourl(fp, hdrs, req.get_full_url())
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
59 r.code = code
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
60 r.msg = msg
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
61 return r
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
62
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
63 def http_error_416(self, req, fp, code, msg, hdrs):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
64 # HTTP's Range Not Satisfiable error
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
65 raise RangeError('Requested Range Not Satisfiable')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
66
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
67 class RangeableFileObject:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
68 """File object wrapper to enable raw range handling.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
69 This was implemented primarilary for handling range
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
70 specifications for file:// urls. This object effectively makes
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
71 a file object look like it consists only of a range of bytes in
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
72 the stream.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
73
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
74 Examples:
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
75 # expose 10 bytes, starting at byte position 20, from
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
76 # /etc/aliases.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
77 >>> fo = RangeableFileObject(file('/etc/passwd', 'r'), (20,30))
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
78 # seek seeks within the range (to position 23 in this case)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
79 >>> fo.seek(3)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
80 # tell tells where your at _within the range_ (position 3 in
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
81 # this case)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
82 >>> fo.tell()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
83 # read EOFs if an attempt is made to read past the last
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
84 # byte in the range. the following will return only 7 bytes.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
85 >>> fo.read(30)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
86 """
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
87
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
88 def __init__(self, fo, rangetup):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
89 """Create a RangeableFileObject.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
90 fo -- a file like object. only the read() method need be
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
91 supported but supporting an optimized seek() is
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
92 preferable.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
93 rangetup -- a (firstbyte,lastbyte) tuple specifying the range
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
94 to work over.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
95 The file object provided is assumed to be at byte offset 0.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
96 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
97 self.fo = fo
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
98 (self.firstbyte, self.lastbyte) = range_tuple_normalize(rangetup)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
99 self.realpos = 0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
100 self._do_seek(self.firstbyte)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
101
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
102 def __getattr__(self, name):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
103 """This effectively allows us to wrap at the instance level.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
104 Any attribute not found in _this_ object will be searched for
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
105 in self.fo. This includes methods."""
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
106 if hasattr(self.fo, name):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
107 return getattr(self.fo, name)
7008
8fee8ff13d37 use Exception(args)-style raising consistently (py3k compatibility)
Peter Ruibal <peter.ruibal@intel.com>
parents: 5930
diff changeset
108 raise AttributeError(name)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
109
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
110 def tell(self):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
111 """Return the position within the range.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
112 This is different from fo.seek in that position 0 is the
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
113 first byte position of the range tuple. For example, if
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
114 this object was created with a range tuple of (500,899),
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
115 tell() will return 0 when at byte position 500 of the file.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
116 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
117 return (self.realpos - self.firstbyte)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
118
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
119 def seek(self, offset, whence=0):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
120 """Seek within the byte range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
121 Positioning is identical to that described under tell().
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
122 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
123 assert whence in (0, 1, 2)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
124 if whence == 0: # absolute seek
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
125 realoffset = self.firstbyte + offset
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
126 elif whence == 1: # relative seek
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
127 realoffset = self.realpos + offset
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
128 elif whence == 2: # absolute from end of file
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
129 # XXX: are we raising the right Error here?
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
130 raise IOError('seek from end of file not supported.')
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
131
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
132 # do not allow seek past lastbyte in range
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
133 if self.lastbyte and (realoffset >= self.lastbyte):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
134 realoffset = self.lastbyte
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
135
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
136 self._do_seek(realoffset - self.realpos)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
137
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
138 def read(self, size=-1):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
139 """Read within the range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
140 This method will limit the size read based on the range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
141 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
142 size = self._calc_read_size(size)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
143 rslt = self.fo.read(size)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
144 self.realpos += len(rslt)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
145 return rslt
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
146
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
147 def readline(self, size=-1):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
148 """Read lines within the range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
149 This method will limit the size read based on the range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
150 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
151 size = self._calc_read_size(size)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
152 rslt = self.fo.readline(size)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
153 self.realpos += len(rslt)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
154 return rslt
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
155
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
156 def _calc_read_size(self, size):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
157 """Handles calculating the amount of data to read based on
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
158 the range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
159 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
160 if self.lastbyte:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
161 if size > -1:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
162 if ((self.realpos + size) >= self.lastbyte):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
163 size = (self.lastbyte - self.realpos)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
164 else:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
165 size = (self.lastbyte - self.realpos)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
166 return size
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
167
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
168 def _do_seek(self, offset):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
169 """Seek based on whether wrapped object supports seek().
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
170 offset is relative to the current position (self.realpos).
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
171 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
172 assert offset >= 0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
173 if not hasattr(self.fo, 'seek'):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
174 self._poor_mans_seek(offset)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
175 else:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
176 self.fo.seek(self.realpos + offset)
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
177 self.realpos += offset
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
178
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
179 def _poor_mans_seek(self, offset):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
180 """Seek by calling the wrapped file objects read() method.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
181 This is used for file like objects that do not have native
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
182 seek support. The wrapped objects read() method is called
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
183 to manually seek to the desired position.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
184 offset -- read this number of bytes from the wrapped
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
185 file object.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
186 raise RangeError if we encounter EOF before reaching the
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
187 specified offset.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
188 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
189 pos = 0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
190 bufsize = 1024
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
191 while pos < offset:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
192 if (pos + bufsize) > offset:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
193 bufsize = offset - pos
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
194 buf = self.fo.read(bufsize)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
195 if len(buf) != bufsize:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
196 raise RangeError('Requested Range Not Satisfiable')
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
197 pos += bufsize
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
198
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
199 class FileRangeHandler(urllib2.FileHandler):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
200 """FileHandler subclass that adds Range support.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
201 This class handles Range headers exactly like an HTTP
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
202 server would.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
203 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
204 def open_local_file(self, req):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
205 import mimetypes
9034
8429062de8d3 compat: use email in favor of mimetools
Alejandro Santos <alejolp@alejolp.com>
parents: 8378
diff changeset
206 import email
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
207 host = req.get_host()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
208 file = req.get_selector()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
209 localfile = urllib.url2pathname(file)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
210 stats = os.stat(localfile)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
211 size = stats[stat.ST_SIZE]
8378
59acf64995d2 byterange: fix import error
Martin Geisler <mg@lazybytes.net>
parents: 8366
diff changeset
212 modified = email.Utils.formatdate(stats[stat.ST_MTIME])
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
213 mtype = mimetypes.guess_type(file)[0]
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
214 if host:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
215 host, port = urllib.splitport(host)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
216 if port or socket.gethostbyname(host) not in self.get_names():
667
31a9aa890016 A number of minor fixes to problems that pychecker found.
mark.williamson@cl.cam.ac.uk
parents: 575
diff changeset
217 raise urllib2.URLError('file not on local host')
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
218 fo = open(localfile,'rb')
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
219 brange = req.headers.get('Range', None)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
220 brange = range_header_to_tuple(brange)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
221 assert brange != ()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
222 if brange:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
223 (fb, lb) = brange
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
224 if lb == '':
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
225 lb = size
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
226 if fb < 0 or fb > size or lb > size:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
227 raise RangeError('Requested Range Not Satisfiable')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
228 size = (lb - fb)
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
229 fo = RangeableFileObject(fo, (fb, lb))
9034
8429062de8d3 compat: use email in favor of mimetools
Alejandro Santos <alejolp@alejolp.com>
parents: 8378
diff changeset
230 headers = email.message_from_string(
5930
c301f15c965a send conservatively capitalized HTTP headers
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 3673
diff changeset
231 'Content-Type: %s\nContent-Length: %d\nLast-Modified: %s\n' %
9034
8429062de8d3 compat: use email in favor of mimetools
Alejandro Santos <alejolp@alejolp.com>
parents: 8378
diff changeset
232 (mtype or 'text/plain', size, modified))
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
233 return urllib.addinfourl(fo, headers, 'file:'+file)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
234
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
235
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
236 # FTP Range Support
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
237 # Unfortunately, a large amount of base FTP code had to be copied
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
238 # from urllib and urllib2 in order to insert the FTP REST command.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
239 # Code modifications for range support have been commented as
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
240 # follows:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
241 # -- range support modifications start/end here
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
242
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
243 from urllib import splitport, splituser, splitpasswd, splitattr, \
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
244 unquote, addclosehook, addinfourl
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
245 import ftplib
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
246 import socket
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
247 import sys
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
248 import mimetypes
9034
8429062de8d3 compat: use email in favor of mimetools
Alejandro Santos <alejolp@alejolp.com>
parents: 8378
diff changeset
249 import email
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
250
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
251 class FTPRangeHandler(urllib2.FTPHandler):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
252 def ftp_open(self, req):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
253 host = req.get_host()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
254 if not host:
7008
8fee8ff13d37 use Exception(args)-style raising consistently (py3k compatibility)
Peter Ruibal <peter.ruibal@intel.com>
parents: 5930
diff changeset
255 raise IOError('ftp error', 'no host given')
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
256 host, port = splitport(host)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
257 if port is None:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
258 port = ftplib.FTP_PORT
9695
e4211db457c0 byterange: backport fix from upstream
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9034
diff changeset
259 else:
e4211db457c0 byterange: backport fix from upstream
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9034
diff changeset
260 port = int(port)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
261
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
262 # username/password handling
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
263 user, host = splituser(host)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
264 if user:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
265 user, passwd = splitpasswd(user)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
266 else:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
267 passwd = None
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
268 host = unquote(host)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
269 user = unquote(user or '')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
270 passwd = unquote(passwd or '')
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
271
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
272 try:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
273 host = socket.gethostbyname(host)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
274 except socket.error, msg:
667
31a9aa890016 A number of minor fixes to problems that pychecker found.
mark.williamson@cl.cam.ac.uk
parents: 575
diff changeset
275 raise urllib2.URLError(msg)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
276 path, attrs = splitattr(req.get_selector())
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
277 dirs = path.split('/')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
278 dirs = map(unquote, dirs)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
279 dirs, file = dirs[:-1], dirs[-1]
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
280 if dirs and not dirs[0]:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
281 dirs = dirs[1:]
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
282 try:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
283 fw = self.connect_ftp(user, passwd, host, port, dirs)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
284 type = file and 'I' or 'D'
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
285 for attr in attrs:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
286 attr, value = splitattr(attr)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
287 if attr.lower() == 'type' and \
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
288 value in ('a', 'A', 'i', 'I', 'd', 'D'):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
289 type = value.upper()
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
290
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
291 # -- range support modifications start here
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
292 rest = None
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
293 range_tup = range_header_to_tuple(req.headers.get('Range', None))
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
294 assert range_tup != ()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
295 if range_tup:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
296 (fb, lb) = range_tup
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
297 if fb > 0:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
298 rest = fb
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
299 # -- range support modifications end here
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
300
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
301 fp, retrlen = fw.retrfile(file, type, rest)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
302
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
303 # -- range support modifications start here
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
304 if range_tup:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
305 (fb, lb) = range_tup
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
306 if lb == '':
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
307 if retrlen is None or retrlen == 0:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 9695
diff changeset
308 raise RangeError('Requested Range Not Satisfiable due'
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 9695
diff changeset
309 ' to unobtainable file length.')
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
310 lb = retrlen
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
311 retrlen = lb - fb
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
312 if retrlen < 0:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
313 # beginning of range is larger than file
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
314 raise RangeError('Requested Range Not Satisfiable')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
315 else:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
316 retrlen = lb - fb
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
317 fp = RangeableFileObject(fp, (0, retrlen))
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
318 # -- range support modifications end here
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
319
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
320 headers = ""
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
321 mtype = mimetypes.guess_type(req.get_full_url())[0]
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
322 if mtype:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
323 headers += "Content-Type: %s\n" % mtype
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
324 if retrlen is not None and retrlen >= 0:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
325 headers += "Content-Length: %d\n" % retrlen
9034
8429062de8d3 compat: use email in favor of mimetools
Alejandro Santos <alejolp@alejolp.com>
parents: 8378
diff changeset
326 headers = email.message_from_string(headers)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
327 return addinfourl(fp, headers, req.get_full_url())
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
328 except ftplib.all_errors, msg:
7008
8fee8ff13d37 use Exception(args)-style raising consistently (py3k compatibility)
Peter Ruibal <peter.ruibal@intel.com>
parents: 5930
diff changeset
329 raise IOError('ftp error', msg), sys.exc_info()[2]
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
330
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
331 def connect_ftp(self, user, passwd, host, port, dirs):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
332 fw = ftpwrapper(user, passwd, host, port, dirs)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
333 return fw
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
334
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
335 class ftpwrapper(urllib.ftpwrapper):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
336 # range support note:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
337 # this ftpwrapper code is copied directly from
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
338 # urllib. The only enhancement is to add the rest
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
339 # argument and pass it on to ftp.ntransfercmd
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
340 def retrfile(self, file, type, rest=None):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
341 self.endtransfer()
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
342 if type in ('d', 'D'):
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
343 cmd = 'TYPE A'
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
344 isdir = 1
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
345 else:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
346 cmd = 'TYPE ' + type
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
347 isdir = 0
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
348 try:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
349 self.ftp.voidcmd(cmd)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
350 except ftplib.all_errors:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
351 self.init()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
352 self.ftp.voidcmd(cmd)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
353 conn = None
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
354 if file and not isdir:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
355 # Use nlst to see if the file exists at all
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
356 try:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
357 self.ftp.nlst(file)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
358 except ftplib.error_perm, reason:
7008
8fee8ff13d37 use Exception(args)-style raising consistently (py3k compatibility)
Peter Ruibal <peter.ruibal@intel.com>
parents: 5930
diff changeset
359 raise IOError('ftp error', reason), sys.exc_info()[2]
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
360 # Restore the transfer mode!
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
361 self.ftp.voidcmd(cmd)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
362 # Try to retrieve as a file
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
363 try:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
364 cmd = 'RETR ' + file
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
365 conn = self.ftp.ntransfercmd(cmd, rest)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
366 except ftplib.error_perm, reason:
674
6513ba7d858a Make consistent use of str.startswith() in conditionals.
chad.netzer@gmail.com
parents: 667
diff changeset
367 if str(reason).startswith('501'):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
368 # workaround for REST not supported error
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
369 fp, retrlen = self.retrfile(file, type)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
370 fp = RangeableFileObject(fp, (rest,''))
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
371 return (fp, retrlen)
674
6513ba7d858a Make consistent use of str.startswith() in conditionals.
chad.netzer@gmail.com
parents: 667
diff changeset
372 elif not str(reason).startswith('550'):
7008
8fee8ff13d37 use Exception(args)-style raising consistently (py3k compatibility)
Peter Ruibal <peter.ruibal@intel.com>
parents: 5930
diff changeset
373 raise IOError('ftp error', reason), sys.exc_info()[2]
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
374 if not conn:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
375 # Set transfer mode to ASCII!
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
376 self.ftp.voidcmd('TYPE A')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
377 # Try a directory listing
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
378 if file:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
379 cmd = 'LIST ' + file
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
380 else:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
381 cmd = 'LIST'
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
382 conn = self.ftp.ntransfercmd(cmd)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
383 self.busy = 1
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
384 # Pass back both a suitably decorated object and a retrieval length
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
385 return (addclosehook(conn[0].makefile('rb'),
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
386 self.endtransfer), conn[1])
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
387
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
388
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
389 ####################################################################
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
390 # Range Tuple Functions
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
391 # XXX: These range tuple functions might go better in a class.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
392
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
393 _rangere = None
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
394 def range_header_to_tuple(range_header):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
395 """Get a (firstbyte,lastbyte) tuple from a Range header value.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
396
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
397 Range headers have the form "bytes=<firstbyte>-<lastbyte>". This
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
398 function pulls the firstbyte and lastbyte values and returns
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
399 a (firstbyte,lastbyte) tuple. If lastbyte is not specified in
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
400 the header value, it is returned as an empty string in the
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
401 tuple.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
402
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
403 Return None if range_header is None
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
404 Return () if range_header does not conform to the range spec
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
405 pattern.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
406
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
407 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
408 global _rangere
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
409 if range_header is None:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
410 return None
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
411 if _rangere is None:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
412 import re
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
413 _rangere = re.compile(r'^bytes=(\d{1,})-(\d*)')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
414 match = _rangere.match(range_header)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
415 if match:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
416 tup = range_tuple_normalize(match.group(1, 2))
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
417 if tup and tup[1]:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
418 tup = (tup[0], tup[1]+1)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
419 return tup
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
420 return ()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
421
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
422 def range_tuple_to_header(range_tup):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
423 """Convert a range tuple to a Range header value.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
424 Return a string of the form "bytes=<firstbyte>-<lastbyte>" or None
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
425 if no range is needed.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
426 """
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
427 if range_tup is None:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
428 return None
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
429 range_tup = range_tuple_normalize(range_tup)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
430 if range_tup:
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
431 if range_tup[1]:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
432 range_tup = (range_tup[0], range_tup[1] - 1)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
433 return 'bytes=%s-%s' % range_tup
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
434
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
435 def range_tuple_normalize(range_tup):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
436 """Normalize a (first_byte,last_byte) range tuple.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
437 Return a tuple whose first element is guaranteed to be an int
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
438 and whose second element will be '' (meaning: the last byte) or
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
439 an int. Finally, return None if the normalized tuple == (0,'')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
440 as that is equivelant to retrieving the entire file.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
441 """
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
442 if range_tup is None:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
443 return None
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
444 # handle first byte
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
445 fb = range_tup[0]
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
446 if fb in (None, ''):
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
447 fb = 0
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
448 else:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
449 fb = int(fb)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
450 # handle last byte
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
451 try:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
452 lb = range_tup[1]
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
453 except IndexError:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
454 lb = ''
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
455 else:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
456 if lb is None:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
457 lb = ''
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
458 elif lb != '':
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
459 lb = int(lb)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
460 # check if range is over the entire file
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
461 if (fb, lb) == (0, ''):
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
462 return None
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
463 # check that the range is valid
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
464 if lb < fb:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
465 raise RangeError('Invalid byte range: %s-%s' % (fb, lb))
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
466 return (fb, lb)