Release 0.58.0 includes the Earth high-precision boundary PMTiles/MVT pipeline, standardized Earth boundary source collectors, China POV boundary configuration templates, and removal of the legacy low-precision GeoJSON fallback. It also adds Earth news target-location queueing/archive support, fixes datasource task status visibility, documents the Earth surface depth-spacing rules that prevent far-zoom z-fighting snow/black blocks, and updates bilingual operations/developer docs.
75 lines
2.7 KiB
Python
75 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Check whether the Earth boundary pipeline is ready for PMTiles production.
|
|
|
|
This is intentionally a verifier, not a fake builder. It fails when the repo is
|
|
still using seed data or when the external MVT/PMTiles toolchain is absent.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import shutil
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
DEFAULT_CONFIG = Path("config/earth-boundary-sources.example.json")
|
|
DEFAULT_ARTIFACT = Path("frontend/public/earth/data/boundaries/earth-boundaries-china-pov-v1.pmtiles")
|
|
|
|
|
|
def load_json(path: Path) -> dict[str, Any]:
|
|
with path.open("r", encoding="utf-8") as f:
|
|
payload = json.load(f)
|
|
if not isinstance(payload, dict):
|
|
raise ValueError(f"{path} must contain a JSON object")
|
|
return payload
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--config", type=Path, default=DEFAULT_CONFIG)
|
|
parser.add_argument("--artifact", type=Path, default=DEFAULT_ARTIFACT)
|
|
args = parser.parse_args()
|
|
|
|
config = load_json(args.config)
|
|
policy = config.get("policy") or {}
|
|
collector_configs = config.get("collectorConfigs") or {}
|
|
failures: list[str] = []
|
|
warnings: list[str] = []
|
|
|
|
if policy.get("productionTileFormat") != "pmtiles+mvt":
|
|
failures.append("policy.productionTileFormat must be pmtiles+mvt")
|
|
if not policy.get("povPolicyPath"):
|
|
failures.append("policy.povPolicyPath is required")
|
|
required_kinds = {"admin0-boundaries", "coastline", "claim-lines"}
|
|
configured_kinds = {str(source.get("sourceKind")) for source in collector_configs.values()}
|
|
missing_kinds = sorted(required_kinds - configured_kinds)
|
|
if missing_kinds:
|
|
failures.append(f"missing production source kind(s): {', '.join(missing_kinds)}")
|
|
for collector_name, source in collector_configs.items():
|
|
endpoint = str(source.get("endpoint") or "")
|
|
if not endpoint or endpoint.startswith("https://example.com/"):
|
|
failures.append(f"{collector_name} endpoint must be configured to an audited production source")
|
|
|
|
for tool in ("tippecanoe", "pmtiles"):
|
|
if shutil.which(tool) is None:
|
|
failures.append(f"external tool not found in PATH: {tool}")
|
|
|
|
if not args.artifact.exists():
|
|
warnings.append(f"PMTiles artifact does not exist yet: {args.artifact}")
|
|
|
|
result = {
|
|
"ready": not failures,
|
|
"failures": failures,
|
|
"warnings": warnings,
|
|
"artifact": str(args.artifact),
|
|
}
|
|
print(json.dumps(result, ensure_ascii=False, sort_keys=True))
|
|
return 0 if not failures else 2
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|