Skip to content

Commit

Permalink
Feature/online help (#3)
Browse files Browse the repository at this point in the history
* added help text, show-config command, sane defaults

* cleaned up __root__ references, fixed bugs, added small features

- Fixed pyproject.toml dependencies
- Added model properties to encapsulate `__root__`
- Added online help for commands
- Added `show-config` command
- Added `--basedir` CLI option
- Fixed docker syntax line in base template
- Added support for SHELL in stage template
- Fixed bug with LABEL k/v pair
- Updated test suite
  • Loading branch information
eric-anderton-at-rearc authored Nov 7, 2023
1 parent b8dfaa2 commit 026fd31
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 10 deletions.
4 changes: 4 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
- Add `setup` feature for modules
- Add build profiles to control the generation of the bakefile(s)
- Add duplicate name check to config file validation
- Upgrade to pydantic 2.x
- Unit tests
- Integration (CLI) tests
63 changes: 56 additions & 7 deletions docker_printer/cli.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import subprocess
import textwrap
from pathlib import Path
Expand All @@ -24,18 +25,29 @@ def version_callback(value: bool):
raise typer.Exit()


def base_dir_callback(value: str = None):
# Change CWD to target so path resolution works as expected
if value:
resoled_value = Path(value).resolve()
os.chdir(str(resoled_value))


@app.callback()
def main(
version: bool = typer.Option(
None, "--version", callback=version_callback, is_eager=True
),
base_dir: str = typer.Option(
None, "--basedir", callback=base_dir_callback, is_eager=True
),
):
# Do other global stuff, handle other global options here
return


@app.command()
def synth():
"""Synthesizes new Dockerfiles from configuration."""
_synth()


Expand All @@ -52,7 +64,7 @@ def _synth():
with open(dockerfile_path, "w", newline="\n") as f:
f.write(dockerfile)

for build_config in build_configs.__root__:
for build_config in build_configs.configs:
bakefile_path = base_dir() / f"docker-bake.{build_config.name}.json"
bakefile = build_config.generate_bakefile(targets)
with open(bakefile_path, "w", newline="\n") as f:
Expand All @@ -63,15 +75,48 @@ def _synth():


@app.command()
def build(name: str):
def build(name: str = "default"):
"""Builds the current configuration from synthesized Dockerfile(s)."""
_, build_configs = _synth()

try:
config = next(cfg for cfg in build_configs.__root__ if cfg.name == name)
config = next(cfg for cfg in build_configs.configs if cfg.name == name)
except StopIteration:
raise typer.Abort(f"No build config found with name '{name}'")
names = ", ".join(set([x.name for x in build_configs.configs]))
typer.secho(
f"Error: No build config found with name '{name}'", fg=typer.colors.RED
)
typer.secho(f"Valid names: {names}", fg=typer.colors.YELLOW)
typer.Exit(1)
else:
typer.echo(config.build_command)
subprocess.run(config.build_command, shell=True)

subprocess.run(config.build_command)

@app.command()
def show_config():
"""List the current config files and build targets."""
preload_modules()

target_config_file = targets_file()
build_config_file = builds_file()
target_configs = TargetCollection.parse_obj(yml_load(target_config_file))
build_configs = BuildConfigCollection.parse_obj(yml_load(build_config_file))

typer.secho("Config files", bold=True, fg=typer.colors.GREEN)
typer.echo(str(target_config_file))
typer.echo(str(build_config_file))

typer.secho("\nTargets", bold=True, fg=typer.colors.GREEN)
for target in target_configs.targets:
typer.echo(target.name)
for mod in target.all_modules():
typer.echo(f" {mod.name}")
typer.echo()

typer.secho("\nBuilds", bold=True, fg=typer.colors.GREEN)
for build_config in build_configs.configs:
typer.echo(f"{build_config.name} {build_config.image}")


@app.command()
Expand All @@ -82,10 +127,14 @@ def init(
dir_okay=True,
)
):
"""Initializes a new project tree."""
base_dir = path / "docker-printer"
if base_dir.exists():
typer.echo(f"{base_dir} already exists, cannot initialize new project")
raise typer.Abort()
typer.secho(
f"Error: {base_dir} already exists, cannot initialize new project",
fg=typer.colors.RED,
)
typer.Exit(1)

base_dir.mkdir(exist_ok=False, parents=False)
(base_dir / "modules").mkdir(exist_ok=False, parents=False)
Expand Down
4 changes: 4 additions & 0 deletions docker_printer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,7 @@ def build_command(self):

class BuildConfigCollection(BaseModel):
__root__: List[BuildConfig]

@property
def configs(self):
return [t for t in self.__root__]
2 changes: 1 addition & 1 deletion docker_printer/resources/templates/base.Dockerfile.jinja2
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# syntax = docker/dockerfile:1.2
# syntax=docker/dockerfile:1

{% block pre_init %}{% endblock %}

Expand Down
6 changes: 5 additions & 1 deletion docker_printer/resources/templates/stage.Dockerfile.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ FROM {{ base }} AS {{ name }}

{% block labels -%}
{% for key, value in labels.items() -%}
LABEL "{{ key }}"={{ value }}"
LABEL "{{ key }}"="{{ value }}"
{% endfor %}
{%- endblock %}

Expand All @@ -20,6 +20,10 @@ ENV {{ key }}="{{ value }}"
{% endfor %}
{%- endblock %}

{% if shell -%}
SHELL {{ shell|tojson|safe }}
{%- endif %}

{% block instructions -%}
{% for instr in instructions -%}
{{ instr }}
Expand Down
2 changes: 1 addition & 1 deletion examples/fastapi_app/Dockerfile.synth
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# syntax = docker/dockerfile:1.2
# syntax=docker/dockerfile:1

ARG PYTHON_VERSION=3.9
ARG BASE_OS=slim
Expand Down

0 comments on commit 026fd31

Please sign in to comment.