Initial upload: PatternForge CLI tool with pattern detection and boilerplate generation
This commit is contained in:
155
src/patternforge/cli.py
Normal file
155
src/patternforge/cli.py
Normal file
@@ -0,0 +1,155 @@
|
||||
|
||||
import click
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from patternforge.analyzer import CodeAnalyzer
|
||||
from patternforge.config import Config
|
||||
from patternforge.generator import BoilerplateGenerator
|
||||
from patternforge.template import TemplateManager
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.option("--config", "-c", type=click.Path(exists=True), help="Config file path")
|
||||
@click.pass_context
|
||||
def main(ctx: click.Context, config: str | None) -> None:
|
||||
ctx.ensure_object(dict)
|
||||
cfg = Config.load(config) if config else Config.load()
|
||||
ctx.obj["config"] = cfg
|
||||
|
||||
|
||||
@main.command("analyze")
|
||||
@click.argument("path", type=click.Path(exists=True, file_okay=True, dir_okay=True))
|
||||
@click.option("--language", "-l", required=True, help="Programming language")
|
||||
@click.option("--output", "-o", required=True, type=click.Path(), help="Output file for patterns")
|
||||
@click.option("--recursive/--no-recursive", default=True, help="Analyze directories recursively")
|
||||
@click.pass_context
|
||||
def analyze(ctx: click.Context, path: str, language: str, output: str, recursive: bool) -> None:
|
||||
"""Analyze a codebase and extract patterns."""
|
||||
config: Config = ctx.obj["config"]
|
||||
console.print(f"Analyzing [cyan]{path}[/] for [cyan]{language}[/] patterns...")
|
||||
analyzer = CodeAnalyzer(language, config)
|
||||
patterns = analyzer.analyze(path, recursive)
|
||||
analyzer.save_patterns(output, patterns)
|
||||
console.print(f"Patterns saved to [green]{output}[/]")
|
||||
console.print(f"Detected: {patterns.get('summary', {})}")
|
||||
|
||||
|
||||
@click.group()
|
||||
def template() -> None:
|
||||
"""Template management commands."""
|
||||
pass
|
||||
|
||||
|
||||
@template.command("create")
|
||||
@click.argument("name", type=str)
|
||||
@click.option("--pattern", "-p", type=click.Path(exists=True), required=True, help="Pattern file")
|
||||
@click.option("--template", "-t", type=click.Path(exists=True), help="Custom Jinja2 template file")
|
||||
@click.option("--description", "-d", type=str, default="", help="Template description")
|
||||
@click.pass_context
|
||||
def template_create(
|
||||
ctx: click.Context, name: str, pattern: str, template: str | None, description: str
|
||||
) -> None:
|
||||
"""Create a new template from detected patterns."""
|
||||
config: Config = ctx.obj["config"]
|
||||
manager = TemplateManager(config)
|
||||
manager.create_template(name, pattern, template, description)
|
||||
console.print(f"Template [green]{name}[/] created successfully")
|
||||
|
||||
|
||||
@template.command("list")
|
||||
@click.pass_context
|
||||
def template_list(ctx: click.Context) -> None:
|
||||
"""List all available templates."""
|
||||
config: Config = ctx.obj["config"]
|
||||
manager = TemplateManager(config)
|
||||
templates = manager.list_templates()
|
||||
if not templates:
|
||||
console.print("[yellow]No templates found[/]")
|
||||
return
|
||||
table = Table(title="Templates")
|
||||
table.add_column("Name")
|
||||
table.add_column("Description")
|
||||
table.add_column("Created")
|
||||
for t in templates:
|
||||
table.add_row(t["name"], t.get("description", ""), t.get("created", ""))
|
||||
console.print(table)
|
||||
|
||||
|
||||
@template.command("remove")
|
||||
@click.argument("name", type=str)
|
||||
@click.option("--force/--no-force", default=False, help="Skip confirmation")
|
||||
@click.pass_context
|
||||
def template_remove(ctx: click.Context, name: str, force: bool) -> None:
|
||||
"""Remove a template."""
|
||||
config: Config = ctx.obj["config"]
|
||||
if not force:
|
||||
if not click.confirm(f"Remove template [cyan]{name}[/]?"):
|
||||
return
|
||||
manager = TemplateManager(config)
|
||||
manager.remove_template(name)
|
||||
console.print(f"Template [green]{name}[/] removed")
|
||||
|
||||
|
||||
main.add_command(template, "template")
|
||||
|
||||
|
||||
@main.command("generate")
|
||||
@click.argument("template", type=str)
|
||||
@click.option("--output", "-o", type=click.Path(), required=True, help="Output directory")
|
||||
@click.option(
|
||||
"--data", "-d", type=click.Path(exists=True), help="JSON data file for template variables"
|
||||
)
|
||||
@click.option("--name", "-n", help="Name for the generated files")
|
||||
@click.pass_context
|
||||
def generate(
|
||||
ctx: click.Context, template: str, output: str, data: str | None, name: str | None
|
||||
) -> None:
|
||||
"""Generate boilerplate from a template."""
|
||||
config: Config = ctx.obj["config"]
|
||||
generator = BoilerplateGenerator(config)
|
||||
generator.generate(template, output, data, name)
|
||||
console.print(f"Boilerplate generated at [green]{output}[/]")
|
||||
|
||||
|
||||
@main.command("export")
|
||||
@click.argument("source", type=click.Path(exists=True))
|
||||
@click.argument("destination", type=click.Path())
|
||||
@click.option("--format", "-f", type=click.Choice(["yaml", "json"]), default="yaml")
|
||||
@click.pass_context
|
||||
def export(ctx: click.Context, source: str, destination: str, format: str) -> None:
|
||||
"""Export patterns or templates for team sharing."""
|
||||
config: Config = ctx.obj["config"]
|
||||
manager = TemplateManager(config)
|
||||
manager.export_patterns(source, destination, format)
|
||||
console.print(f"Exported to [green]{destination}[/]")
|
||||
|
||||
|
||||
@main.command("import")
|
||||
@click.argument("source", type=click.Path(exists=True))
|
||||
@click.pass_context
|
||||
def import_patterns(ctx: click.Context, source: str) -> None:
|
||||
"""Import patterns from team repository."""
|
||||
config: Config = ctx.obj["config"]
|
||||
manager = TemplateManager(config)
|
||||
manager.import_patterns(source)
|
||||
console.print(f"Imported from [green]{source}[/]")
|
||||
|
||||
|
||||
@main.command("config")
|
||||
@click.pass_context
|
||||
def show_config(ctx: click.Context) -> None:
|
||||
"""Show current configuration."""
|
||||
config: Config = ctx.obj["config"]
|
||||
table = Table(title="Configuration")
|
||||
table.add_column("Setting")
|
||||
table.add_column("Value")
|
||||
for key, value in config.to_dict().items():
|
||||
table.add_row(key, str(value))
|
||||
console.print(table)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user