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 util") |
11 demandload(globals(), "struct os bz2 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: |
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): |
|
45 def compress(self, x): |
|
46 return x |
|
47 def flush(self): |
|
48 return "" |
|
49 |
|
50 def writebundle(cg, filename, compress): |
|
51 """Write a bundle file and return its filename. |
|
52 |
|
53 Existing files will not be overwritten. |
|
54 If no filename is specified, a temporary file is created. |
|
55 bz2 compression can be turned off. |
|
56 The bundle file will be deleted in case of errors. |
|
57 """ |
|
58 |
|
59 fh = None |
|
60 cleanup = None |
|
61 try: |
|
62 if filename: |
|
63 if os.path.exists(filename): |
|
64 raise util.Abort(_("file '%s' already exists") % filename) |
|
65 fh = open(filename, "wb") |
|
66 else: |
|
67 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg") |
|
68 fh = os.fdopen(fd, "wb") |
|
69 cleanup = filename |
|
70 |
|
71 if compress: |
|
72 fh.write("HG10") |
|
73 z = bz2.BZ2Compressor(9) |
|
74 else: |
|
75 fh.write("HG10UN") |
|
76 z = nocompress() |
|
77 # parse the changegroup data, otherwise we will block |
|
78 # in case of sshrepo because we don't know the end of the stream |
|
79 |
|
80 # an empty chunkiter is the end of the changegroup |
|
81 empty = False |
|
82 while not empty: |
|
83 empty = True |
|
84 for chunk in chunkiter(cg): |
|
85 empty = False |
|
86 fh.write(z.compress(genchunk(chunk))) |
|
87 fh.write(z.compress(closechunk())) |
|
88 fh.write(z.flush()) |
|
89 cleanup = None |
|
90 return filename |
|
91 finally: |
|
92 if fh is not None: |
|
93 fh.close() |
|
94 if cleanup is not None: |
|
95 os.unlink(cleanup) |