146 lines
4.6 KiB
Python
Executable File
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()
|