feat: add init command and --project option to build
This commit is contained in:
parent
d772f5dcc5
commit
a4600df4d5
1 changed files with 66 additions and 4 deletions
|
|
@ -23,7 +23,15 @@ class _DefaultBuildGroup(TyperGroup): # type: ignore[misc]
|
||||||
|
|
||||||
@override
|
@override
|
||||||
def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]:
|
def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]:
|
||||||
if not args or (args[0] not in self.commands and not args[0].startswith("-")):
|
# Prepend "build" unless the first token is already a known command
|
||||||
|
# or a top-level flag (--help / --install-completion / --show-completion).
|
||||||
|
is_command = bool(args) and args[0] in self.commands
|
||||||
|
is_top_level_flag = bool(args) and args[0] in {
|
||||||
|
"--help",
|
||||||
|
"--install-completion",
|
||||||
|
"--show-completion",
|
||||||
|
}
|
||||||
|
if not is_command and not is_top_level_flag:
|
||||||
args = ["build", *args]
|
args = ["build", *args]
|
||||||
return super().parse_args(ctx, args)
|
return super().parse_args(ctx, args)
|
||||||
|
|
||||||
|
|
@ -47,8 +55,24 @@ def _project_name(config_path: Path) -> str:
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
def _find_config(directory: Path) -> Path:
|
def _find_config(directory: Path, project: str | None = None) -> Path:
|
||||||
"""Find the single ``*.hokusai.{yaml,yml}`` file in *directory*."""
|
"""Find a ``*.hokusai.{yaml,yml}`` config file in *directory*.
|
||||||
|
|
||||||
|
When *project* is given, look for ``<project>.hokusai.{yaml,yml}``
|
||||||
|
specifically. Otherwise auto-detect the single config file present.
|
||||||
|
"""
|
||||||
|
if project is not None:
|
||||||
|
for suffix in _CONFIG_SUFFIXES:
|
||||||
|
candidate = directory / f"{project}{suffix}"
|
||||||
|
if candidate.exists():
|
||||||
|
return candidate
|
||||||
|
click.echo(
|
||||||
|
click.style("Error: ", fg="red", bold=True)
|
||||||
|
+ f"No config file found for project '{project}'",
|
||||||
|
err=True,
|
||||||
|
)
|
||||||
|
raise typer.Exit(code=1)
|
||||||
|
|
||||||
candidates: list[Path] = []
|
candidates: list[Path] = []
|
||||||
for suffix in _CONFIG_SUFFIXES:
|
for suffix in _CONFIG_SUFFIXES:
|
||||||
candidates.extend(directory.glob(f"*{suffix}"))
|
candidates.extend(directory.glob(f"*{suffix}"))
|
||||||
|
|
@ -128,10 +152,13 @@ def build(
|
||||||
target: Annotated[
|
target: Annotated[
|
||||||
str | None, typer.Argument(help="Specific target to build.")
|
str | None, typer.Argument(help="Specific target to build.")
|
||||||
] = None,
|
] = None,
|
||||||
|
project: Annotated[
|
||||||
|
str | None, typer.Option(help="Project name (loads <project>.hokusai.yaml).")
|
||||||
|
] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Build all targets (or a specific target) in dependency order."""
|
"""Build all targets (or a specific target) in dependency order."""
|
||||||
project_dir = Path.cwd()
|
project_dir = Path.cwd()
|
||||||
config_path = _find_config(project_dir)
|
config_path = _find_config(project_dir, project)
|
||||||
config = load_config(config_path)
|
config = load_config(config_path)
|
||||||
name = _project_name(config_path)
|
name = _project_name(config_path)
|
||||||
|
|
||||||
|
|
@ -212,6 +239,41 @@ def graph() -> None:
|
||||||
click.echo(f" {node}{arrow}{', '.join(preds)}")
|
click.echo(f" {node}{arrow}{', '.join(preds)}")
|
||||||
|
|
||||||
|
|
||||||
|
@app.command()
|
||||||
|
def init() -> None:
|
||||||
|
"""Create a starter .hokusai.yaml config file."""
|
||||||
|
name = str(click.prompt("Project name", type=str)).strip() # pyright: ignore[reportAny]
|
||||||
|
if not name:
|
||||||
|
click.echo(click.style("Error: ", fg="red", bold=True) + "Name cannot be empty")
|
||||||
|
raise typer.Exit(code=1)
|
||||||
|
|
||||||
|
filename = f"{name}.hokusai.yaml"
|
||||||
|
dest = Path.cwd() / filename
|
||||||
|
if dest.exists():
|
||||||
|
click.echo(
|
||||||
|
click.style("Error: ", fg="red", bold=True) + f"{filename} already exists"
|
||||||
|
)
|
||||||
|
raise typer.Exit(code=1)
|
||||||
|
|
||||||
|
content = f"""\
|
||||||
|
# {name} - hokusai project
|
||||||
|
defaults:
|
||||||
|
image_model: flux-2-pro
|
||||||
|
|
||||||
|
targets:
|
||||||
|
great_wave.png:
|
||||||
|
prompt: >-
|
||||||
|
A recreation of Hokusai's "The Great Wave off Kanagawa", but instead of
|
||||||
|
boats and people, paint brushes, canvases, and framed paintings are
|
||||||
|
swimming and tumbling in the towering wave. Oil paint tubes burst open
|
||||||
|
and trail ribbons of colour through the spray. The iconic Mount Fuji
|
||||||
|
sits serenely in the background. Ukiyo-e woodblock print style with
|
||||||
|
vivid modern pigment colours.
|
||||||
|
"""
|
||||||
|
_ = dest.write_text(content)
|
||||||
|
click.echo(click.style(" created ", fg="green") + click.style(filename, bold=True))
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def models() -> None:
|
def models() -> None:
|
||||||
"""List available models and their capabilities."""
|
"""List available models and their capabilities."""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue