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