Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions src/pythainer/builders/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
tailored specifically for Docker environments.
"""
import os
import shutil
import tempfile
from pathlib import Path
from typing import Dict, List

from pythainer.builders.cmds import (
AddPkgDockerBuildCommand,
CopyDockerBuildCommand,
DockerBuildCommand,
StrDockerBuildCommand,
)
Expand Down Expand Up @@ -220,16 +222,15 @@ def add_packages(self, packages: List[str]) -> None:
"""
self._build_commands.append(AddPkgDockerBuildCommand(packages=packages))

def copy(self, filename: PathType, destination: PathType) -> None:
def copy(self, source_path: Path, destination_path: Path) -> None:
"""
Copies a file to the docker container

Parameters:
filename (PathType): The file to copy to the container.
destination (PathType): The location to place the file within the Docker container.
source_path (Path): The file or folder to copy to the container.
destination_path (Path): The location to place the file or folder within the Docker container.
"""
cmd = f"COPY {filename} {destination}"
self._build_commands.append(StrDockerBuildCommand(cmd))
self._build_commands.append(CopyDockerBuildCommand(source_path,destination_path))


class DockerBuilder(PartialDockerBuilder):
Expand Down Expand Up @@ -389,19 +390,25 @@ def build(self, dockerfile_savepath: PathType = "", docker_context: PathType = "
Parameters:
dockerfile_savepath (PathType): Optional path to save the Dockerfile used for the build.
"""

main_dir = Path("/tmp/pythainer/docker/")
mkdir(main_dir)
with tempfile.TemporaryDirectory(
prefix="/tmp/pythainer/docker/docker-build-",
dir=main_dir,
) as temp_dir:

temp_path = Path(temp_dir)
dockerfile_path = (temp_path / "Dockerfile").resolve()
dockerfile_paths = [dockerfile_path] + (
[dockerfile_savepath] if dockerfile_savepath else []
)
self.generate_dockerfile(dockerfile_paths=dockerfile_paths)

data_path = main_dir / "data"

shutil.move(data_path, temp_path)

command = self.get_build_commands(
dockerfile_path=dockerfile_path,
docker_build_dir=Path(docker_context).resolve() if docker_context else temp_path,
Expand All @@ -418,6 +425,7 @@ def build(self, dockerfile_savepath: PathType = "", docker_context: PathType = "
output_is_log=True,
)


def get_runner(
self,
workdir: PathType | None = None,
Expand Down
49 changes: 49 additions & 0 deletions src/pythainer/builders/cmds.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
and package managers.
"""

import os
from pathlib import Path
import shutil
from typing import List


Expand Down Expand Up @@ -68,6 +71,52 @@ def get_str_for_dockerfile(
"""
return str(self._str)

class CopyDockerBuildCommand(DockerBuildCommand):
"""
Represents a simple string command in a Dockerfile, such as a comment or other directive that
does not involve complex logic or conditional behavior.
"""

def __init__(self, source_path:Path ,destination_path:Path) -> None:
"""
Initializes the StrDockerBuildCommand with a string.

Parameters:
s (str): The string that represents this Dockerfile command.
"""
super().__init__()
self._source_path = source_path
self._destination_path = destination_path

# pylint: disable=arguments-differ
def get_str_for_dockerfile(
self,
docker_file_Path: Path,
*args,
**kwargs,
) -> str:
"""
Returns the string that was initialized at the creation of the object.

Returns:
str: The command string.
"""

data_path = Path("/tmp/pythainer/docker/data")

if os.path.isfile(self._source_path):
shutil.copyfile(self._source_path, data_path / self._source_path)
elif os.path.isdir(self._source_path):
shutil.copytree(self._source_path, data_path / self._source_path,dirs_exist_ok=True)
else:
raise FileExistsError(f'{self._source_path} is not a valid target to copy into the docker container')



cmd = f"COPY --chown=${{USER_NAME}} {self._source_path} {self._destination_path}"

return cmd


class AddPkgDockerBuildCommand(DockerBuildCommand):
"""
Expand Down
57 changes: 56 additions & 1 deletion src/pythainer/examples/builders/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
projects like CLSPV.
"""

from typing import Iterable, List
import os
from pathlib import Path
from typing import Iterable, List, Optional

from pythainer.builders import PartialDockerBuilder, UbuntuDockerBuilder
from pythainer.builders.utils import cmake_build_install
Expand Down Expand Up @@ -419,3 +421,56 @@ def qemu_builder(
builder.workdir(path="..")

return builder

def pyvenv_builder(
requirements_file_path:Optional[Path] = None,
dependency_folders:Optional[List[Path]] = None,
single_packages: Optional[List[str]] = None,
lib_dir:Path = Path("/home/${USER_NAME}/workspace/libraries")
) -> PartialDockerBuilder:

"""
Create a python virtual environment given the specified parameters

Parameters:
requirements_file_path (Optional[Path] = None):
Path to a file structured like a requirements.txt
dependency_folders (Optional[List[Path]] = None):
A list of paths that point towards folders with their own
setup.py or pyproject.toml file, to be added to the venv
single_packages:
A list of names of packages such as
"numpy" or "matplotlib" to be added to the venv.
lib_dir:
lib_dir (Path): Directory for libraries and tools.

Returns:
PartialDockerBuilder: A builder that, when composed/applied, creates a venv in the container.
"""

venv_dir = lib_dir / "./python_venv/"
builder = PartialDockerBuilder()

builder.desc("install the python cvenv")
builder.user()
builder.run("mkdir {lib_dir}")
builder.workdir(venv_dir)

builder.run("python3 -m venv .cvenv")
builder.run("./.cvenv/bin/python3 -m pip install --upgrade setuptools pip")

if single_packages:
packagelist = " ".join(single_packages)
builder.run(f"./.cvenv/bin/python3 -m pip install --upgrade {packagelist}")

if requirements_file_path:
builder.copy(requirements_file_path, venv_dir / "./requirements_file/requirements.txt")
builder.run(f"./.cvenv/bin/python3 -m pip install -r {venv_dir / "./requirements_file/requirements.txt"}")

if dependency_folders:
for path in dependency_folders:
builder.copy(path,venv_dir / f"./dependencies/{os.path.basename(os.path.normpath(path))}")
builder.run(f"./.cvenv/bin/python3 -m pip install -e ./dependencies/{os.path.basename(os.path.normpath(path))}/")

builder.env(name="PATH", value=f"$PATH:{venv_dir / ".cvenv/bin/"}")
return builder