|
1 | 1 | """ |
2 | | -Module that contains the command line app. |
| 2 | +Command line interface for OMI. |
3 | 3 |
|
4 | | -Why does this file exist, and why not put this in __main__? |
| 4 | +This CLI only supports the split-files layout: |
| 5 | +- datasets/<dataset_id>.dataset.yaml |
| 6 | +- datasets/<dataset_id>.template.yaml (optional) |
| 7 | +- resources/<dataset_id>/*.resource.yaml |
| 8 | +(optionally wired via metadata_index.yaml) |
5 | 9 |
|
6 | | - You might be tempted to import things from __main__ later, but that will cause |
7 | | - problems: the code will get executed twice: |
| 10 | +Usage: |
| 11 | +omi assemble \ |
| 12 | + --base-dir ./metadata \ |
| 13 | + --dataset-id powerplants \ |
| 14 | + --output-file ./out/powerplants.json \ |
| 15 | + --index-file ./metadata/metadata_index.yaml # optional |
8 | 16 |
|
9 | | - - When you run `python -m omi` python will execute |
10 | | - ``__main__.py`` as a script. That means there won't be any |
11 | | - ``omi.__main__`` in ``sys.modules``. |
12 | | - - When you import __main__ it will get executed again (as a module) because |
13 | | - there's no ``omi.__main__`` in ``sys.modules``. |
14 | | -
|
15 | | - Also see (1) from http://click.pocoo.org/5/setuptools/#setuptools-integration |
16 | 17 | """ |
17 | 18 |
|
| 19 | +from __future__ import annotations |
| 20 | + |
| 21 | +from pathlib import Path |
| 22 | +from typing import Optional |
| 23 | + |
18 | 24 | import click |
19 | 25 |
|
| 26 | +from omi.creation.creator import OEMetadataCreator |
| 27 | +from omi.creation.init import init_dataset, init_resources_from_files |
| 28 | +from omi.creation.utils import apply_template_to_resources, load_parts |
| 29 | + |
20 | 30 |
|
21 | 31 | @click.group() |
22 | 32 | def grp() -> None: |
23 | | - """Init click group.""" |
| 33 | + """OMI CLI.""" |
| 34 | + |
| 35 | + |
| 36 | +@grp.command("assemble") |
| 37 | +@click.option( |
| 38 | + "--base-dir", |
| 39 | + required=True, |
| 40 | + type=click.Path(file_okay=False, path_type=Path), |
| 41 | + help="Root directory containing 'datasets/' and 'resources/'.", |
| 42 | +) |
| 43 | +@click.option("--dataset-id", required=True, help="Logical dataset id (e.g. 'powerplants').") |
| 44 | +@click.option( |
| 45 | + "--output-file", |
| 46 | + required=True, |
| 47 | + type=click.Path(dir_okay=False, path_type=Path), |
| 48 | + help="Path to write the generated OEMetadata JSON.", |
| 49 | +) |
| 50 | +@click.option( |
| 51 | + "--index-file", |
| 52 | + default=None, |
| 53 | + type=click.Path(dir_okay=False, path_type=Path), |
| 54 | + help="Optional metadata index YAML for explicit mapping.", |
| 55 | +) |
| 56 | +def assemble_cmd(base_dir: Path, dataset_id: str, output_file: Path, index_file: Optional[Path]) -> None: |
| 57 | + """Assemble OEMetadata from split YAML files and write JSON to OUTPUT_FILE.""" |
| 58 | + # Load pieces |
| 59 | + version, dataset, resources, template = load_parts(base_dir, dataset_id, index_file=index_file) |
| 60 | + merged_resources = apply_template_to_resources(resources, template) |
| 61 | + |
| 62 | + # Build & save with the correct spec version |
| 63 | + creator = OEMetadataCreator(oem_version=version) |
| 64 | + creator.save(dataset, merged_resources, output_file, ensure_ascii=False, indent=2) |
| 65 | + |
| 66 | + |
| 67 | +@click.group() |
| 68 | +def init() -> None: |
| 69 | + """Scaffold OEMetadata split-files layout.""" |
| 70 | + |
| 71 | + |
| 72 | +@init.command("dataset") |
| 73 | +@click.argument("base_dir", type=click.Path(file_okay=False, path_type=Path)) |
| 74 | +@click.argument("dataset_id") |
| 75 | +@click.option("--oem-version", default="OEMetadata-2.0", show_default=True) |
| 76 | +@click.option("--resource", "resources", multiple=True, help="Initial resource names (repeatable).") |
| 77 | +@click.option("--overwrite", is_flag=True, help="Overwrite existing files.") |
| 78 | +def init_dataset_cmd( |
| 79 | + base_dir: Path, |
| 80 | + dataset_id: str, |
| 81 | + oem_version: str, |
| 82 | + resources: tuple[str, ...], |
| 83 | + *, |
| 84 | + overwrite: bool, |
| 85 | +) -> None: |
| 86 | + """Initialize a split-files OEMetadata dataset layout under BASE_DIR.""" |
| 87 | + res = init_dataset(base_dir, dataset_id, oem_version=oem_version, resources=resources, overwrite=overwrite) |
| 88 | + click.echo(f"dataset: {res.dataset_yaml}") |
| 89 | + click.echo(f"template: {res.template_yaml}") |
| 90 | + for p in res.resource_yamls: |
| 91 | + click.echo(f"resource: {p}") |
| 92 | + |
| 93 | + |
| 94 | +@init.command("resources") |
| 95 | +@click.argument("base_dir", type=click.Path(file_okay=False, path_type=Path)) |
| 96 | +@click.argument("dataset_id") |
| 97 | +@click.argument("files", nargs=-1, type=click.Path(exists=True, dir_okay=False, path_type=Path)) |
| 98 | +@click.option("--oem-version", default="OEMetadata-2.0", show_default=True) |
| 99 | +@click.option("--overwrite", is_flag=True, help="Overwrite existing files.") |
| 100 | +def init_resources_cmd( |
| 101 | + base_dir: Path, |
| 102 | + dataset_id: str, |
| 103 | + files: tuple[Path, ...], |
| 104 | + oem_version: str, |
| 105 | + *, |
| 106 | + overwrite: bool, |
| 107 | +) -> None: |
| 108 | + """Create resource YAML files for DATASET_ID from the given FILES.""" |
| 109 | + outs = init_resources_from_files(base_dir, dataset_id, files, oem_version=oem_version, overwrite=overwrite) |
| 110 | + for p in outs: |
| 111 | + click.echo(p) |
24 | 112 |
|
25 | 113 |
|
26 | | -cli = click.CommandCollection(sources=[grp]) |
| 114 | +# Keep CommandCollection for backwards compatibility with your entry point |
| 115 | +cli = click.CommandCollection(sources=[grp, init]) |
27 | 116 |
|
28 | 117 |
|
29 | 118 | def main() -> None: |
|
0 commit comments