##// END OF EJS Templates
python-2.6: deprecation of GzipFile.filename
Dirkjan Ochtman -
r6495:3130c9de default
parent child Browse files
Show More
@@ -1,224 +1,225 b''
1 # archival.py - revision archival for mercurial
1 # archival.py - revision archival for mercurial
2 #
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of
5 # This software may be used and distributed according to the terms of
6 # the GNU General Public License, incorporated herein by reference.
6 # the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 from node import hex
9 from node import hex
10 import cStringIO, os, stat, tarfile, time, util, zipfile
10 import cStringIO, os, stat, tarfile, time, util, zipfile
11 import zlib, gzip
11 import zlib, gzip
12
12
13 def tidyprefix(dest, prefix, suffixes):
13 def tidyprefix(dest, prefix, suffixes):
14 '''choose prefix to use for names in archive. make sure prefix is
14 '''choose prefix to use for names in archive. make sure prefix is
15 safe for consumers.'''
15 safe for consumers.'''
16
16
17 if prefix:
17 if prefix:
18 prefix = util.normpath(prefix)
18 prefix = util.normpath(prefix)
19 else:
19 else:
20 if not isinstance(dest, str):
20 if not isinstance(dest, str):
21 raise ValueError('dest must be string if no prefix')
21 raise ValueError('dest must be string if no prefix')
22 prefix = os.path.basename(dest)
22 prefix = os.path.basename(dest)
23 lower = prefix.lower()
23 lower = prefix.lower()
24 for sfx in suffixes:
24 for sfx in suffixes:
25 if lower.endswith(sfx):
25 if lower.endswith(sfx):
26 prefix = prefix[:-len(sfx)]
26 prefix = prefix[:-len(sfx)]
27 break
27 break
28 lpfx = os.path.normpath(util.localpath(prefix))
28 lpfx = os.path.normpath(util.localpath(prefix))
29 prefix = util.pconvert(lpfx)
29 prefix = util.pconvert(lpfx)
30 if not prefix.endswith('/'):
30 if not prefix.endswith('/'):
31 prefix += '/'
31 prefix += '/'
32 if prefix.startswith('../') or os.path.isabs(lpfx) or '/../' in prefix:
32 if prefix.startswith('../') or os.path.isabs(lpfx) or '/../' in prefix:
33 raise util.Abort(_('archive prefix contains illegal components'))
33 raise util.Abort(_('archive prefix contains illegal components'))
34 return prefix
34 return prefix
35
35
36 class tarit:
36 class tarit:
37 '''write archive to tar file or stream. can write uncompressed,
37 '''write archive to tar file or stream. can write uncompressed,
38 or compress with gzip or bzip2.'''
38 or compress with gzip or bzip2.'''
39
39
40 class GzipFileWithTime(gzip.GzipFile):
40 class GzipFileWithTime(gzip.GzipFile):
41
41
42 def __init__(self, *args, **kw):
42 def __init__(self, *args, **kw):
43 timestamp = None
43 timestamp = None
44 if 'timestamp' in kw:
44 if 'timestamp' in kw:
45 timestamp = kw.pop('timestamp')
45 timestamp = kw.pop('timestamp')
46 if timestamp == None:
46 if timestamp == None:
47 self.timestamp = time.time()
47 self.timestamp = time.time()
48 else:
48 else:
49 self.timestamp = timestamp
49 self.timestamp = timestamp
50 gzip.GzipFile.__init__(self, *args, **kw)
50 gzip.GzipFile.__init__(self, *args, **kw)
51
51
52 def _write_gzip_header(self):
52 def _write_gzip_header(self):
53 self.fileobj.write('\037\213') # magic header
53 self.fileobj.write('\037\213') # magic header
54 self.fileobj.write('\010') # compression method
54 self.fileobj.write('\010') # compression method
55 fname = self.filename[:-3]
55 # Python 2.6 deprecates self.filename
56 fname = getattr(self, 'name', None) or self.filename
56 flags = 0
57 flags = 0
57 if fname:
58 if fname:
58 flags = gzip.FNAME
59 flags = gzip.FNAME
59 self.fileobj.write(chr(flags))
60 self.fileobj.write(chr(flags))
60 gzip.write32u(self.fileobj, long(self.timestamp))
61 gzip.write32u(self.fileobj, long(self.timestamp))
61 self.fileobj.write('\002')
62 self.fileobj.write('\002')
62 self.fileobj.write('\377')
63 self.fileobj.write('\377')
63 if fname:
64 if fname:
64 self.fileobj.write(fname + '\000')
65 self.fileobj.write(fname + '\000')
65
66
66 def __init__(self, dest, prefix, mtime, kind=''):
67 def __init__(self, dest, prefix, mtime, kind=''):
67 self.prefix = tidyprefix(dest, prefix, ['.tar', '.tar.bz2', '.tar.gz',
68 self.prefix = tidyprefix(dest, prefix, ['.tar', '.tar.bz2', '.tar.gz',
68 '.tgz', '.tbz2'])
69 '.tgz', '.tbz2'])
69 self.mtime = mtime
70 self.mtime = mtime
70
71
71 def taropen(name, mode, fileobj=None):
72 def taropen(name, mode, fileobj=None):
72 if kind == 'gz':
73 if kind == 'gz':
73 mode = mode[0]
74 mode = mode[0]
74 if not fileobj:
75 if not fileobj:
75 fileobj = open(name, mode + 'b')
76 fileobj = open(name, mode + 'b')
76 gzfileobj = self.GzipFileWithTime(name, mode + 'b',
77 gzfileobj = self.GzipFileWithTime(name, mode + 'b',
77 zlib.Z_BEST_COMPRESSION,
78 zlib.Z_BEST_COMPRESSION,
78 fileobj, timestamp=mtime)
79 fileobj, timestamp=mtime)
79 return tarfile.TarFile.taropen(name, mode, gzfileobj)
80 return tarfile.TarFile.taropen(name, mode, gzfileobj)
80 else:
81 else:
81 return tarfile.open(name, mode + kind, fileobj)
82 return tarfile.open(name, mode + kind, fileobj)
82
83
83 if isinstance(dest, str):
84 if isinstance(dest, str):
84 self.z = taropen(dest, mode='w:')
85 self.z = taropen(dest, mode='w:')
85 else:
86 else:
86 # Python 2.5-2.5.1 have a regression that requires a name arg
87 # Python 2.5-2.5.1 have a regression that requires a name arg
87 self.z = taropen(name='', mode='w|', fileobj=dest)
88 self.z = taropen(name='', mode='w|', fileobj=dest)
88
89
89 def addfile(self, name, mode, islink, data):
90 def addfile(self, name, mode, islink, data):
90 i = tarfile.TarInfo(self.prefix + name)
91 i = tarfile.TarInfo(self.prefix + name)
91 i.mtime = self.mtime
92 i.mtime = self.mtime
92 i.size = len(data)
93 i.size = len(data)
93 if islink:
94 if islink:
94 i.type = tarfile.SYMTYPE
95 i.type = tarfile.SYMTYPE
95 i.mode = 0777
96 i.mode = 0777
96 i.linkname = data
97 i.linkname = data
97 data = None
98 data = None
98 else:
99 else:
99 i.mode = mode
100 i.mode = mode
100 data = cStringIO.StringIO(data)
101 data = cStringIO.StringIO(data)
101 self.z.addfile(i, data)
102 self.z.addfile(i, data)
102
103
103 def done(self):
104 def done(self):
104 self.z.close()
105 self.z.close()
105
106
106 class tellable:
107 class tellable:
107 '''provide tell method for zipfile.ZipFile when writing to http
108 '''provide tell method for zipfile.ZipFile when writing to http
108 response file object.'''
109 response file object.'''
109
110
110 def __init__(self, fp):
111 def __init__(self, fp):
111 self.fp = fp
112 self.fp = fp
112 self.offset = 0
113 self.offset = 0
113
114
114 def __getattr__(self, key):
115 def __getattr__(self, key):
115 return getattr(self.fp, key)
116 return getattr(self.fp, key)
116
117
117 def write(self, s):
118 def write(self, s):
118 self.fp.write(s)
119 self.fp.write(s)
119 self.offset += len(s)
120 self.offset += len(s)
120
121
121 def tell(self):
122 def tell(self):
122 return self.offset
123 return self.offset
123
124
124 class zipit:
125 class zipit:
125 '''write archive to zip file or stream. can write uncompressed,
126 '''write archive to zip file or stream. can write uncompressed,
126 or compressed with deflate.'''
127 or compressed with deflate.'''
127
128
128 def __init__(self, dest, prefix, mtime, compress=True):
129 def __init__(self, dest, prefix, mtime, compress=True):
129 self.prefix = tidyprefix(dest, prefix, ('.zip',))
130 self.prefix = tidyprefix(dest, prefix, ('.zip',))
130 if not isinstance(dest, str):
131 if not isinstance(dest, str):
131 try:
132 try:
132 dest.tell()
133 dest.tell()
133 except (AttributeError, IOError):
134 except (AttributeError, IOError):
134 dest = tellable(dest)
135 dest = tellable(dest)
135 self.z = zipfile.ZipFile(dest, 'w',
136 self.z = zipfile.ZipFile(dest, 'w',
136 compress and zipfile.ZIP_DEFLATED or
137 compress and zipfile.ZIP_DEFLATED or
137 zipfile.ZIP_STORED)
138 zipfile.ZIP_STORED)
138 self.date_time = time.gmtime(mtime)[:6]
139 self.date_time = time.gmtime(mtime)[:6]
139
140
140 def addfile(self, name, mode, islink, data):
141 def addfile(self, name, mode, islink, data):
141 i = zipfile.ZipInfo(self.prefix + name, self.date_time)
142 i = zipfile.ZipInfo(self.prefix + name, self.date_time)
142 i.compress_type = self.z.compression
143 i.compress_type = self.z.compression
143 # unzip will not honor unix file modes unless file creator is
144 # unzip will not honor unix file modes unless file creator is
144 # set to unix (id 3).
145 # set to unix (id 3).
145 i.create_system = 3
146 i.create_system = 3
146 ftype = stat.S_IFREG
147 ftype = stat.S_IFREG
147 if islink:
148 if islink:
148 mode = 0777
149 mode = 0777
149 ftype = stat.S_IFLNK
150 ftype = stat.S_IFLNK
150 i.external_attr = (mode | ftype) << 16L
151 i.external_attr = (mode | ftype) << 16L
151 self.z.writestr(i, data)
152 self.z.writestr(i, data)
152
153
153 def done(self):
154 def done(self):
154 self.z.close()
155 self.z.close()
155
156
156 class fileit:
157 class fileit:
157 '''write archive as files in directory.'''
158 '''write archive as files in directory.'''
158
159
159 def __init__(self, name, prefix, mtime):
160 def __init__(self, name, prefix, mtime):
160 if prefix:
161 if prefix:
161 raise util.Abort(_('cannot give prefix when archiving to files'))
162 raise util.Abort(_('cannot give prefix when archiving to files'))
162 self.basedir = name
163 self.basedir = name
163 self.opener = util.opener(self.basedir)
164 self.opener = util.opener(self.basedir)
164
165
165 def addfile(self, name, mode, islink, data):
166 def addfile(self, name, mode, islink, data):
166 if islink:
167 if islink:
167 self.opener.symlink(data, name)
168 self.opener.symlink(data, name)
168 return
169 return
169 f = self.opener(name, "w", atomictemp=True)
170 f = self.opener(name, "w", atomictemp=True)
170 f.write(data)
171 f.write(data)
171 f.rename()
172 f.rename()
172 destfile = os.path.join(self.basedir, name)
173 destfile = os.path.join(self.basedir, name)
173 os.chmod(destfile, mode)
174 os.chmod(destfile, mode)
174
175
175 def done(self):
176 def done(self):
176 pass
177 pass
177
178
178 archivers = {
179 archivers = {
179 'files': fileit,
180 'files': fileit,
180 'tar': tarit,
181 'tar': tarit,
181 'tbz2': lambda name, prefix, mtime: tarit(name, prefix, mtime, 'bz2'),
182 'tbz2': lambda name, prefix, mtime: tarit(name, prefix, mtime, 'bz2'),
182 'tgz': lambda name, prefix, mtime: tarit(name, prefix, mtime, 'gz'),
183 'tgz': lambda name, prefix, mtime: tarit(name, prefix, mtime, 'gz'),
183 'uzip': lambda name, prefix, mtime: zipit(name, prefix, mtime, False),
184 'uzip': lambda name, prefix, mtime: zipit(name, prefix, mtime, False),
184 'zip': zipit,
185 'zip': zipit,
185 }
186 }
186
187
187 def archive(repo, dest, node, kind, decode=True, matchfn=None,
188 def archive(repo, dest, node, kind, decode=True, matchfn=None,
188 prefix=None, mtime=None):
189 prefix=None, mtime=None):
189 '''create archive of repo as it was at node.
190 '''create archive of repo as it was at node.
190
191
191 dest can be name of directory, name of archive file, or file
192 dest can be name of directory, name of archive file, or file
192 object to write archive to.
193 object to write archive to.
193
194
194 kind is type of archive to create.
195 kind is type of archive to create.
195
196
196 decode tells whether to put files through decode filters from
197 decode tells whether to put files through decode filters from
197 hgrc.
198 hgrc.
198
199
199 matchfn is function to filter names of files to write to archive.
200 matchfn is function to filter names of files to write to archive.
200
201
201 prefix is name of path to put before every archive member.'''
202 prefix is name of path to put before every archive member.'''
202
203
203 def write(name, mode, islink, getdata):
204 def write(name, mode, islink, getdata):
204 if matchfn and not matchfn(name): return
205 if matchfn and not matchfn(name): return
205 data = getdata()
206 data = getdata()
206 if decode:
207 if decode:
207 data = repo.wwritedata(name, data)
208 data = repo.wwritedata(name, data)
208 archiver.addfile(name, mode, islink, data)
209 archiver.addfile(name, mode, islink, data)
209
210
210 ctx = repo.changectx(node)
211 ctx = repo.changectx(node)
211 if kind not in archivers:
212 if kind not in archivers:
212 raise util.Abort(_("unknown archive type '%s'" % kind))
213 raise util.Abort(_("unknown archive type '%s'" % kind))
213 archiver = archivers[kind](dest, prefix, mtime or ctx.date()[0])
214 archiver = archivers[kind](dest, prefix, mtime or ctx.date()[0])
214 m = ctx.manifest()
215 m = ctx.manifest()
215 items = m.items()
216 items = m.items()
216 items.sort()
217 items.sort()
217 if repo.ui.configbool("ui", "archivemeta", True):
218 if repo.ui.configbool("ui", "archivemeta", True):
218 write('.hg_archival.txt', 0644, False,
219 write('.hg_archival.txt', 0644, False,
219 lambda: 'repo: %s\nnode: %s\n' % (
220 lambda: 'repo: %s\nnode: %s\n' % (
220 hex(repo.changelog.node(0)), hex(node)))
221 hex(repo.changelog.node(0)), hex(node)))
221 for filename, filenode in items:
222 for filename, filenode in items:
222 write(filename, m.execf(filename) and 0755 or 0644, m.linkf(filename),
223 write(filename, m.execf(filename) and 0755 or 0644, m.linkf(filename),
223 lambda: repo.file(filename).read(filenode))
224 lambda: repo.file(filename).read(filenode))
224 archiver.done()
225 archiver.done()
General Comments 0
You need to be logged in to leave comments. Login now