scripts/package_site.py (1874B)
1 #!/usr/bin/env python3
2 """Package only generated regular files, preserving dot-prefixed repository names."""
3
4 import argparse
5 from pathlib import Path
6 import tarfile
7
8 ROOT = Path(__file__).resolve().parents[1]
9 MAX_ARCHIVE_BYTES = 1024 * 1024 * 1024
10
11
12 def package(public, output):
13 public = public.resolve()
14 output = output.resolve()
15 if output.is_relative_to(public):
16 raise ValueError("Place the deployment archive outside the generated site")
17 if not (public / "index.html").is_file():
18 raise ValueError("The generated site has no index.html")
19 paths = sorted(public.rglob("*"))
20 total = 0
21 for path in paths:
22 if path.is_symlink() or path.is_junction() or not (path.is_file() or path.is_dir()):
23 raise ValueError(f"Deployment contains a link or special file: {path}")
24 if ".git" in path.relative_to(public).parts:
25 raise ValueError("Git metadata must never be deployed")
26 if path.is_file():
27 total += path.stat().st_size
28 total += 2048
29 if total >= MAX_ARCHIVE_BYTES:
30 raise ValueError("Generated site exceeds the 1 GiB deployment limit")
31 output.parent.mkdir(parents=True, exist_ok=True)
32 with tarfile.open(output, "w", format=tarfile.PAX_FORMAT, dereference=True) as archive:
33 for path in paths:
34 archive.add(path, arcname=path.relative_to(public).as_posix(), recursive=False)
35 if output.stat().st_size >= MAX_ARCHIVE_BYTES:
36 raise ValueError("Deployment archive exceeds the 1 GiB limit")
37 print(f"Packaged {len(paths)} entries into {output} ({output.stat().st_size:,} bytes)")
38
39
40 def main():
41 parser = argparse.ArgumentParser(description=__doc__)
42 parser.add_argument("--output", type=Path, required=True)
43 args = parser.parse_args()
44 package(ROOT / "public", args.output)
45
46
47 if __name__ == "__main__":
48 main()