139 lines
4.4 KiB
Python
139 lines
4.4 KiB
Python
import logging
|
|
import os
|
|
from enum import Enum
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
import typer
|
|
from rich.logging import RichHandler
|
|
|
|
from poetry_slam.build_tool import BuildTool
|
|
from poetry_slam.templates import TEMPLATE_ROOT, templates
|
|
|
|
app = typer.Typer()
|
|
app_state = dict()
|
|
|
|
logger = logging.getLogger("slam.cli")
|
|
|
|
Template = Enum("Template", ((name, name) for name in templates()))
|
|
|
|
|
|
@app.callback(invoke_without_command=True)
|
|
def main(
|
|
context: typer.Context,
|
|
verbose: bool = typer.Option(False, help="Enable verbose output."),
|
|
log_level: str = typer.Option("error", help=" Set the log level."),
|
|
poetry: Optional[Path] = typer.Option(
|
|
"poetry",
|
|
help="Path to the poetry executable; defaults to the first in your path.",
|
|
),
|
|
):
|
|
logging.basicConfig(
|
|
format="%(message)s",
|
|
level=getattr(logging, log_level.upper()),
|
|
handlers=[RichHandler(rich_tracebacks=True, tracebacks_suppress=[typer])],
|
|
)
|
|
app_state["build_tool"] = BuildTool(poetry=poetry, verbose=verbose)
|
|
if context.invoked_subcommand is None:
|
|
logger.debug("No command specified; defaulting to build.")
|
|
build()
|
|
|
|
|
|
@app.command()
|
|
def init():
|
|
"""
|
|
Add opinionated defaults to your pyproject.toml.
|
|
"""
|
|
defaults = TEMPLATE_ROOT / "slam_defaults.toml"
|
|
target = app_state["build_tool"].project_root / "pyproject.toml"
|
|
if not target.exists():
|
|
raise RuntimeError(f"Could not find pyproject.toml at '{target}'")
|
|
logger.debug(f"Checking for modifications to {target}")
|
|
existing = target.read_text()
|
|
if "### SLAM" in existing:
|
|
logging.info("Found what looks like poetry-slam modifications; stopping.")
|
|
print(f"Abort: It looks like poetry-slam has already modified {target}.")
|
|
else:
|
|
backup = Path(str(target) + ".slam-orig")
|
|
backup.write_text(existing)
|
|
logging.debug(f"Saved backup of {target} to {backup}")
|
|
new = Path(str(target) + ".slam-new")
|
|
new.write_text(existing + "\n\n" + defaults.read_text())
|
|
logging.debug(f"Wrote temporary file {new}")
|
|
new.rename(target)
|
|
logging.debug(f"Renamed {new} to {target}")
|
|
print(f"Added poetry-slam defaults to {target}")
|
|
|
|
logging.debug("Adding test dependencies to dev group.")
|
|
app_state["build_tool"].run_with_poetry("add", "-G", "dev", "pytest", "pytest-cov")
|
|
|
|
|
|
@app.command()
|
|
def new(
|
|
template: Template = typer.Option("default", help="The template to use."),
|
|
project_name: str = typer.Argument(
|
|
help="The name of your new project. Defaults to the current directory name"
|
|
)
|
|
):
|
|
"""
|
|
Initialize a project with boilerplate code.
|
|
"""
|
|
package_name = project_name.lower().replace('-', '_')
|
|
tmpl = templates()[template.name]
|
|
tmpl.values = {
|
|
'PROJECT_NAME': project_name,
|
|
'PACKAGE_NAME': package_name,
|
|
'DESCRIPTION': f"{project_name}: automatically generated by poetry-slam.",
|
|
'AUTHOR_NAME': os.environ['USER']
|
|
}
|
|
logging.debug(f"Configuring template: {tmpl}")
|
|
tmpl.apply()
|
|
init()
|
|
backup = app_state["build_tool"].project_root / "pyproject.toml.slam-orig"
|
|
logging.debug(f"Cleaning up {backup}...")
|
|
backup.unlink()
|
|
build()
|
|
backup = app_state["build_tool"].run(project_name, "--help")
|
|
print(f"Successfully initialized new {template.name} project {project_name}.")
|
|
|
|
|
|
@app.command()
|
|
def format():
|
|
"""
|
|
Run isort, autoflake, and black on the src/ and test/ directories.
|
|
"""
|
|
returncode = app_state["build_tool"].auto_format()
|
|
print(f"slam format: {'SUCCESS' if returncode == 0 else 'ERROR'}")
|
|
return returncode
|
|
|
|
|
|
@app.command()
|
|
def build():
|
|
"""
|
|
Calls format, test, and install before invoking 'poetry build'.
|
|
"""
|
|
returncode = app_state["build_tool"].build()
|
|
print(f"slam build: {'SUCCESS' if returncode == 0 else 'ERROR'}")
|
|
return returncode
|
|
|
|
|
|
@app.command()
|
|
def install():
|
|
"""
|
|
Synonym for 'poetry install'
|
|
"""
|
|
returncode = app_state["build_tool"].install()
|
|
print(f"slam install: {'SUCCESS' if returncode == 0 else 'ERROR'}")
|
|
return returncode
|
|
|
|
|
|
@app.command(context_settings={"allow_extra_args": True, "ignore_unknown_options": True})
|
|
def test(context: typer.Context):
|
|
"""
|
|
Synonym for 'poetry run pytest' Output is always verbose.
|
|
"""
|
|
app_state["build_tool"].verbose = True
|
|
returncode = app_state["build_tool"].test(context.args)
|
|
print(f"slam test: {'SUCCESS' if returncode == 0 else 'ERROR'}")
|
|
return returncode
|