From 07ceac36aced6ea47ca330e0335dbab217840999 Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Thu, 24 Oct 2024 07:09:41 -0500 Subject: [PATCH 01/16] fix: silverback build missing files during generate --- silverback/_cli.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/silverback/_cli.py b/silverback/_cli.py index 15e1b80c..e4e4a04d 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -41,10 +41,6 @@ WORKDIR /app RUN chown harambe:harambe /app USER harambe -COPY ape-config.yaml . -COPY requirements.txt . -RUN pip install --upgrade pip && pip install -r requirements.txt -RUN ape plugins install -U . """ @@ -152,12 +148,20 @@ def build(generate, path): bots.append(file) for bot in bots: dockerfile_content = DOCKERFILE_CONTENT + if (Path.cwd() / "requirements.txt").exists(): + dockerfile_content += "COPY requirements.txt .\n" + dockerfile_content += "RUN pip install --upgrade pip && pip install -r requirements.txt\n" + + if (Path.cwd() / "ape-config.yaml").exists(): + dockerfile_content += "COPY ape-config.yaml .\n" + dockerfile_content += "RUN ape plugins install -U .\n" + if "__init__" in bot.name: docker_filename = f"Dockerfile.{bot.parent.name}" - dockerfile_content += f"COPY {path.name}/ /app/bot" + dockerfile_content += f"COPY {path.name}/ /app/bot\n" else: docker_filename = f"Dockerfile.{bot.name.replace('.py', '')}" - dockerfile_content += f"COPY {path.name}/{bot.name} /app/bot.py" + dockerfile_content += f"COPY {path.name}/{bot.name} /app/bot.py\n" dockerfile_path = Path.cwd() / ".silverback-images" / docker_filename dockerfile_path.parent.mkdir(exist_ok=True) dockerfile_path.write_text(dockerfile_content.strip() + "\n") From 8f198191124704da60fbdb19712d0707bb2a4e6a Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Thu, 24 Oct 2024 07:15:01 -0500 Subject: [PATCH 02/16] fix: black --- silverback/_cli.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/silverback/_cli.py b/silverback/_cli.py index e4e4a04d..7dfbe1e0 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -150,7 +150,9 @@ def build(generate, path): dockerfile_content = DOCKERFILE_CONTENT if (Path.cwd() / "requirements.txt").exists(): dockerfile_content += "COPY requirements.txt .\n" - dockerfile_content += "RUN pip install --upgrade pip && pip install -r requirements.txt\n" + dockerfile_content += ( + "RUN pip install --upgrade pip && pip install -r requirements.txt\n" + ) if (Path.cwd() / "ape-config.yaml").exists(): dockerfile_content += "COPY ape-config.yaml .\n" From de83ebb78a25a9236ebd8bde670f3a4dc0bfe59c Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Thu, 24 Oct 2024 15:03:01 -0500 Subject: [PATCH 03/16] feat: proper bot bots and python file treatment --- silverback/_cli.py | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/silverback/_cli.py b/silverback/_cli.py index 7dfbe1e0..8ae5a08c 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -128,21 +128,36 @@ def run(cli_ctx, account, runner_class, recorder_class, max_exceptions, bot): asyncio.run(runner.run()) +def build_helper(docker_fn: str, dockerfile_c: str): + dockerfile_path = Path.cwd() / ".silverback-images" / docker_fn + dockerfile_path.parent.mkdir(exist_ok=True) + dockerfile_path.write_text(dockerfile_c.strip() + "\n") + click.echo(f"Generated {dockerfile_path}") + + + @cli.command(section="Local Commands") @click.option("--generate", is_flag=True, default=False) @click.argument("path", required=False, type=str, default="bots") def build(generate, path): """Generate Dockerfiles and build bot images""" if generate: - if not (path := Path.cwd() / path).exists(): + if not (path := Path.cwd() / path).exists() and not (path := Path.cwd() / "bot").exists() and not (path := Path.cwd() / "bot.py").exists(): raise FileNotFoundError( - f"The bots directory '{path}' does not exist. " - "You should have a `{path}/` folder in the root of your project." + f"The bots directory '{path}', 'bot/' and 'bot.py' does not exist in your path. " + f"You should have a '{path}/' or 'bot/' folder, or a 'bot.py' file in the root of your project." ) - files = {file for file in path.iterdir() if file.is_file()} + if path.is_file(): + dockerfile_content = DOCKERFILE_CONTENT + docker_filename = f"Dockerfile.{path.parent.name}-bot" + dockerfile_content += f"COPY {path.name}/ /app/bot\n" + build_helper(docker_filename, dockerfile_content) + return + + files = sorted({file for file in path.iterdir() if file.is_file()}, reverse=True) bots = [] for file in files: - if "__init__" in file.name: + if file.name == "__init__.py" or file.name == "bot.py": bots = [file] break bots.append(file) @@ -158,16 +173,13 @@ def build(generate, path): dockerfile_content += "COPY ape-config.yaml .\n" dockerfile_content += "RUN ape plugins install -U .\n" - if "__init__" in bot.name: - docker_filename = f"Dockerfile.{bot.parent.name}" + if bot.name == "__init__.py" or bot.name == "bot.py": + docker_filename = f"Dockerfile.{bot.parent.parent.name}-bot" dockerfile_content += f"COPY {path.name}/ /app/bot\n" else: - docker_filename = f"Dockerfile.{bot.name.replace('.py', '')}" + docker_filename = f"Dockerfile.{bot.name.replace('.py', '')}-bot" dockerfile_content += f"COPY {path.name}/{bot.name} /app/bot.py\n" - dockerfile_path = Path.cwd() / ".silverback-images" / docker_filename - dockerfile_path.parent.mkdir(exist_ok=True) - dockerfile_path.write_text(dockerfile_content.strip() + "\n") - click.echo(f"Generated {dockerfile_path}") + build_helper(docker_filename, dockerfile_content) return if not (path := Path.cwd() / ".silverback-images").exists(): From 3dd34f7ab276c34f82810af699e782111df2543e Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Thu, 24 Oct 2024 15:05:54 -0500 Subject: [PATCH 04/16] fix: black --- silverback/_cli.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/silverback/_cli.py b/silverback/_cli.py index 8ae5a08c..b5568f3c 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -135,14 +135,17 @@ def build_helper(docker_fn: str, dockerfile_c: str): click.echo(f"Generated {dockerfile_path}") - @cli.command(section="Local Commands") @click.option("--generate", is_flag=True, default=False) @click.argument("path", required=False, type=str, default="bots") def build(generate, path): """Generate Dockerfiles and build bot images""" if generate: - if not (path := Path.cwd() / path).exists() and not (path := Path.cwd() / "bot").exists() and not (path := Path.cwd() / "bot.py").exists(): + if ( + not (path := Path.cwd() / path).exists() + and not (path := Path.cwd() / "bot").exists() + and not (path := Path.cwd() / "bot.py").exists() + ): raise FileNotFoundError( f"The bots directory '{path}', 'bot/' and 'bot.py' does not exist in your path. " f"You should have a '{path}/' or 'bot/' folder, or a 'bot.py' file in the root of your project." From 9a4d5aef4654418414a1581fb68b66dd10cba5bc Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Thu, 24 Oct 2024 15:24:22 -0500 Subject: [PATCH 05/16] fix: flake8 issue --- silverback/_cli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/silverback/_cli.py b/silverback/_cli.py index b5568f3c..851217ef 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -148,7 +148,8 @@ def build(generate, path): ): raise FileNotFoundError( f"The bots directory '{path}', 'bot/' and 'bot.py' does not exist in your path. " - f"You should have a '{path}/' or 'bot/' folder, or a 'bot.py' file in the root of your project." + f"You should have a '{path}/' or 'bot/' folder, or a 'bot.py' file in the root " + "of your project." ) if path.is_file(): dockerfile_content = DOCKERFILE_CONTENT From 3d5f9556c5047288d2bf88a5bdf183a25c61aa20 Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Fri, 25 Oct 2024 16:36:17 -0500 Subject: [PATCH 06/16] refactor: cleanup the build helper function placement --- silverback/_cli.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/silverback/_cli.py b/silverback/_cli.py index 851217ef..cba5e894 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -63,6 +63,16 @@ def _account_callback(ctx, param, val): return val +def _build_helper(docker_fn: str, dockerfile_c: str): + """ + Used in multiple places in build. + """ + dockerfile_path = Path.cwd() / ".silverback-images" / docker_fn + dockerfile_path.parent.mkdir(exist_ok=True) + dockerfile_path.write_text(dockerfile_c.strip() + "\n") + click.echo(f"Generated {dockerfile_path}") + + # TODO: Make `silverback.settings.Settings` (to remove having to set envvars) # TODO: Use `envvar=...` to be able to set the value of options from correct envvar def _network_callback(ctx, param, val): @@ -128,13 +138,6 @@ def run(cli_ctx, account, runner_class, recorder_class, max_exceptions, bot): asyncio.run(runner.run()) -def build_helper(docker_fn: str, dockerfile_c: str): - dockerfile_path = Path.cwd() / ".silverback-images" / docker_fn - dockerfile_path.parent.mkdir(exist_ok=True) - dockerfile_path.write_text(dockerfile_c.strip() + "\n") - click.echo(f"Generated {dockerfile_path}") - - @cli.command(section="Local Commands") @click.option("--generate", is_flag=True, default=False) @click.argument("path", required=False, type=str, default="bots") @@ -155,7 +158,7 @@ def build(generate, path): dockerfile_content = DOCKERFILE_CONTENT docker_filename = f"Dockerfile.{path.parent.name}-bot" dockerfile_content += f"COPY {path.name}/ /app/bot\n" - build_helper(docker_filename, dockerfile_content) + _build_helper(docker_filename, dockerfile_content) return files = sorted({file for file in path.iterdir() if file.is_file()}, reverse=True) @@ -183,7 +186,7 @@ def build(generate, path): else: docker_filename = f"Dockerfile.{bot.name.replace('.py', '')}-bot" dockerfile_content += f"COPY {path.name}/{bot.name} /app/bot.py\n" - build_helper(docker_filename, dockerfile_content) + _build_helper(docker_filename, dockerfile_content) return if not (path := Path.cwd() / ".silverback-images").exists(): From 481f0f8b71faff49e774d6886edee196bfd99507 Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Sat, 26 Oct 2024 04:19:52 -0500 Subject: [PATCH 07/16] fix: pipe only the stdout --- silverback/_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/silverback/_cli.py b/silverback/_cli.py index cba5e894..f535d525 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -205,7 +205,7 @@ def build(generate, path): result = subprocess.run( command, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + stderr=subprocess.STDOUT, text=True, check=True, ) From b5ac3d1b0d218924e48a95421ca7c74fa43094b0 Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Sat, 26 Oct 2024 04:23:20 -0500 Subject: [PATCH 08/16] feat: allow generate flag to also build --- silverback/_cli.py | 57 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/silverback/_cli.py b/silverback/_cli.py index f535d525..32c7e18b 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -159,35 +159,34 @@ def build(generate, path): docker_filename = f"Dockerfile.{path.parent.name}-bot" dockerfile_content += f"COPY {path.name}/ /app/bot\n" _build_helper(docker_filename, dockerfile_content) - return - - files = sorted({file for file in path.iterdir() if file.is_file()}, reverse=True) - bots = [] - for file in files: - if file.name == "__init__.py" or file.name == "bot.py": - bots = [file] - break - bots.append(file) - for bot in bots: - dockerfile_content = DOCKERFILE_CONTENT - if (Path.cwd() / "requirements.txt").exists(): - dockerfile_content += "COPY requirements.txt .\n" - dockerfile_content += ( - "RUN pip install --upgrade pip && pip install -r requirements.txt\n" - ) - - if (Path.cwd() / "ape-config.yaml").exists(): - dockerfile_content += "COPY ape-config.yaml .\n" - dockerfile_content += "RUN ape plugins install -U .\n" - - if bot.name == "__init__.py" or bot.name == "bot.py": - docker_filename = f"Dockerfile.{bot.parent.parent.name}-bot" - dockerfile_content += f"COPY {path.name}/ /app/bot\n" - else: - docker_filename = f"Dockerfile.{bot.name.replace('.py', '')}-bot" - dockerfile_content += f"COPY {path.name}/{bot.name} /app/bot.py\n" - _build_helper(docker_filename, dockerfile_content) - return + + else: + files = sorted({file for file in path.iterdir() if file.is_file()}, reverse=True) + bots = [] + for file in files: + if file.name == "__init__.py" or file.name == "bot.py": + bots = [file] + break + bots.append(file) + for bot in bots: + dockerfile_content = DOCKERFILE_CONTENT + if (Path.cwd() / "requirements.txt").exists(): + dockerfile_content += "COPY requirements.txt .\n" + dockerfile_content += ( + "RUN pip install --upgrade pip && pip install -r requirements.txt\n" + ) + + if (Path.cwd() / "ape-config.yaml").exists(): + dockerfile_content += "COPY ape-config.yaml .\n" + dockerfile_content += "RUN ape plugins install -U .\n" + + if bot.name == "__init__.py" or bot.name == "bot.py": + docker_filename = f"Dockerfile.{bot.parent.parent.name}-bot" + dockerfile_content += f"COPY {path.name}/ /app/bot\n" + else: + docker_filename = f"Dockerfile.{bot.name.replace('.py', '')}" + dockerfile_content += f"COPY {path.name}/{bot.name} /app/bot.py\n" + _build_helper(docker_filename, dockerfile_content) if not (path := Path.cwd() / ".silverback-images").exists(): raise FileNotFoundError( From f81c667740d1bbe5be7d6ce1b2dba6ea4e69a90d Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Sat, 26 Oct 2024 05:45:17 -0500 Subject: [PATCH 09/16] feat: add build_utils file --- silverback/_build_utils.py | 119 +++++++++++++++++++++++++++++++++++++ silverback/_cli.py | 53 +---------------- 2 files changed, 121 insertions(+), 51 deletions(-) create mode 100644 silverback/_build_utils.py diff --git a/silverback/_build_utils.py b/silverback/_build_utils.py new file mode 100644 index 00000000..7a87460c --- /dev/null +++ b/silverback/_build_utils.py @@ -0,0 +1,119 @@ +from typing import Union + +import click + +from functools import singledispatchmethod +from pathlib import Path + + +DOCKERFILE_CONTENT = """ +FROM ghcr.io/apeworx/silverback:stable +USER root +WORKDIR /app +RUN chown harambe:harambe /app +USER harambe +""" + + +class BasePath(Path): + _flavour = type(Path())._flavour + _parse_args = type(Path())._parse_args + + +class FilePath(BasePath): + """A subclass of Path representing a file.""" + + +class DirPath(BasePath): + """A subclass of Path representing a path""" + + +def generate_path(path: Path): + if path.is_file(): + return FilePath(str(path)) + elif path.is_dir(): + return DirPath(str(path)) + else: + raise ValueError( + f"{path} is neither a file nor a directory" + ) + + +PathType = Union[ + "FilePath", + "DirPath" +] + +def generate_dockerfiles(path: Path): + path = generate_path(path) + dg = DockerfileGenerator() + breakpoint() + dg.generate_dockerfiles(path) + +class DockerfileGenerator: + + @property + def dockerfile_name(self): + return self._dockerfile_name + + @dockerfile_name.setter + def dockerfile_name(self, name): + self._dockerfile_name = name + + @singledispatchmethod + def generate_dockerfiles(self, path: PathType): + """ + Will generate a file based on path type + """ + + @generate_dockerfiles.register + def _(self, path: FilePath): + dockerfile_content = self._check_for_requirements(DOCKERFILE_CONTENT) + self.dockerfile_name = f"Dockerfile.{path.parent.name}-bot" + dockerfile_content += f"COPY {path.name}/ /app/bot.py\n" + self._build_helper(dockerfile_content) + + @generate_dockerfiles.register + def _(self, path: DirPath): + bots = self._get_all_bot_files(path) + for bot in bots: + dockerfile_content = self._check_for_requirements(DOCKERFILE_CONTENT) + if bot.name == "__init__.py" or bot.name == "bot.py": + self.dockerfile_name = f"Dockerfile.{bot.parent.parent.name}-bot" + dockerfile_content += f"COPY {path.name}/ /app/bot\n" + else: + self.dockerfile_name = f"Dockerfile.{bot.name.replace('.py', '')}" + dockerfile_content += f"COPY {path.name}/{bot.name} /app/bot.py\n" + self._build_helper(dockerfile_content) + + def _build_helper(self, dockerfile_c: str): + """ + Used in multiple places in build. + """ + dockerfile_path = Path.cwd() / ".silverback-images" / self.dockerfile_name + dockerfile_path.parent.mkdir(exist_ok=True) + dockerfile_path.write_text(dockerfile_c.strip() + "\n") + click.echo(f"Generated {dockerfile_path}") + + def _check_for_requirements(self, dockerfile_content): + if (Path.cwd() / "requirements.txt").exists(): + dockerfile_content += "COPY requirements.txt .\n" + dockerfile_content += ( + "RUN pip install --upgrade pip && pip install -r requirements.txt\n" + ) + + if (Path.cwd() / "ape-config.yaml").exists(): + dockerfile_content += "COPY ape-config.yaml .\n" + dockerfile_content += "RUN ape plugins install -U .\n" + + return dockerfile_content + + def _get_all_bot_files(self, path: DirPath): + files = sorted({file for file in path.iterdir() if file.is_file()}, reverse=True) + bots = [] + for file in files: + if file.name == "__init__.py" or file.name == "bot.py": + bots = [file] + break + bots.append(file) + return bots diff --git a/silverback/_cli.py b/silverback/_cli.py index 32c7e18b..2724e166 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -19,6 +19,7 @@ from ape.exceptions import Abort, ApeException from fief_client.integrations.cli import FiefAuth +from silverback._build_utils import generate_dockerfiles from silverback._click_ext import ( SectionedHelpGroup, auth_required, @@ -35,14 +36,6 @@ from silverback.runner import PollingRunner, WebsocketRunner from silverback.worker import run_worker -DOCKERFILE_CONTENT = """ -FROM ghcr.io/apeworx/silverback:stable -USER root -WORKDIR /app -RUN chown harambe:harambe /app -USER harambe -""" - @click.group(cls=SectionedHelpGroup) def cli(): @@ -63,16 +56,6 @@ def _account_callback(ctx, param, val): return val -def _build_helper(docker_fn: str, dockerfile_c: str): - """ - Used in multiple places in build. - """ - dockerfile_path = Path.cwd() / ".silverback-images" / docker_fn - dockerfile_path.parent.mkdir(exist_ok=True) - dockerfile_path.write_text(dockerfile_c.strip() + "\n") - click.echo(f"Generated {dockerfile_path}") - - # TODO: Make `silverback.settings.Settings` (to remove having to set envvars) # TODO: Use `envvar=...` to be able to set the value of options from correct envvar def _network_callback(ctx, param, val): @@ -154,39 +137,7 @@ def build(generate, path): f"You should have a '{path}/' or 'bot/' folder, or a 'bot.py' file in the root " "of your project." ) - if path.is_file(): - dockerfile_content = DOCKERFILE_CONTENT - docker_filename = f"Dockerfile.{path.parent.name}-bot" - dockerfile_content += f"COPY {path.name}/ /app/bot\n" - _build_helper(docker_filename, dockerfile_content) - - else: - files = sorted({file for file in path.iterdir() if file.is_file()}, reverse=True) - bots = [] - for file in files: - if file.name == "__init__.py" or file.name == "bot.py": - bots = [file] - break - bots.append(file) - for bot in bots: - dockerfile_content = DOCKERFILE_CONTENT - if (Path.cwd() / "requirements.txt").exists(): - dockerfile_content += "COPY requirements.txt .\n" - dockerfile_content += ( - "RUN pip install --upgrade pip && pip install -r requirements.txt\n" - ) - - if (Path.cwd() / "ape-config.yaml").exists(): - dockerfile_content += "COPY ape-config.yaml .\n" - dockerfile_content += "RUN ape plugins install -U .\n" - - if bot.name == "__init__.py" or bot.name == "bot.py": - docker_filename = f"Dockerfile.{bot.parent.parent.name}-bot" - dockerfile_content += f"COPY {path.name}/ /app/bot\n" - else: - docker_filename = f"Dockerfile.{bot.name.replace('.py', '')}" - dockerfile_content += f"COPY {path.name}/{bot.name} /app/bot.py\n" - _build_helper(docker_filename, dockerfile_content) + generate_dockerfiles(path) if not (path := Path.cwd() / ".silverback-images").exists(): raise FileNotFoundError( From 2882ddc0e2d487ed51f4258d3718ffd956ad043b Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Sat, 26 Oct 2024 05:46:05 -0500 Subject: [PATCH 10/16] feat: add note about subclassing --- silverback/_build_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/silverback/_build_utils.py b/silverback/_build_utils.py index 7a87460c..61733d24 100644 --- a/silverback/_build_utils.py +++ b/silverback/_build_utils.py @@ -15,6 +15,7 @@ """ +# Note: Python3.12 supports subclassing pathlib.Path class BasePath(Path): _flavour = type(Path())._flavour _parse_args = type(Path())._parse_args From 2980b22a7d827e1d9b086c5ad2b5c0a86b2f98d5 Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Sat, 26 Oct 2024 05:50:27 -0500 Subject: [PATCH 11/16] feat: move image generate to build utils --- silverback/_build_utils.py | 31 ++++++++++++++++++++++++++++++- silverback/_cli.py | 24 +++--------------------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/silverback/_build_utils.py b/silverback/_build_utils.py index 61733d24..ce412009 100644 --- a/silverback/_build_utils.py +++ b/silverback/_build_utils.py @@ -1,6 +1,8 @@ from typing import Union import click +import shlex +import subprocess from functools import singledispatchmethod from pathlib import Path @@ -48,9 +50,13 @@ def generate_path(path: Path): def generate_dockerfiles(path: Path): path = generate_path(path) dg = DockerfileGenerator() - breakpoint() dg.generate_dockerfiles(path) + +def generate_docker_images(path: Path): + DockerfileGenerator.generate_images(path) + + class DockerfileGenerator: @property @@ -118,3 +124,26 @@ def _get_all_bot_files(self, path: DirPath): break bots.append(file) return bots + + @staticmethod + def generate_images(path: Path): + dockerfiles = {file for file in path.iterdir() if file.is_file()} + for file in dockerfiles: + try: + command = shlex.split( + "docker build -f " + f"./{file.parent.name}/{file.name} " + f"-t {file.name.split('.')[1]}:latest ." + ) + result = subprocess.run( + command, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + check=True, + ) + click.echo(result.stdout) + except subprocess.CalledProcessError as e: + click.echo("Error during docker build:") + click.echo(e.stderr) + raise diff --git a/silverback/_cli.py b/silverback/_cli.py index 2724e166..ea665cea 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -19,7 +19,7 @@ from ape.exceptions import Abort, ApeException from fief_client.integrations.cli import FiefAuth -from silverback._build_utils import generate_dockerfiles +from silverback._build_utils import generate_dockerfiles, generate_docker_images from silverback._click_ext import ( SectionedHelpGroup, auth_required, @@ -144,26 +144,8 @@ def build(generate, path): f"The dockerfile directory '{path}' does not exist. " "You should have a `{path}/` folder in the root of your project." ) - dockerfiles = {file for file in path.iterdir() if file.is_file()} - for file in dockerfiles: - try: - command = shlex.split( - "docker build -f " - f"./{file.parent.name}/{file.name} " - f"-t {file.name.split('.')[1]}:latest ." - ) - result = subprocess.run( - command, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - text=True, - check=True, - ) - click.echo(result.stdout) - except subprocess.CalledProcessError as e: - click.echo("Error during docker build:") - click.echo(e.stderr) - raise + + generate_docker_images(path) @cli.command(cls=ConnectedProviderCommand, section="Local Commands") From bc8f1550098d3fdebbef23e483d3a33e990bbc7d Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Sat, 26 Oct 2024 06:02:00 -0500 Subject: [PATCH 12/16] refactor: clean up some code --- silverback/_build_utils.py | 16 +++++----------- silverback/_cli.py | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/silverback/_build_utils.py b/silverback/_build_utils.py index ce412009..fd6d3d59 100644 --- a/silverback/_build_utils.py +++ b/silverback/_build_utils.py @@ -1,12 +1,10 @@ -from typing import Union - -import click import shlex import subprocess - from functools import singledispatchmethod from pathlib import Path +from typing import Union +import click DOCKERFILE_CONTENT = """ FROM ghcr.io/apeworx/silverback:stable @@ -37,15 +35,11 @@ def generate_path(path: Path): elif path.is_dir(): return DirPath(str(path)) else: - raise ValueError( - f"{path} is neither a file nor a directory" - ) + raise ValueError(f"{path} is neither a file nor a directory") + +PathType = Union["FilePath", "DirPath"] -PathType = Union[ - "FilePath", - "DirPath" -] def generate_dockerfiles(path: Path): path = generate_path(path) diff --git a/silverback/_cli.py b/silverback/_cli.py index ea665cea..640fc4b1 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -19,7 +19,7 @@ from ape.exceptions import Abort, ApeException from fief_client.integrations.cli import FiefAuth -from silverback._build_utils import generate_dockerfiles, generate_docker_images +from silverback._build_utils import generate_docker_images, generate_dockerfiles from silverback._click_ext import ( SectionedHelpGroup, auth_required, From ea152065c62ad71f033d17705775e583ea4322ce Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Sat, 26 Oct 2024 06:09:01 -0500 Subject: [PATCH 13/16] refactor: more cleanup --- silverback/_build_utils.py | 1 - silverback/_cli.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/silverback/_build_utils.py b/silverback/_build_utils.py index fd6d3d59..144e913a 100644 --- a/silverback/_build_utils.py +++ b/silverback/_build_utils.py @@ -18,7 +18,6 @@ # Note: Python3.12 supports subclassing pathlib.Path class BasePath(Path): _flavour = type(Path())._flavour - _parse_args = type(Path())._parse_args class FilePath(BasePath): diff --git a/silverback/_cli.py b/silverback/_cli.py index 640fc4b1..af9ea16d 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -1,7 +1,5 @@ import asyncio import os -import shlex -import subprocess from datetime import datetime, timedelta, timezone from pathlib import Path From eef0aaf19892314549c50eca292100aa28113ac6 Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Sat, 26 Oct 2024 06:14:12 -0500 Subject: [PATCH 14/16] fix: mypy error --- silverback/_build_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/silverback/_build_utils.py b/silverback/_build_utils.py index 144e913a..18409376 100644 --- a/silverback/_build_utils.py +++ b/silverback/_build_utils.py @@ -17,7 +17,7 @@ # Note: Python3.12 supports subclassing pathlib.Path class BasePath(Path): - _flavour = type(Path())._flavour + _flavour = type(Path())._flavour # type: ignore class FilePath(BasePath): From 08d57dc867e1f754163523ce202ed6407e726085 Mon Sep 17 00:00:00 2001 From: johnson2427 Date: Mon, 28 Oct 2024 07:27:50 -0500 Subject: [PATCH 15/16] fix: use clean_path for home directory --- silverback/_build_utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/silverback/_build_utils.py b/silverback/_build_utils.py index 18409376..ad6bd7ed 100644 --- a/silverback/_build_utils.py +++ b/silverback/_build_utils.py @@ -5,6 +5,7 @@ from typing import Union import click +from ape.utils.os import clean_path DOCKERFILE_CONTENT = """ FROM ghcr.io/apeworx/silverback:stable @@ -65,6 +66,7 @@ def generate_dockerfiles(self, path: PathType): """ Will generate a file based on path type """ + raise NotImplementedError(f"Path type {type(path)} not supported") @generate_dockerfiles.register def _(self, path: FilePath): @@ -93,7 +95,7 @@ def _build_helper(self, dockerfile_c: str): dockerfile_path = Path.cwd() / ".silverback-images" / self.dockerfile_name dockerfile_path.parent.mkdir(exist_ok=True) dockerfile_path.write_text(dockerfile_c.strip() + "\n") - click.echo(f"Generated {dockerfile_path}") + click.echo(f"Generated {clean_path(dockerfile_path)}") def _check_for_requirements(self, dockerfile_content): if (Path.cwd() / "requirements.txt").exists(): From adb76e99a05e23278943ebfe96b180814f8dfd55 Mon Sep 17 00:00:00 2001 From: El De-dog-lo <3859395+fubuloubu@users.noreply.github.com> Date: Mon, 28 Oct 2024 13:09:28 -0400 Subject: [PATCH 16/16] refactorb(build): apply suggestions from code review --- silverback/_build_utils.py | 10 +++++----- silverback/_cli.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/silverback/_build_utils.py b/silverback/_build_utils.py index ad6bd7ed..95c3f1c4 100644 --- a/silverback/_build_utils.py +++ b/silverback/_build_utils.py @@ -29,7 +29,7 @@ class DirPath(BasePath): """A subclass of Path representing a path""" -def generate_path(path: Path): +def get_path(path: Path): if path.is_file(): return FilePath(str(path)) elif path.is_dir(): @@ -42,13 +42,13 @@ def generate_path(path: Path): def generate_dockerfiles(path: Path): - path = generate_path(path) + path = get_path(path) dg = DockerfileGenerator() dg.generate_dockerfiles(path) -def generate_docker_images(path: Path): - DockerfileGenerator.generate_images(path) +def build_docker_images(path: Path): + DockerfileGenerator.build_images(path) class DockerfileGenerator: @@ -121,7 +121,7 @@ def _get_all_bot_files(self, path: DirPath): return bots @staticmethod - def generate_images(path: Path): + def build_images(path: Path): dockerfiles = {file for file in path.iterdir() if file.is_file()} for file in dockerfiles: try: diff --git a/silverback/_cli.py b/silverback/_cli.py index af9ea16d..b7568e87 100644 --- a/silverback/_cli.py +++ b/silverback/_cli.py @@ -17,7 +17,7 @@ from ape.exceptions import Abort, ApeException from fief_client.integrations.cli import FiefAuth -from silverback._build_utils import generate_docker_images, generate_dockerfiles +from silverback._build_utils import build_docker_images, generate_dockerfiles from silverback._click_ext import ( SectionedHelpGroup, auth_required, @@ -143,7 +143,7 @@ def build(generate, path): "You should have a `{path}/` folder in the root of your project." ) - generate_docker_images(path) + build_docker_images(path) @cli.command(cls=ConnectedProviderCommand, section="Local Commands")