##// END OF EJS Templates
changegroup.py: delay the loading of the bz2 and zlib modules
Alexis S. L. Carvalho -
r3762:b9d3e12d default
parent child Browse files
Show More
@@ -1,120 +1,120
1 """
1 """
2 changegroup.py - Mercurial changegroup manipulation functions
2 changegroup.py - Mercurial changegroup manipulation functions
3
3
4 Copyright 2006 Matt Mackall <mpm@selenic.com>
4 Copyright 2006 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
8 """
8 """
9 from i18n import gettext as _
9 from i18n import gettext as _
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "struct os bz2 zlib util tempfile")
11 demandload(globals(), "struct os bz2 zlib util tempfile")
12
12
13 def getchunk(source):
13 def getchunk(source):
14 """get a chunk from a changegroup"""
14 """get a chunk from a changegroup"""
15 d = source.read(4)
15 d = source.read(4)
16 if not d:
16 if not d:
17 return ""
17 return ""
18 l = struct.unpack(">l", d)[0]
18 l = struct.unpack(">l", d)[0]
19 if l <= 4:
19 if l <= 4:
20 return ""
20 return ""
21 d = source.read(l - 4)
21 d = source.read(l - 4)
22 if len(d) < l - 4:
22 if len(d) < l - 4:
23 raise util.Abort(_("premature EOF reading chunk"
23 raise util.Abort(_("premature EOF reading chunk"
24 " (got %d bytes, expected %d)")
24 " (got %d bytes, expected %d)")
25 % (len(d), l - 4))
25 % (len(d), l - 4))
26 return d
26 return d
27
27
28 def chunkiter(source):
28 def chunkiter(source):
29 """iterate through the chunks in source"""
29 """iterate through the chunks in source"""
30 while 1:
30 while 1:
31 c = getchunk(source)
31 c = getchunk(source)
32 if not c:
32 if not c:
33 break
33 break
34 yield c
34 yield c
35
35
36 def genchunk(data):
36 def genchunk(data):
37 """build a changegroup chunk"""
37 """build a changegroup chunk"""
38 header = struct.pack(">l", len(data)+ 4)
38 header = struct.pack(">l", len(data)+ 4)
39 return "%s%s" % (header, data)
39 return "%s%s" % (header, data)
40
40
41 def closechunk():
41 def closechunk():
42 return struct.pack(">l", 0)
42 return struct.pack(">l", 0)
43
43
44 class nocompress(object):
44 class nocompress(object):
45 def compress(self, x):
45 def compress(self, x):
46 return x
46 return x
47 def flush(self):
47 def flush(self):
48 return ""
48 return ""
49
49
50 bundletypes = {
50 bundletypes = {
51 "": ("", nocompress),
51 "": ("", nocompress),
52 "HG10UN": ("HG10UN", nocompress),
52 "HG10UN": ("HG10UN", nocompress),
53 "HG10BZ": ("HG10", bz2.BZ2Compressor),
53 "HG10BZ": ("HG10", lambda: bz2.BZ2Compressor()),
54 "HG10GZ": ("HG10GZ", zlib.compressobj),
54 "HG10GZ": ("HG10GZ", lambda: zlib.compressobj()),
55 }
55 }
56
56
57 def writebundle(cg, filename, bundletype):
57 def writebundle(cg, filename, bundletype):
58 """Write a bundle file and return its filename.
58 """Write a bundle file and return its filename.
59
59
60 Existing files will not be overwritten.
60 Existing files will not be overwritten.
61 If no filename is specified, a temporary file is created.
61 If no filename is specified, a temporary file is created.
62 bz2 compression can be turned off.
62 bz2 compression can be turned off.
63 The bundle file will be deleted in case of errors.
63 The bundle file will be deleted in case of errors.
64 """
64 """
65
65
66 fh = None
66 fh = None
67 cleanup = None
67 cleanup = None
68 try:
68 try:
69 if filename:
69 if filename:
70 if os.path.exists(filename):
70 if os.path.exists(filename):
71 raise util.Abort(_("file '%s' already exists") % filename)
71 raise util.Abort(_("file '%s' already exists") % filename)
72 fh = open(filename, "wb")
72 fh = open(filename, "wb")
73 else:
73 else:
74 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
74 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
75 fh = os.fdopen(fd, "wb")
75 fh = os.fdopen(fd, "wb")
76 cleanup = filename
76 cleanup = filename
77
77
78 header, compressor = bundletypes[bundletype]
78 header, compressor = bundletypes[bundletype]
79 fh.write(header)
79 fh.write(header)
80 z = compressor()
80 z = compressor()
81
81
82 # parse the changegroup data, otherwise we will block
82 # parse the changegroup data, otherwise we will block
83 # in case of sshrepo because we don't know the end of the stream
83 # in case of sshrepo because we don't know the end of the stream
84
84
85 # an empty chunkiter is the end of the changegroup
85 # an empty chunkiter is the end of the changegroup
86 empty = False
86 empty = False
87 while not empty:
87 while not empty:
88 empty = True
88 empty = True
89 for chunk in chunkiter(cg):
89 for chunk in chunkiter(cg):
90 empty = False
90 empty = False
91 fh.write(z.compress(genchunk(chunk)))
91 fh.write(z.compress(genchunk(chunk)))
92 fh.write(z.compress(closechunk()))
92 fh.write(z.compress(closechunk()))
93 fh.write(z.flush())
93 fh.write(z.flush())
94 cleanup = None
94 cleanup = None
95 return filename
95 return filename
96 finally:
96 finally:
97 if fh is not None:
97 if fh is not None:
98 fh.close()
98 fh.close()
99 if cleanup is not None:
99 if cleanup is not None:
100 os.unlink(cleanup)
100 os.unlink(cleanup)
101
101
102 def readbundle(fh):
102 def readbundle(fh):
103 header = fh.read(6)
103 header = fh.read(6)
104 if not header.startswith("HG"):
104 if not header.startswith("HG"):
105 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
105 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
106 elif not header.startswith("HG10"):
106 elif not header.startswith("HG10"):
107 raise util.Abort(_("%s: unknown bundle version") % fname)
107 raise util.Abort(_("%s: unknown bundle version") % fname)
108
108
109 if header == "HG10BZ":
109 if header == "HG10BZ":
110 def generator(f):
110 def generator(f):
111 zd = bz2.BZ2Decompressor()
111 zd = bz2.BZ2Decompressor()
112 zd.decompress("BZ")
112 zd.decompress("BZ")
113 for chunk in util.filechunkiter(f, 4096):
113 for chunk in util.filechunkiter(f, 4096):
114 yield zd.decompress(chunk)
114 yield zd.decompress(chunk)
115 return util.chunkbuffer(generator(fh))
115 return util.chunkbuffer(generator(fh))
116 elif header == "HG10UN":
116 elif header == "HG10UN":
117 return fh
117 return fh
118
118
119 raise util.Abort(_("%s: unknown bundle compression type")
119 raise util.Abort(_("%s: unknown bundle compression type")
120 % fname)
120 % fname)
General Comments 0
You need to be logged in to leave comments. Login now