|
6 | 6 | import sys |
7 | 7 | from pathlib import Path |
8 | 8 |
|
| 9 | +import click |
9 | 10 | import yaml |
10 | 11 |
|
11 | 12 | from .common import deep_merge |
12 | 13 | from .render import create_env |
13 | 14 |
|
14 | | -logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") |
| 15 | +logging.basicConfig( |
| 16 | + level=logging.INFO, |
| 17 | + format="%(levelname)s: %(message)s" |
| 18 | +) |
15 | 19 | logger = logging.getLogger(__name__) |
16 | 20 |
|
| 21 | +@click.group() |
| 22 | +@click.option( |
| 23 | + "-v", "--verbose", is_flag=True, |
| 24 | + help="Show debug information" |
| 25 | +) |
| 26 | +@click.option( |
| 27 | + "-q", "--quiet", is_flag=True, |
| 28 | + help="Show errors only" |
| 29 | +) |
| 30 | +def cli(verbose, quiet): |
| 31 | + """PDF document generator from YAML-configured SVG templates.""" |
| 32 | + if quiet: |
| 33 | + logging.getLogger().setLevel(logging.ERROR) |
| 34 | + elif verbose: |
| 35 | + logging.getLogger().setLevel(logging.DEBUG) |
| 36 | + else: |
| 37 | + logging.getLogger().setLevel(logging.INFO) |
| 38 | + |
| 39 | +@cli.command() |
| 40 | +@click.argument("config_path", type=click.Path(exists=True, path_type=Path)) |
| 41 | +def bake(config_path): |
| 42 | + """Generate PDF documents from YAML-configured SVG templates. |
| 43 | +
|
| 44 | + CONFIG_PATH is the path to your configuration YAML file. |
| 45 | + """ |
| 46 | + config = _load_config(config_path) |
| 47 | + base_dir = config_path.parent |
| 48 | + document_paths = _get_document_paths(base_dir, config.get("documents", [])) |
| 49 | + build_dir, dist_dir = _setup_output_directories(base_dir) |
17 | 50 |
|
18 | | -def _get_config_path(config_path=None): |
19 | | - """Get and validate the configuration file path.""" |
20 | | - if config_path is None: |
21 | | - if len(sys.argv) < 2: |
22 | | - logger.error("Config file path is required") |
23 | | - logger.error("Usage: python -m pdfbaker <config_file_path>") |
24 | | - return None |
25 | | - config_path = sys.argv[1] |
26 | | - |
27 | | - config_path = Path(config_path).resolve() |
28 | | - if not config_path.exists(): |
29 | | - logger.error("Configuration file not found: %s", config_path) |
30 | | - return None |
| 51 | + for doc_name, doc_path in document_paths.items(): |
| 52 | + _process_document(doc_name, doc_path, config, build_dir, dist_dir) |
31 | 53 |
|
32 | | - return config_path |
| 54 | + logger.info("Done.") |
| 55 | + return 0 |
33 | 56 |
|
34 | 57 |
|
35 | 58 | def _load_config(config_path): |
@@ -84,32 +107,6 @@ def _validate_document_path(doc_name, doc_path): |
84 | 107 | return bake_path, config_yml_path |
85 | 108 |
|
86 | 109 |
|
87 | | -def _load_document_bake_module(doc_name, bake_path): |
88 | | - """Load the document's bake.py module.""" |
89 | | - doc_bake = importlib.util.spec_from_file_location( |
90 | | - f"documents.{doc_name}.bake", bake_path |
91 | | - ) |
92 | | - module = importlib.util.module_from_spec(doc_bake) |
93 | | - doc_bake.loader.exec_module(module) |
94 | | - return module |
95 | | - |
96 | | - |
97 | | -def _setup_document_output_directories(build_dir, dist_dir, doc_name): |
98 | | - """Set up and clean document-specific build and dist directories.""" |
99 | | - doc_build_dir = build_dir / doc_name |
100 | | - doc_dist_dir = dist_dir / doc_name |
101 | | - os.makedirs(doc_build_dir, exist_ok=True) |
102 | | - os.makedirs(doc_dist_dir, exist_ok=True) |
103 | | - |
104 | | - for dir_path in [doc_build_dir, doc_dist_dir]: |
105 | | - for file in os.listdir(dir_path): |
106 | | - file_path = dir_path / file |
107 | | - if os.path.isfile(file_path): |
108 | | - os.remove(file_path) |
109 | | - |
110 | | - return doc_build_dir, doc_dist_dir |
111 | | - |
112 | | - |
113 | 110 | def _process_document(doc_name, doc_path, config, build_dir, dist_dir): |
114 | 111 | """Process an individual document.""" |
115 | 112 | validation_result = _validate_document_path(doc_name, doc_path) |
@@ -142,23 +139,31 @@ def _process_document(doc_name, doc_path, config, build_dir, dist_dir): |
142 | 139 | ) |
143 | 140 |
|
144 | 141 |
|
145 | | -def main(config_path=None): |
146 | | - """Main function for the document generator.""" |
147 | | - config_path = _get_config_path(config_path) |
148 | | - if config_path is None: |
149 | | - return 1 |
| 142 | +def _load_document_bake_module(doc_name, bake_path): |
| 143 | + """Load the document's bake.py module.""" |
| 144 | + doc_bake = importlib.util.spec_from_file_location( |
| 145 | + f"documents.{doc_name}.bake", bake_path |
| 146 | + ) |
| 147 | + module = importlib.util.module_from_spec(doc_bake) |
| 148 | + doc_bake.loader.exec_module(module) |
| 149 | + return module |
150 | 150 |
|
151 | | - config = _load_config(config_path) |
152 | | - base_dir = config_path.parent |
153 | | - document_paths = _get_document_paths(base_dir, config.get("documents", [])) |
154 | | - build_dir, dist_dir = _setup_output_directories(base_dir) |
155 | 151 |
|
156 | | - for doc_name, doc_path in document_paths.items(): |
157 | | - _process_document(doc_name, doc_path, config, build_dir, dist_dir) |
| 152 | +def _setup_document_output_directories(build_dir, dist_dir, doc_name): |
| 153 | + """Set up and clean document-specific build and dist directories.""" |
| 154 | + doc_build_dir = build_dir / doc_name |
| 155 | + doc_dist_dir = dist_dir / doc_name |
| 156 | + os.makedirs(doc_build_dir, exist_ok=True) |
| 157 | + os.makedirs(doc_dist_dir, exist_ok=True) |
158 | 158 |
|
159 | | - logger.info("Done.") |
160 | | - return 0 |
| 159 | + for dir_path in [doc_build_dir, doc_dist_dir]: |
| 160 | + for file in os.listdir(dir_path): |
| 161 | + file_path = dir_path / file |
| 162 | + if os.path.isfile(file_path): |
| 163 | + os.remove(file_path) |
| 164 | + |
| 165 | + return doc_build_dir, doc_dist_dir |
161 | 166 |
|
162 | 167 |
|
163 | 168 | if __name__ == "__main__": |
164 | | - sys.exit(main()) |
| 169 | + sys.exit(cli()) |
0 commit comments