Files
workspace/tools/ava-converter.py

146 lines
4.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""
AVA GeoJSON to KML Converter
Downloads American Viticultural Area (AVA) boundary data from the UC Davis
Library AVA repository and converts all GeoJSON files to KML format using
ogr2ogr (GDAL).
Source: https://github.com/UCDavisLibrary/ava
License: CC0 1.0 Universal (Public Domain)
"""
import argparse
import datetime
import glob
import logging
import os
import shutil
import subprocess
import sys
import tempfile
DEFAULT_OUTPUT = "/home/wdjones/.openclaw/workspace/projects/ava-kmls"
DEFAULT_REPO = "https://github.com/UCDavisLibrary/ava.git"
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
log = logging.getLogger(__name__)
def check_ogr2ogr():
"""Check that ogr2ogr is available."""
if shutil.which("ogr2ogr") is None:
log.error("ogr2ogr not found. Install GDAL:")
log.error(" Ubuntu/Debian: sudo apt-get install gdal-bin")
log.error(" macOS: brew install gdal")
log.error(" Conda: conda install -c conda-forge gdal")
sys.exit(1)
def clone_repo(repo_url, dest):
"""Clone the AVA repo to a temporary directory."""
log.info(f"Cloning {repo_url} ...")
subprocess.run(["git", "clone", "--depth", "1", repo_url, dest],
check=True, capture_output=True, text=True)
log.info("Clone complete.")
def convert_geojson_to_kml(src, dst):
"""Convert a single GeoJSON file to KML via ogr2ogr. Returns True on success."""
result = subprocess.run(
["ogr2ogr", "-f", "KML", dst, src],
capture_output=True, text=True
)
if result.returncode != 0:
log.error(f" FAILED: {result.stderr.strip()}")
return False
return True
def generate_readme(output_dir, ava_names, errors, repo_url):
"""Generate a README.md summarizing the conversion."""
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
lines = [
"# AVA Boundary Data — KML & GeoJSON",
"",
"American Viticultural Area (AVA) boundaries converted from GeoJSON to KML.",
"",
"## Source",
f"- Repository: {repo_url}",
"- Maintainer: UC Davis Library",
"- License: **CC0 1.0 Universal** (Public Domain)",
"",
f"## Generated: {now}",
"",
f"**{len(ava_names)} AVAs converted** ({len(errors)} errors)",
"",
"## Files",
"- `output/kml/` — KML files (one per AVA)",
"- `output/geojson/` — Original GeoJSON source files",
"",
"## AVA List",
"",
]
for name in sorted(ava_names):
lines.append(f"- {name}")
if errors:
lines += ["", "## Conversion Errors", ""]
for e in sorted(errors):
lines.append(f"- {e}")
readme_path = os.path.join(output_dir, "README.md")
with open(readme_path, "w") as f:
f.write("\n".join(lines) + "\n")
log.info(f"README written to {readme_path}")
def main():
parser = argparse.ArgumentParser(description="Convert UC Davis AVA GeoJSON to KML")
parser.add_argument("--output", default=DEFAULT_OUTPUT, help="Output directory")
parser.add_argument("--repo-url", default=DEFAULT_REPO, help="Source git repo URL")
args = parser.parse_args()
check_ogr2ogr()
output_dir = os.path.abspath(args.output)
kml_dir = os.path.join(output_dir, "output", "kml")
geojson_dir = os.path.join(output_dir, "output", "geojson")
os.makedirs(kml_dir, exist_ok=True)
os.makedirs(geojson_dir, exist_ok=True)
with tempfile.TemporaryDirectory() as tmpdir:
repo_dir = os.path.join(tmpdir, "ava")
clone_repo(args.repo_url, repo_dir)
avas_dir = os.path.join(repo_dir, "avas")
if not os.path.isdir(avas_dir):
log.error(f"No 'avas/' directory found in repo at {avas_dir}")
sys.exit(1)
geojson_files = sorted(glob.glob(os.path.join(avas_dir, "*.geojson")))
log.info(f"Found {len(geojson_files)} GeoJSON files")
converted = []
errors = []
for gj in geojson_files:
basename = os.path.splitext(os.path.basename(gj))[0]
kml_out = os.path.join(kml_dir, f"{basename}.kml")
gj_out = os.path.join(geojson_dir, os.path.basename(gj))
log.info(f"Converting: {basename}")
shutil.copy2(gj, gj_out)
if convert_geojson_to_kml(gj, kml_out):
converted.append(basename)
else:
errors.append(basename)
log.info(f"Done: {len(converted)} converted, {len(errors)} errors")
generate_readme(output_dir, converted, errors, args.repo_url)
if __name__ == "__main__":
main()