retar.py
65 lines
| 1.5 KiB
| text/x-python
|
PythonLexer
/ tools / retar.py
Matthias Bussonnier
|
r25778 | """ | ||
Un-targz and retargz a targz file to ensure reproducible build. | ||||
usage: | ||||
$ export SOURCE_DATE_EPOCH=$(date +%s) | ||||
... | ||||
$ python retar.py <tarfile.gz> | ||||
The process of creating an sdist can be non-reproducible: | ||||
- directory created during the process get a mtime of the creation date; | ||||
- gziping files embed the timestamp of fo zip creation. | ||||
This will untar-retar; ensuring that all mtime > SOURCE_DATE_EPOCH will be set | ||||
equal to SOURCE_DATE_EPOCH. | ||||
""" | ||||
import tarfile | ||||
import sys | ||||
import os | ||||
import gzip | ||||
import io | ||||
if len(sys.argv) > 2: | ||||
raise ValueError("Too many arguments") | ||||
timestamp = int(os.environ["SOURCE_DATE_EPOCH"]) | ||||
old_buf = io.BytesIO() | ||||
with open(sys.argv[1], "rb") as f: | ||||
old_buf.write(f.read()) | ||||
old_buf.seek(0) | ||||
old = tarfile.open(fileobj=old_buf, mode="r:gz") | ||||
buf = io.BytesIO() | ||||
new = tarfile.open(fileobj=buf, mode="w", format=tarfile.GNU_FORMAT) | ||||
for i, m in enumerate(old): | ||||
data = None | ||||
# mutation does not work, copy | ||||
if m.name.endswith('.DS_Store'): | ||||
continue | ||||
m2 = tarfile.TarInfo(m.name) | ||||
m2.mtime = min(timestamp, m.mtime) | ||||
m2.size = m.size | ||||
m2.type = m.type | ||||
m2.linkname = m.linkname | ||||
Matthias Bussonnier
|
r25863 | m2.mode = m.mode | ||
Matthias Bussonnier
|
r25778 | if m.isdir(): | ||
Matthias Bussonnier
|
r25802 | new.addfile(m2) | ||
else: | ||||
Matthias Bussonnier
|
r25778 | data = old.extractfile(m) | ||
new.addfile(m2, data) | ||||
new.close() | ||||
old.close() | ||||
buf.seek(0) | ||||
with open(sys.argv[1], "wb") as f: | ||||
with gzip.GzipFile('', "wb", fileobj=f, mtime=timestamp) as gzf: | ||||
gzf.write(buf.read()) | ||||
Matthias Bussonnier
|
r25802 | |||
# checks the archive is valid. | ||||
archive = tarfile.open(sys.argv[1]) | ||||
names = archive.getnames() | ||||