Skip to content

Commit 9df70c8

Browse files
authored
Merge branch 'main' into feat/docs-update
2 parents 446d098 + db17fdd commit 9df70c8

File tree

9 files changed

+469
-167
lines changed

9 files changed

+469
-167
lines changed

.github/workflows/docs.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ jobs:
2323
with:
2424
python-version: "3.10"
2525

26+
- name: Install Dependencies
27+
run: |
28+
python -m pip install --upgrade pip
29+
pip install .[doc]
30+
2631
- name: Ape Docs
2732
uses: apeworx/sphinx-ape@main
2833
with:

build_docs.py

Lines changed: 0 additions & 89 deletions
This file was deleted.

docs/commands/cluster.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
Cloud Platform
22
==============
3+
CLI commands for interacting with the Silverback Platform.
34

45
.. click:: silverback._cli:login
56
:prog: silverback login
@@ -8,7 +9,12 @@ Cloud Platform
89
.. click:: silverback._cli:cluster
910
:prog: silverback cluster
1011
:nested: full
11-
:commands: workspaces, new, list, info, health
12+
:commands: new, update, list, info, health
13+
14+
.. click:: silverback._cli:workspaces
15+
:prog: silverback cluster workspaces
16+
:nested: full
17+
:commands: new, list, info, update, delete
1218

1319
.. click:: silverback._cli:vars
1420
:prog: silverback cluster vars

docs/commands/run.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
Local Development
22
=================
3+
CLI commands for local development of running Silverback bots and task workers.
34

45
.. click:: silverback._cli:run
56
:prog: silverback run

docs/index.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
.. dynamic-toc-tree::
2+
:commands:
3+
- run
4+
- cluster

silverback/_build_utils.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import shlex
2+
import subprocess
3+
from functools import singledispatchmethod
4+
from pathlib import Path
5+
from typing import Union
6+
7+
import click
8+
from ape.utils.os import clean_path
9+
10+
DOCKERFILE_CONTENT = """
11+
FROM ghcr.io/apeworx/silverback:stable
12+
USER root
13+
WORKDIR /app
14+
RUN chown harambe:harambe /app
15+
USER harambe
16+
"""
17+
18+
19+
# Note: Python3.12 supports subclassing pathlib.Path
20+
class BasePath(Path):
21+
_flavour = type(Path())._flavour # type: ignore
22+
23+
24+
class FilePath(BasePath):
25+
"""A subclass of Path representing a file."""
26+
27+
28+
class DirPath(BasePath):
29+
"""A subclass of Path representing a path"""
30+
31+
32+
def get_path(path: Path):
33+
if path.is_file():
34+
return FilePath(str(path))
35+
elif path.is_dir():
36+
return DirPath(str(path))
37+
else:
38+
raise ValueError(f"{path} is neither a file nor a directory")
39+
40+
41+
PathType = Union["FilePath", "DirPath"]
42+
43+
44+
def generate_dockerfiles(path: Path):
45+
path = get_path(path)
46+
dg = DockerfileGenerator()
47+
dg.generate_dockerfiles(path)
48+
49+
50+
def build_docker_images(path: Path):
51+
DockerfileGenerator.build_images(path)
52+
53+
54+
class DockerfileGenerator:
55+
56+
@property
57+
def dockerfile_name(self):
58+
return self._dockerfile_name
59+
60+
@dockerfile_name.setter
61+
def dockerfile_name(self, name):
62+
self._dockerfile_name = name
63+
64+
@singledispatchmethod
65+
def generate_dockerfiles(self, path: PathType):
66+
"""
67+
Will generate a file based on path type
68+
"""
69+
raise NotImplementedError(f"Path type {type(path)} not supported")
70+
71+
@generate_dockerfiles.register
72+
def _(self, path: FilePath):
73+
dockerfile_content = self._check_for_requirements(DOCKERFILE_CONTENT)
74+
self.dockerfile_name = f"Dockerfile.{path.parent.name}-bot"
75+
dockerfile_content += f"COPY {path.name}/ /app/bot.py\n"
76+
self._build_helper(dockerfile_content)
77+
78+
@generate_dockerfiles.register
79+
def _(self, path: DirPath):
80+
bots = self._get_all_bot_files(path)
81+
for bot in bots:
82+
dockerfile_content = self._check_for_requirements(DOCKERFILE_CONTENT)
83+
if bot.name == "__init__.py" or bot.name == "bot.py":
84+
self.dockerfile_name = f"Dockerfile.{bot.parent.parent.name}-bot"
85+
dockerfile_content += f"COPY {path.name}/ /app/bot\n"
86+
else:
87+
self.dockerfile_name = f"Dockerfile.{bot.name.replace('.py', '')}"
88+
dockerfile_content += f"COPY {path.name}/{bot.name} /app/bot.py\n"
89+
self._build_helper(dockerfile_content)
90+
91+
def _build_helper(self, dockerfile_c: str):
92+
"""
93+
Used in multiple places in build.
94+
"""
95+
dockerfile_path = Path.cwd() / ".silverback-images" / self.dockerfile_name
96+
dockerfile_path.parent.mkdir(exist_ok=True)
97+
dockerfile_path.write_text(dockerfile_c.strip() + "\n")
98+
click.echo(f"Generated {clean_path(dockerfile_path)}")
99+
100+
def _check_for_requirements(self, dockerfile_content):
101+
if (Path.cwd() / "requirements.txt").exists():
102+
dockerfile_content += "COPY requirements.txt .\n"
103+
dockerfile_content += (
104+
"RUN pip install --upgrade pip && pip install -r requirements.txt\n"
105+
)
106+
107+
if (Path.cwd() / "ape-config.yaml").exists():
108+
dockerfile_content += "COPY ape-config.yaml .\n"
109+
dockerfile_content += "RUN ape plugins install -U .\n"
110+
111+
return dockerfile_content
112+
113+
def _get_all_bot_files(self, path: DirPath):
114+
files = sorted({file for file in path.iterdir() if file.is_file()}, reverse=True)
115+
bots = []
116+
for file in files:
117+
if file.name == "__init__.py" or file.name == "bot.py":
118+
bots = [file]
119+
break
120+
bots.append(file)
121+
return bots
122+
123+
@staticmethod
124+
def build_images(path: Path):
125+
dockerfiles = {file for file in path.iterdir() if file.is_file()}
126+
for file in dockerfiles:
127+
try:
128+
command = shlex.split(
129+
"docker build -f "
130+
f"./{file.parent.name}/{file.name} "
131+
f"-t {file.name.split('.')[1]}:latest ."
132+
)
133+
result = subprocess.run(
134+
command,
135+
stdout=subprocess.PIPE,
136+
stderr=subprocess.STDOUT,
137+
text=True,
138+
check=True,
139+
)
140+
click.echo(result.stdout)
141+
except subprocess.CalledProcessError as e:
142+
click.echo("Error during docker build:")
143+
click.echo(e.stderr)
144+
raise

0 commit comments

Comments
 (0)