|
1 | 1 | """A Typer CLI for CPPython interfacing""" |
2 | 2 |
|
| 3 | +from importlib.metadata import entry_points |
3 | 4 | from pathlib import Path |
4 | 5 | from typing import Annotated |
5 | 6 |
|
|
14 | 15 |
|
15 | 16 | app = typer.Typer(no_args_is_help=True) |
16 | 17 |
|
| 18 | +info_app = typer.Typer(no_args_is_help=True, help='Prints project information including plugin configuration, managed files, and templates.') |
| 19 | +app.add_typer(info_app, name='info') |
| 20 | + |
| 21 | +list_app = typer.Typer(no_args_is_help=True, help='List project entities.') |
| 22 | +app.add_typer(list_app, name='list') |
| 23 | + |
17 | 24 |
|
18 | 25 | def get_enabled_project(context: typer.Context) -> Project: |
19 | 26 | """Helper to load and validate an enabled Project from CLI context.""" |
@@ -123,43 +130,62 @@ def main( |
123 | 130 | context.obj = ConsoleConfiguration(project_configuration=project_configuration, interface=interface) |
124 | 131 |
|
125 | 132 |
|
126 | | -@app.command() |
127 | | -def info( |
| 133 | +def _print_plugin_report(role: str, name: str, report: PluginReport) -> None: |
| 134 | + """Print a single plugin's report to the console. |
| 135 | +
|
| 136 | + Args: |
| 137 | + role: The plugin role label (e.g. 'Provider', 'Generator') |
| 138 | + name: The plugin name |
| 139 | + report: The plugin report to display |
| 140 | + """ |
| 141 | + print(f'\n[bold]{role}:[/bold] {name}') |
| 142 | + |
| 143 | + if report.configuration: |
| 144 | + print(' [bold]Configuration:[/bold]') |
| 145 | + for key, value in report.configuration.items(): |
| 146 | + print(f' {key}: {value}') |
| 147 | + |
| 148 | + if report.managed_files: |
| 149 | + print(' [bold]Managed files:[/bold]') |
| 150 | + for file_path in report.managed_files: |
| 151 | + print(f' {file_path}') |
| 152 | + |
| 153 | + if report.template_files: |
| 154 | + print(' [bold]Templates:[/bold]') |
| 155 | + for filename, content in report.template_files.items(): |
| 156 | + print(f' [cyan]{filename}[/cyan]') |
| 157 | + print() |
| 158 | + print(Syntax(content, 'python', theme='monokai', line_numbers=True)) |
| 159 | + |
| 160 | + |
| 161 | +@info_app.command() |
| 162 | +def info_provider( |
128 | 163 | context: typer.Context, |
129 | 164 | ) -> None: |
130 | | - """Prints project information including plugin configuration, managed files, and templates.""" |
| 165 | + """Show provider plugin information.""" |
131 | 166 | project = get_enabled_project(context) |
132 | 167 | project_info = project.info() |
133 | 168 |
|
134 | | - if not project_info: |
| 169 | + entry = project_info.get('provider') |
| 170 | + if entry is None: |
135 | 171 | return |
136 | 172 |
|
137 | | - for role in ('provider', 'generator'): |
138 | | - entry = project_info.get(role) |
139 | | - if entry is None: |
140 | | - continue |
141 | | - |
142 | | - name: str = entry['name'] |
143 | | - report: PluginReport = entry['report'] |
| 173 | + _print_plugin_report('Provider', entry['name'], entry['report']) |
144 | 174 |
|
145 | | - print(f'\n[bold]{role.title()}:[/bold] {name}') |
146 | 175 |
|
147 | | - if report.configuration: |
148 | | - print(' [bold]Configuration:[/bold]') |
149 | | - for key, value in report.configuration.items(): |
150 | | - print(f' {key}: {value}') |
| 176 | +@info_app.command() |
| 177 | +def info_generator( |
| 178 | + context: typer.Context, |
| 179 | +) -> None: |
| 180 | + """Show generator plugin information.""" |
| 181 | + project = get_enabled_project(context) |
| 182 | + project_info = project.info() |
151 | 183 |
|
152 | | - if report.managed_files: |
153 | | - print(' [bold]Managed files:[/bold]') |
154 | | - for path in report.managed_files: |
155 | | - print(f' {path}') |
| 184 | + entry = project_info.get('generator') |
| 185 | + if entry is None: |
| 186 | + return |
156 | 187 |
|
157 | | - if report.template_files: |
158 | | - print(' [bold]Templates:[/bold]') |
159 | | - for filename, content in report.template_files.items(): |
160 | | - print(f' [cyan]{filename}[/cyan]') |
161 | | - print() |
162 | | - print(Syntax(content, 'python', theme='monokai', line_numbers=True)) |
| 188 | + _print_plugin_report('Generator', entry['name'], entry['report']) |
163 | 189 |
|
164 | 190 |
|
165 | 191 | @app.command() |
@@ -218,11 +244,40 @@ def update( |
218 | 244 | project.update(groups=group_list) |
219 | 245 |
|
220 | 246 |
|
221 | | -@app.command(name='list') |
222 | | -def list_command( |
223 | | - _: typer.Context, |
| 247 | +@list_app.command() |
| 248 | +def plugins() -> None: |
| 249 | + """List all installed CPPython plugins.""" |
| 250 | + groups = { |
| 251 | + 'Generators': 'cppython.generator', |
| 252 | + 'Providers': 'cppython.provider', |
| 253 | + 'SCM': 'cppython.scm', |
| 254 | + } |
| 255 | + |
| 256 | + for label, group in groups.items(): |
| 257 | + entries = entry_points(group=group) |
| 258 | + print(f'\n[bold]{label}:[/bold]') |
| 259 | + if not entries: |
| 260 | + print(' (none installed)') |
| 261 | + else: |
| 262 | + for ep in sorted(entries, key=lambda e: e.name): |
| 263 | + print(f' {ep.name}') |
| 264 | + |
| 265 | + |
| 266 | +@list_app.command() |
| 267 | +def targets( |
| 268 | + context: typer.Context, |
224 | 269 | ) -> None: |
225 | | - """Prints project information""" |
| 270 | + """List discovered build targets.""" |
| 271 | + project = get_enabled_project(context) |
| 272 | + target_list = project.list_targets() |
| 273 | + |
| 274 | + if not target_list: |
| 275 | + print('[dim]No targets found. Have you run install and build?[/dim]') |
| 276 | + return |
| 277 | + |
| 278 | + print('\n[bold]Targets:[/bold]') |
| 279 | + for target_name in sorted(target_list): |
| 280 | + print(f' {target_name}') |
226 | 281 |
|
227 | 282 |
|
228 | 283 | @app.command() |
|
0 commit comments