| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- """Package reviewed front-end files only; record the observed production baseline."""
- import hashlib
- import json
- from pathlib import Path
- import urllib.request
- import zipfile
- ROOT = Path(__file__).resolve().parents[1]
- OUT = ROOT / 'artifacts/商品图片展示-20261106-r1'
- WORK = ROOT / 'work/product-media/frontend-package'
- DOCS = ROOT / 'docs/industry-product-images-20261106'
- FILES = [
- 'src/core/library.js', 'src/core/library-comparison.js',
- 'src/services/library-service.js', 'src/services/library-images.js', 'src/services/library-comparison.js',
- 'src/pages/view-library.js', 'src/pages/library-styles.js',
- 'src/pages/library-product-image.js', 'src/pages/library-product-compare.js',
- ]
- sha = lambda body: hashlib.sha256(body).hexdigest()
- normalized = lambda body: sha(body.replace(b'\r\n', b'\n'))
- def main():
- WORK.mkdir(parents=True, exist_ok=True)
- OUT.mkdir(parents=True, exist_ok=True)
- target = OUT / 'ksf-product-images-20261106-r1.zip'
- if target.exists():
- raise RuntimeError('RELEASE_ALREADY_EXISTS')
- observed = []
- for path in FILES + ['src/pages/library-product-detail.js']:
- req = urllib.request.Request('https://kangshifu.fmode.cn/' + path, headers={'Cache-Control': 'no-cache'})
- with urllib.request.urlopen(req, timeout=25) as response:
- before, mime = response.read(), response.headers.get('Content-Type', '')
- absent = 'text/html' in mime
- after = (ROOT / path).read_bytes()
- backup = WORK / 'production-before' / path
- backup.parent.mkdir(parents=True, exist_ok=True)
- backup.write_bytes(before)
- observed.append({'path': path, 'sha256': sha(after), 'normalizedSha256': normalized(after),
- 'observedProductionSha256': sha(before), 'priorNormalizedSha256': [] if absent else [normalized(before)],
- 'allowMissing': absent, 'dependencyOnly': path not in FILES,
- 'productionMatchesLocal': not absent and normalized(before) == normalized(after)})
- manifest = {'schema': 'ksf.product-images.frontend-release.v1', 'origin': 'https://kangshifu.fmode.cn',
- 'files': [row for row in observed if not row['dependencyOnly']],
- 'dependencies': [row for row in observed if row['dependencyOnly']],
- 'databaseImageCount': 4674, 'databasePublished': True, 'frontendPublished': False,
- 'instructions': ['Use the existing static-site publishing channel.',
- 'Compare the observed production baseline before replacing any file; stop on mismatch.',
- 'Resolve the product detail dependency with the main workspace owner; it is not included for replacement.',
- 'Upload new modules before importing pages; retain backups and verify the module graph and browser afterward.']}
- raw_manifest = (json.dumps(manifest, ensure_ascii=False, indent=2) + '\n').encode()
- (DOCS / 'frontend-release.json').write_bytes(raw_manifest)
- with zipfile.ZipFile(target, 'x', compression=zipfile.ZIP_DEFLATED) as archive:
- for path in FILES:
- archive.write(ROOT / path, 'payload/' + path)
- archive.writestr('deploy/frontend-release.json', raw_manifest)
- for name in ['README.md', 'database-verification.json', 'browser-acceptance.json', 'module-check.json', 'comparison-regression.json']:
- archive.write(DOCS / name, 'docs/' + name)
- for path in ['test/library-images.test.js', 'scripts/import-product-images.py', 'scripts/test_import_product_images.py', 'scripts/verify-product-images.py']:
- archive.write(ROOT / path, 'verification/' + path)
- receipt = {'ok': True, 'file': str(target.relative_to(ROOT)), 'bytes': target.stat().st_size,
- 'sha256': sha(target.read_bytes()), 'frontendFiles': len(FILES), 'frontendPublished': False,
- 'productionDependenciesRequiringIntegration': [r['path'] for r in observed if r['dependencyOnly'] and not r['productionMatchesLocal']]}
- (DOCS / 'package-receipt.json').write_text(json.dumps(receipt, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
- print(json.dumps(receipt, ensure_ascii=False))
- if __name__ == '__main__':
- main()
|