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