##// END OF EJS Templates
Fix retaring process for twine....
Matthias Bussonnier -
Show More
@@ -1,60 +1,64 b''
1 1 """
2 2 Un-targz and retargz a targz file to ensure reproducible build.
3 3
4 4 usage:
5 5
6 6 $ export SOURCE_DATE_EPOCH=$(date +%s)
7 7 ...
8 8 $ python retar.py <tarfile.gz>
9 9
10 10 The process of creating an sdist can be non-reproducible:
11 11 - directory created during the process get a mtime of the creation date;
12 12 - gziping files embed the timestamp of fo zip creation.
13 13
14 14 This will untar-retar; ensuring that all mtime > SOURCE_DATE_EPOCH will be set
15 15 equal to SOURCE_DATE_EPOCH.
16 16
17 17 """
18 18
19 19 import tarfile
20 20 import sys
21 21 import os
22 22 import gzip
23 23 import io
24 24
25 25 if len(sys.argv) > 2:
26 26 raise ValueError("Too many arguments")
27 27
28 28
29 29 timestamp = int(os.environ["SOURCE_DATE_EPOCH"])
30 30
31 31 old_buf = io.BytesIO()
32 32 with open(sys.argv[1], "rb") as f:
33 33 old_buf.write(f.read())
34 34 old_buf.seek(0)
35 35 old = tarfile.open(fileobj=old_buf, mode="r:gz")
36 36
37 37 buf = io.BytesIO()
38 38 new = tarfile.open(fileobj=buf, mode="w", format=tarfile.GNU_FORMAT)
39 39 for i, m in enumerate(old):
40 40 data = None
41 41 # mutation does not work, copy
42 42 if m.name.endswith('.DS_Store'):
43 43 continue
44 44 m2 = tarfile.TarInfo(m.name)
45 45 m2.mtime = min(timestamp, m.mtime)
46 46 m2.size = m.size
47 47 m2.type = m.type
48 48 m2.linkname = m.linkname
49 49 if m.isdir():
50 new.addfile(m2)
51 else:
50 52 data = old.extractfile(m)
51 53 new.addfile(m2, data)
52 else:
53 new.addfile(m2)
54 54 new.close()
55 55 old.close()
56 56
57 57 buf.seek(0)
58 58 with open(sys.argv[1], "wb") as f:
59 59 with gzip.GzipFile('', "wb", fileobj=f, mtime=timestamp) as gzf:
60 60 gzf.write(buf.read())
61
62 # checks the archive is valid.
63 archive = tarfile.open(sys.argv[1])
64 names = archive.getnames()
General Comments 0
You need to be logged in to leave comments. Login now