Mercurial > hg
comparison mercurial/archival.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | c04e0836f039 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
14 import time | 14 import time |
15 import zipfile | 15 import zipfile |
16 import zlib | 16 import zlib |
17 | 17 |
18 from .i18n import _ | 18 from .i18n import _ |
19 from .node import ( | 19 from .node import nullrev |
20 nullrev, | |
21 ) | |
22 | 20 |
23 from . import ( | 21 from . import ( |
24 error, | 22 error, |
25 formatter, | 23 formatter, |
26 match as matchmod, | 24 match as matchmod, |
27 pycompat, | 25 pycompat, |
28 scmutil, | 26 scmutil, |
29 util, | 27 util, |
30 vfs as vfsmod, | 28 vfs as vfsmod, |
31 ) | 29 ) |
30 | |
32 stringio = util.stringio | 31 stringio = util.stringio |
33 | 32 |
34 # from unzip source code: | 33 # from unzip source code: |
35 _UNX_IFREG = 0x8000 | 34 _UNX_IFREG = 0x8000 |
36 _UNX_IFLNK = 0xa000 | 35 _UNX_IFLNK = 0xA000 |
36 | |
37 | 37 |
38 def tidyprefix(dest, kind, prefix): | 38 def tidyprefix(dest, kind, prefix): |
39 '''choose prefix to use for names in archive. make sure prefix is | 39 '''choose prefix to use for names in archive. make sure prefix is |
40 safe for consumers.''' | 40 safe for consumers.''' |
41 | 41 |
46 raise ValueError('dest must be string if no prefix') | 46 raise ValueError('dest must be string if no prefix') |
47 prefix = os.path.basename(dest) | 47 prefix = os.path.basename(dest) |
48 lower = prefix.lower() | 48 lower = prefix.lower() |
49 for sfx in exts.get(kind, []): | 49 for sfx in exts.get(kind, []): |
50 if lower.endswith(sfx): | 50 if lower.endswith(sfx): |
51 prefix = prefix[:-len(sfx)] | 51 prefix = prefix[: -len(sfx)] |
52 break | 52 break |
53 lpfx = os.path.normpath(util.localpath(prefix)) | 53 lpfx = os.path.normpath(util.localpath(prefix)) |
54 prefix = util.pconvert(lpfx) | 54 prefix = util.pconvert(lpfx) |
55 if not prefix.endswith('/'): | 55 if not prefix.endswith('/'): |
56 prefix += '/' | 56 prefix += '/' |
60 prefix = prefix[2:] | 60 prefix = prefix[2:] |
61 if prefix.startswith('../') or os.path.isabs(lpfx) or '/../' in prefix: | 61 if prefix.startswith('../') or os.path.isabs(lpfx) or '/../' in prefix: |
62 raise error.Abort(_('archive prefix contains illegal components')) | 62 raise error.Abort(_('archive prefix contains illegal components')) |
63 return prefix | 63 return prefix |
64 | 64 |
65 | |
65 exts = { | 66 exts = { |
66 'tar': ['.tar'], | 67 'tar': ['.tar'], |
67 'tbz2': ['.tbz2', '.tar.bz2'], | 68 'tbz2': ['.tbz2', '.tar.bz2'], |
68 'tgz': ['.tgz', '.tar.gz'], | 69 'tgz': ['.tgz', '.tar.gz'], |
69 'zip': ['.zip'], | 70 'zip': ['.zip'], |
70 'txz': ['.txz', '.tar.xz'] | 71 'txz': ['.txz', '.tar.xz'], |
71 } | 72 } |
73 | |
72 | 74 |
73 def guesskind(dest): | 75 def guesskind(dest): |
74 for kind, extensions in exts.iteritems(): | 76 for kind, extensions in exts.iteritems(): |
75 if any(dest.endswith(ext) for ext in extensions): | 77 if any(dest.endswith(ext) for ext in extensions): |
76 return kind | 78 return kind |
77 return None | 79 return None |
78 | 80 |
81 | |
79 def _rootctx(repo): | 82 def _rootctx(repo): |
80 # repo[0] may be hidden | 83 # repo[0] may be hidden |
81 for rev in repo: | 84 for rev in repo: |
82 return repo[rev] | 85 return repo[rev] |
83 return repo[nullrev] | 86 return repo[nullrev] |
87 | |
84 | 88 |
85 # {tags} on ctx includes local tags and 'tip', with no current way to limit | 89 # {tags} on ctx includes local tags and 'tip', with no current way to limit |
86 # that to global tags. Therefore, use {latesttag} as a substitute when | 90 # that to global tags. Therefore, use {latesttag} as a substitute when |
87 # the distance is 0, since that will be the list of global tags on ctx. | 91 # the distance is 0, since that will be the list of global tags on ctx. |
88 _defaultmetatemplate = br''' | 92 _defaultmetatemplate = br''' |
92 {ifeq(latesttagdistance, 0, join(latesttag % "tag: {tag}", "\n"), | 96 {ifeq(latesttagdistance, 0, join(latesttag % "tag: {tag}", "\n"), |
93 separate("\n", | 97 separate("\n", |
94 join(latesttag % "latesttag: {tag}", "\n"), | 98 join(latesttag % "latesttag: {tag}", "\n"), |
95 "latesttagdistance: {latesttagdistance}", | 99 "latesttagdistance: {latesttagdistance}", |
96 "changessincelatesttag: {changessincelatesttag}"))} | 100 "changessincelatesttag: {changessincelatesttag}"))} |
97 '''[1:] # drop leading '\n' | 101 '''[ |
102 1: | |
103 ] # drop leading '\n' | |
104 | |
98 | 105 |
99 def buildmetadata(ctx): | 106 def buildmetadata(ctx): |
100 '''build content of .hg_archival.txt''' | 107 '''build content of .hg_archival.txt''' |
101 repo = ctx.repo() | 108 repo = ctx.repo() |
102 | 109 |
103 opts = { | 110 opts = { |
104 'template': repo.ui.config('experimental', 'archivemetatemplate', | 111 'template': repo.ui.config( |
105 _defaultmetatemplate) | 112 'experimental', 'archivemetatemplate', _defaultmetatemplate |
113 ) | |
106 } | 114 } |
107 | 115 |
108 out = util.stringio() | 116 out = util.stringio() |
109 | 117 |
110 fm = formatter.formatter(repo.ui, out, 'archive', opts) | 118 fm = formatter.formatter(repo.ui, out, 'archive', opts) |
119 fm.data(dirty=dirty) | 127 fm.data(dirty=dirty) |
120 fm.end() | 128 fm.end() |
121 | 129 |
122 return out.getvalue() | 130 return out.getvalue() |
123 | 131 |
132 | |
124 class tarit(object): | 133 class tarit(object): |
125 '''write archive to tar file or stream. can write uncompressed, | 134 '''write archive to tar file or stream. can write uncompressed, |
126 or compress with gzip or bzip2.''' | 135 or compress with gzip or bzip2.''' |
127 | 136 |
128 class GzipFileWithTime(gzip.GzipFile): | 137 class GzipFileWithTime(gzip.GzipFile): |
129 | |
130 def __init__(self, *args, **kw): | 138 def __init__(self, *args, **kw): |
131 timestamp = None | 139 timestamp = None |
132 if r'timestamp' in kw: | 140 if r'timestamp' in kw: |
133 timestamp = kw.pop(r'timestamp') | 141 timestamp = kw.pop(r'timestamp') |
134 if timestamp is None: | 142 if timestamp is None: |
136 else: | 144 else: |
137 self.timestamp = timestamp | 145 self.timestamp = timestamp |
138 gzip.GzipFile.__init__(self, *args, **kw) | 146 gzip.GzipFile.__init__(self, *args, **kw) |
139 | 147 |
140 def _write_gzip_header(self): | 148 def _write_gzip_header(self): |
141 self.fileobj.write('\037\213') # magic header | 149 self.fileobj.write('\037\213') # magic header |
142 self.fileobj.write('\010') # compression method | 150 self.fileobj.write('\010') # compression method |
143 fname = self.name | 151 fname = self.name |
144 if fname and fname.endswith('.gz'): | 152 if fname and fname.endswith('.gz'): |
145 fname = fname[:-3] | 153 fname = fname[:-3] |
146 flags = 0 | 154 flags = 0 |
147 if fname: | 155 if fname: |
160 def taropen(mode, name='', fileobj=None): | 168 def taropen(mode, name='', fileobj=None): |
161 if kind == 'gz': | 169 if kind == 'gz': |
162 mode = mode[0:1] | 170 mode = mode[0:1] |
163 if not fileobj: | 171 if not fileobj: |
164 fileobj = open(name, mode + 'b') | 172 fileobj = open(name, mode + 'b') |
165 gzfileobj = self.GzipFileWithTime(name, | 173 gzfileobj = self.GzipFileWithTime( |
166 pycompat.sysstr(mode + 'b'), | 174 name, |
167 zlib.Z_BEST_COMPRESSION, | 175 pycompat.sysstr(mode + 'b'), |
168 fileobj, timestamp=mtime) | 176 zlib.Z_BEST_COMPRESSION, |
177 fileobj, | |
178 timestamp=mtime, | |
179 ) | |
169 self.fileobj = gzfileobj | 180 self.fileobj = gzfileobj |
170 return tarfile.TarFile.taropen( | 181 return tarfile.TarFile.taropen( |
171 name, pycompat.sysstr(mode), gzfileobj) | 182 name, pycompat.sysstr(mode), gzfileobj |
183 ) | |
172 else: | 184 else: |
173 return tarfile.open( | 185 return tarfile.open(name, pycompat.sysstr(mode + kind), fileobj) |
174 name, pycompat.sysstr(mode + kind), fileobj) | |
175 | 186 |
176 if isinstance(dest, bytes): | 187 if isinstance(dest, bytes): |
177 self.z = taropen('w:', name=dest) | 188 self.z = taropen('w:', name=dest) |
178 else: | 189 else: |
179 self.z = taropen('w|', fileobj=dest) | 190 self.z = taropen('w|', fileobj=dest) |
197 def done(self): | 208 def done(self): |
198 self.z.close() | 209 self.z.close() |
199 if self.fileobj: | 210 if self.fileobj: |
200 self.fileobj.close() | 211 self.fileobj.close() |
201 | 212 |
213 | |
202 class zipit(object): | 214 class zipit(object): |
203 '''write archive to zip file or stream. can write uncompressed, | 215 '''write archive to zip file or stream. can write uncompressed, |
204 or compressed with deflate.''' | 216 or compressed with deflate.''' |
205 | 217 |
206 def __init__(self, dest, mtime, compress=True): | 218 def __init__(self, dest, mtime, compress=True): |
207 if isinstance(dest, bytes): | 219 if isinstance(dest, bytes): |
208 dest = pycompat.fsdecode(dest) | 220 dest = pycompat.fsdecode(dest) |
209 self.z = zipfile.ZipFile(dest, r'w', | 221 self.z = zipfile.ZipFile( |
210 compress and zipfile.ZIP_DEFLATED or | 222 dest, r'w', compress and zipfile.ZIP_DEFLATED or zipfile.ZIP_STORED |
211 zipfile.ZIP_STORED) | 223 ) |
212 | 224 |
213 # Python's zipfile module emits deprecation warnings if we try | 225 # Python's zipfile module emits deprecation warnings if we try |
214 # to store files with a date before 1980. | 226 # to store files with a date before 1980. |
215 epoch = 315532800 # calendar.timegm((1980, 1, 1, 0, 0, 0, 1, 1, 0)) | 227 epoch = 315532800 # calendar.timegm((1980, 1, 1, 0, 0, 0, 1, 1, 0)) |
216 if mtime < epoch: | 228 if mtime < epoch: |
217 mtime = epoch | 229 mtime = epoch |
218 | 230 |
219 self.mtime = mtime | 231 self.mtime = mtime |
220 self.date_time = time.gmtime(mtime)[:6] | 232 self.date_time = time.gmtime(mtime)[:6] |
231 ftype = _UNX_IFLNK | 243 ftype = _UNX_IFLNK |
232 i.external_attr = (mode | ftype) << 16 | 244 i.external_attr = (mode | ftype) << 16 |
233 # add "extended-timestamp" extra block, because zip archives | 245 # add "extended-timestamp" extra block, because zip archives |
234 # without this will be extracted with unexpected timestamp, | 246 # without this will be extracted with unexpected timestamp, |
235 # if TZ is not configured as GMT | 247 # if TZ is not configured as GMT |
236 i.extra += struct.pack('<hhBl', | 248 i.extra += struct.pack( |
237 0x5455, # block type: "extended-timestamp" | 249 '<hhBl', |
238 1 + 4, # size of this block | 250 0x5455, # block type: "extended-timestamp" |
239 1, # "modification time is present" | 251 1 + 4, # size of this block |
240 int(self.mtime)) # last modification (UTC) | 252 1, # "modification time is present" |
253 int(self.mtime), | |
254 ) # last modification (UTC) | |
241 self.z.writestr(i, data) | 255 self.z.writestr(i, data) |
242 | 256 |
243 def done(self): | 257 def done(self): |
244 self.z.close() | 258 self.z.close() |
259 | |
245 | 260 |
246 class fileit(object): | 261 class fileit(object): |
247 '''write archive as files in directory.''' | 262 '''write archive as files in directory.''' |
248 | 263 |
249 def __init__(self, name, mtime): | 264 def __init__(self, name, mtime): |
264 os.utime(destfile, (self.mtime, self.mtime)) | 279 os.utime(destfile, (self.mtime, self.mtime)) |
265 | 280 |
266 def done(self): | 281 def done(self): |
267 pass | 282 pass |
268 | 283 |
284 | |
269 archivers = { | 285 archivers = { |
270 'files': fileit, | 286 'files': fileit, |
271 'tar': tarit, | 287 'tar': tarit, |
272 'tbz2': lambda name, mtime: tarit(name, mtime, 'bz2'), | 288 'tbz2': lambda name, mtime: tarit(name, mtime, 'bz2'), |
273 'tgz': lambda name, mtime: tarit(name, mtime, 'gz'), | 289 'tgz': lambda name, mtime: tarit(name, mtime, 'gz'), |
274 'txz': lambda name, mtime: tarit(name, mtime, 'xz'), | 290 'txz': lambda name, mtime: tarit(name, mtime, 'xz'), |
275 'uzip': lambda name, mtime: zipit(name, mtime, False), | 291 'uzip': lambda name, mtime: zipit(name, mtime, False), |
276 'zip': zipit, | 292 'zip': zipit, |
277 } | 293 } |
278 | 294 |
279 def archive(repo, dest, node, kind, decode=True, match=None, | 295 |
280 prefix='', mtime=None, subrepos=False): | 296 def archive( |
297 repo, | |
298 dest, | |
299 node, | |
300 kind, | |
301 decode=True, | |
302 match=None, | |
303 prefix='', | |
304 mtime=None, | |
305 subrepos=False, | |
306 ): | |
281 '''create archive of repo as it was at node. | 307 '''create archive of repo as it was at node. |
282 | 308 |
283 dest can be name of directory, name of archive file, or file | 309 dest can be name of directory, name of archive file, or file |
284 object to write archive to. | 310 object to write archive to. |
285 | 311 |
328 | 354 |
329 files = [f for f in ctx.manifest().matches(match)] | 355 files = [f for f in ctx.manifest().matches(match)] |
330 total = len(files) | 356 total = len(files) |
331 if total: | 357 if total: |
332 files.sort() | 358 files.sort() |
333 scmutil.prefetchfiles(repo, [ctx.rev()], | 359 scmutil.prefetchfiles( |
334 scmutil.matchfiles(repo, files)) | 360 repo, [ctx.rev()], scmutil.matchfiles(repo, files) |
335 progress = repo.ui.makeprogress(_('archiving'), unit=_('files'), | 361 ) |
336 total=total) | 362 progress = repo.ui.makeprogress( |
363 _('archiving'), unit=_('files'), total=total | |
364 ) | |
337 progress.update(0) | 365 progress.update(0) |
338 for f in files: | 366 for f in files: |
339 ff = ctx.flags(f) | 367 ff = ctx.flags(f) |
340 write(f, 'x' in ff and 0o755 or 0o644, 'l' in ff, ctx[f].data) | 368 write(f, 'x' in ff and 0o755 or 0o644, 'l' in ff, ctx[f].data) |
341 progress.increment(item=f) | 369 progress.increment(item=f) |