mirror of
https://github.com/CyC2018/Interview-Notebook.git
synced 2026-10-31 11:05:36 +00:00
49 lines
2.2 KiB
Python
49 lines
2.2 KiB
Python
"""Create a reproducible UTF-8 ZIP from the validated manifest, without credentials."""
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import tempfile
|
|
import zipfile
|
|
from pathlib import Path
|
|
|
|
|
|
def create_archive(source, output):
|
|
source, output = Path(source).resolve(), Path(output).resolve()
|
|
if output.is_relative_to(source):
|
|
raise ValueError('发布包必须保存在网站产物目录外。')
|
|
manifest = json.loads((source / 'asset-manifest.json').read_text())
|
|
records = {item['path']: item for item in manifest['files']}
|
|
names = sorted([*records, 'asset-manifest.json'])
|
|
output.parent.mkdir(parents=True, exist_ok=True)
|
|
with tempfile.NamedTemporaryFile(dir=output.parent, suffix='.zip', delete=False) as temporary:
|
|
temporary_path = Path(temporary.name)
|
|
try:
|
|
with zipfile.ZipFile(temporary_path, 'w', compression=zipfile.ZIP_DEFLATED) as archive:
|
|
for name in names:
|
|
path = source / name
|
|
if not path.resolve().is_relative_to(source) or path.is_symlink():
|
|
raise ValueError('非法发布路径:' + name)
|
|
data = path.read_bytes()
|
|
if name in records:
|
|
record = records[name]
|
|
if len(data) != record['bytes'] or hashlib.sha256(data).hexdigest() != record['sha256']:
|
|
raise ValueError('打包前文件校验不一致:' + name)
|
|
entry = zipfile.ZipInfo(name, date_time=(1980, 1, 1, 0, 0, 0))
|
|
entry.compress_type = zipfile.ZIP_DEFLATED
|
|
entry.create_system = 3
|
|
entry.external_attr = 0o100644 << 16
|
|
archive.writestr(entry, data, compresslevel=6)
|
|
temporary_path.replace(output)
|
|
finally:
|
|
temporary_path.unlink(missing_ok=True)
|
|
return len(names)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
website = Path(__file__).resolve().parents[1]
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--source', type=Path, default=website / 'dist')
|
|
parser.add_argument('--output', type=Path, default=website / '.cache/site-release.zip')
|
|
args = parser.parse_args()
|
|
print('已校验并打包文件:' + str(create_archive(args.source, args.output)))
|