#!/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()