Files
djinit/src/djinit/cli.py
T

159 lines
5.5 KiB
Python

import logging
from typing import Annotated, Optional
import typer
from rich.panel import Panel
from rich.text import Text
from djinit.creators.app import AppCreator
from djinit.creators.setup import SetupCreator
from djinit.ui.console import UIColors, UIFormatter, console
from djinit.ui.input import get_user_input
from djinit.utils.secretkey import display_secret_keys, generate_multiple_keys
from djinit.utils.validators import validate_app_name
# Configure logger
logger = logging.getLogger(__name__)
app = typer.Typer(
help="djinit - A CLI tool to set up Django projects with best practices.",
add_completion=False,
no_args_is_help=False,
)
def version_callback(value: bool):
if value:
from importlib.metadata import version
try:
typer.echo(f"djinit v{version('djinitx')}")
except Exception:
typer.echo("djinit (version unknown)")
raise typer.Exit()
@app.callback(invoke_without_command=True)
def main(
ctx: typer.Context,
version: Annotated[
Optional[bool],
typer.Option("--version", "-v", callback=version_callback, is_eager=True, help="Show the version and exit."),
] = None,
):
"""
djinit: Django Project Initializer
"""
if ctx.invoked_subcommand is None:
setup()
@app.command("secret")
def secret(
count: Annotated[int, typer.Option("--count", "-c", help="Number of keys to generate")] = 3,
length: Annotated[int, typer.Option("--length", "-l", help="Length of each secret key")] = 50,
):
"""
Generate Django secret keys.
"""
keys = generate_multiple_keys(count, length)
UIFormatter.print_info("")
display_secret_keys(keys)
instructions = Text()
instructions.append("📋 Usage Instructions:\n", style=UIColors.ACCENT)
instructions.append("1. Copy the appropriate secret key for your environment\n")
instructions.append("2. Add it to your .env file:\n")
instructions.append(" SECRET_KEY=your_secret_key_here\n", style=UIColors.CODE)
instructions.append("3. Or set it as an environment variable:\n")
instructions.append(" export SECRET_KEY=your_secret_key_here\n", style=UIColors.CODE)
instructions.append("4. Never commit secret keys to version control!\n", style=UIColors.WARNING)
console.print(Panel(instructions, title="💡 How to Use", border_style="blue"))
console.print()
@app.command("app")
def create_app(app_names: Annotated[list[str], typer.Argument(help="Name(s) of the Django app(s) to create")]):
"""
Create one or more Django apps.
"""
UIFormatter.print_info("")
UIFormatter.print_header("Django App Creation")
UIFormatter.print_info("")
# Process app names (handle commma separation if passed as single arg)
processed_names = []
for name in app_names:
parts = [p.strip() for p in name.split(",") if p.strip()]
processed_names.extend(parts)
processed_names = list(dict.fromkeys(processed_names)) # Dedup
if not processed_names:
UIFormatter.print_error("App name cannot be empty")
raise typer.Exit(1)
for name in processed_names:
is_valid, error_msg = validate_app_name(name)
if not is_valid:
UIFormatter.print_error(f"Invalid app name '{name}': {error_msg}")
raise typer.Exit(1)
any_failure = False
for name in processed_names:
creator = AppCreator(name)
success = creator.create_app()
if not success:
UIFormatter.print_error(f"Failed to create Django app '{name}'")
any_failure = True
break # Stop on failure? Or continue? Original code broke loop on failure.
if any_failure:
raise typer.Exit(1)
instructions = Text()
instructions.append("🚀 Next Steps:\n", style=UIColors.ACCENT)
instructions.append("1. The app(s) have been added to INSTALLED_APPS in settings/base.py\n")
instructions.append("2. Create your models in each app's models.py\n")
instructions.append("3. Run migrations: just makemigrations\n")
instructions.append("4. Apply migrations: just migrate\n")
instructions.append("5. Create views, serializers and routes(URLs) for your app(s)\n")
console.print(Panel(instructions, title="💡 What's Next", border_style="green"))
UIFormatter.print_info("")
@app.command("setup")
def setup():
"""
Interactively set up a new Django project.
"""
UIFormatter.print_header("Django Project Setup")
project_dir, project_name, primary_app, app_names, metadata = get_user_input()
orchestrator = SetupCreator(project_dir, project_name, primary_app, app_names, metadata)
success = orchestrator.create()
if success:
UIFormatter.print_info("")
UIFormatter.print_header("Setup Complete!")
console.print(f"[bold green]Project '{project_name}' has been successfully created![/bold green]")
instructions = Text()
instructions.append("🚀 Next Steps:\n", style=UIColors.ACCENT)
instructions.append(f"1. cd {project_dir}\n")
instructions.append("2. Install dependencies: pip install -r requirements.txt\n")
instructions.append("3. Run migrations: just migrate (or python manage.py migrate)\n")
instructions.append("4. Start server: just run (or python manage.py runserver)\n")
console.print(Panel(instructions, title="Get Started", border_style="green"))
else:
UIFormatter.print_error("Project setup failed. Please check the logs above.")
raise typer.Exit(1)
if __name__ == "__main__":
app()