generated from ApeWorX/project-template
-
-
Notifications
You must be signed in to change notification settings - Fork 14
fix: silverback build missing files during generate #151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 14 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
07ceac3
fix: silverback build missing files during generate
johnson2427 8f19819
fix: black
johnson2427 de83ebb
feat: proper bot bots and python file treatment
johnson2427 3dd34f7
fix: black
johnson2427 9a4d5ae
fix: flake8 issue
johnson2427 3d5f955
refactor: cleanup the build helper function placement
johnson2427 481f0f8
fix: pipe only the stdout
johnson2427 b5ac3d1
feat: allow generate flag to also build
johnson2427 f81c667
feat: add build_utils file
johnson2427 2882ddc
feat: add note about subclassing
johnson2427 2980b22
feat: move image generate to build utils
johnson2427 bc8f155
refactor: clean up some code
johnson2427 ea15206
refactor: more cleanup
johnson2427 eef0aaf
fix: mypy error
johnson2427 08d57dc
fix: use clean_path for home directory
johnson2427 adb76e9
refactorb(build): apply suggestions from code review
fubuloubu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
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 | ||
USER root | ||
WORKDIR /app | ||
RUN chown harambe:harambe /app | ||
USER harambe | ||
""" | ||
|
||
|
||
# Note: Python3.12 supports subclassing pathlib.Path | ||
class BasePath(Path): | ||
_flavour = type(Path())._flavour # type: ignore | ||
|
||
|
||
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) | ||
fubuloubu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
dg = DockerfileGenerator() | ||
dg.generate_dockerfiles(path) | ||
|
||
|
||
def generate_docker_images(path: Path): | ||
fubuloubu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
DockerfileGenerator.generate_images(path) | ||
fubuloubu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
|
||
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 | ||
|
||
@staticmethod | ||
def generate_images(path: Path): | ||
fubuloubu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.