Coverage for lunar_toolkit/cli/build_db.py: 37%
41 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-19 02:58 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-19 02:58 +0000
1"""build-db - download CUMINDEX files and build local Parquet databases."""
3import argparse
4import sys
5from pathlib import Path
7from ..constants import DATASETS, DEFAULT_CACHE_DIR
9COMMAND = "build-db"
12def add_parser(sub: argparse._SubParsersAction) -> None:
13 p = sub.add_parser(
14 COMMAND,
15 help="Build the local Parquet index database(s).",
16 formatter_class=argparse.RawDescriptionHelpFormatter,
17 epilog="""
18Examples
19--------
20 lunar build-db # EDR only (default)
21 lunar build-db edr cdr # EDR and CDR
22 lunar build-db --all # EDR, CDR, and RDR
23 lunar build-db edr --force # rebuild even if exists
24 lunar build-db edr --update # append PDS volumes newer than the built release
25 lunar build-db edr --release LROLRC_0066C --volume-only # one volume (~20k rows)
26""",
27 )
28 p.add_argument(
29 "datasets",
30 nargs="*",
31 metavar="DATASET",
32 help="Datasets to build: edr, cdr, rdr (default: edr if none given).",
33 )
34 p.add_argument(
35 "--all",
36 action="store_true",
37 help="Build all three datasets: edr, cdr, rdr.",
38 )
39 p.add_argument(
40 "--force",
41 action="store_true",
42 help="Rebuild even if the Parquet already exists.",
43 )
44 p.add_argument(
45 "--update",
46 action="store_true",
47 help="Append newer per-volume INDEX.TABs to an existing database.",
48 )
49 p.add_argument(
50 "--release",
51 default=None,
52 metavar="VOLUME",
53 help="Build from this PDS volume, e.g. LROLRC_0066C (default: newest on the server).",
54 )
55 p.add_argument(
56 "--volume-only",
57 action="store_true",
58 help="Use the volume's own INDEX/INDEX.TAB instead of the cumulative CUMINDEX.TAB.",
59 )
60 p.add_argument(
61 "--wkt",
62 action="store_true",
63 help="Also store an FP_WKT footprint polygon column.",
64 )
65 p.add_argument(
66 "--memory-limit",
67 default="4GB",
68 metavar="SIZE",
69 help="DuckDB memory limit; sorting spills to disk beyond it (default: 4GB).",
70 )
71 p.add_argument(
72 "--threads",
73 type=int,
74 default=None,
75 metavar="N",
76 help="DuckDB worker threads (default: all cores).",
77 )
78 p.add_argument(
79 "--data-dir",
80 type=Path,
81 default=None,
82 metavar="DIR",
83 help="Where to write Parquet files (default: LUNAR_DATA_DIR or the user data dir).",
84 )
85 p.add_argument(
86 "--cache-dir",
87 default=str(DEFAULT_CACHE_DIR),
88 metavar="DIR",
89 help=f"Where to cache raw TAB/LBL downloads (default: {DEFAULT_CACHE_DIR}).",
90 )
93def run(args: argparse.Namespace) -> int:
94 from ..lroc.cumindex import CumIndex
96 if args.all:
97 datasets = list(DATASETS)
98 elif args.datasets:
99 invalid = [d for d in args.datasets if d not in DATASETS]
100 if invalid:
101 print(
102 f"Unknown dataset(s): {', '.join(invalid)}. Choose from: {', '.join(DATASETS)}",
103 file=sys.stderr,
104 )
105 return 1
106 datasets = args.datasets
107 else:
108 datasets = ["edr"]
110 cache_dir = Path(args.cache_dir)
112 for dataset in datasets:
113 ds = DATASETS[dataset]
114 print(f"\n{ds['label']}")
115 ci = CumIndex(dataset=dataset, data_dir=args.data_dir, cache_dir=cache_dir)
116 print(f" Parquet : {ci.parquet_path}")
117 print(f" Cache : {cache_dir}")
118 if args.update and ci.parquet_path.exists() and not args.force:
119 ci.update_db(memory_limit=args.memory_limit, threads=args.threads)
120 continue
121 ci.build_db(
122 force=args.force,
123 release=args.release,
124 volume_only=args.volume_only,
125 memory_limit=args.memory_limit,
126 threads=args.threads,
127 wkt=args.wkt,
128 )
130 return 0