-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathcreate-reproducible-tar.py
More file actions
executable file
·68 lines (53 loc) · 2 KB
/
Copy pathcreate-reproducible-tar.py
File metadata and controls
executable file
·68 lines (53 loc) · 2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/usr/bin/env python3
"""Create a deterministic root-owned XZ-compressed tar archive."""
from __future__ import annotations
import os
from pathlib import Path
import sys
import tarfile
def normalized_info(tar: tarfile.TarFile, path: Path, name: str, mtime: int) -> tarfile.TarInfo:
info = tar.gettarinfo(str(path), arcname=name)
info.uid = 0
info.gid = 0
info.uname = "root"
info.gname = "root"
info.mtime = mtime
info.mode = 0o755
info.pax_headers = {}
return info
def add_tree(tar: tarfile.TarFile, root: Path, relative: Path, mtime: int) -> None:
path = root / relative
name = f"./{relative.as_posix()}"
info = normalized_info(tar, path, name, mtime)
if info.isfile():
with path.open("rb") as source:
tar.addfile(info, source)
return
tar.addfile(info)
if info.isdir():
for child in sorted(path.iterdir(), key=lambda item: os.fsencode(item.name)):
add_tree(tar, root, relative / child.name, mtime)
def main() -> int:
if len(sys.argv) != 4:
raise SystemExit("usage: create-reproducible-tar.py <source-dir> <archive.txz> <unix-mtime>")
source = Path(sys.argv[1]).resolve()
destination = Path(sys.argv[2]).resolve()
mtime = int(sys.argv[3])
if not source.is_dir():
raise SystemExit(f"source directory does not exist: {source}")
destination.parent.mkdir(parents=True, exist_ok=True)
with tarfile.open(destination, mode="w:xz", format=tarfile.GNU_FORMAT, preset=6) as tar:
root_info = tarfile.TarInfo("./")
root_info.type = tarfile.DIRTYPE
root_info.uid = 0
root_info.gid = 0
root_info.uname = "root"
root_info.gname = "root"
root_info.mode = 0o755
root_info.mtime = mtime
tar.addfile(root_info)
for child in sorted(source.iterdir(), key=lambda item: os.fsencode(item.name)):
add_tree(tar, source, Path(child.name), mtime)
return 0
if __name__ == "__main__":
raise SystemExit(main())