Skip to content

Commit

Permalink
Add support for installing custom wheels in Dockerfile
Browse files Browse the repository at this point in the history
  • Loading branch information
zackees committed Mar 25, 2024
1 parent e9e432c commit 2647064
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 35 deletions.
1 change: 1 addition & 0 deletions src/python_compile/assets/debian-dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ RUN echo '#!/bin/sh' > /entrypoint.sh && \
echo 'mkdir /tmp_dir' >> /entrypoint.sh && \
echo 'cd /tmp_dir' >> /entrypoint.sh && \
echo 'if [ -f "/host_dir/requirements.txt" ]; then pip install -r /host_dir/requirements.txt; fi' >> /entrypoint.sh && \
echo 'if [ -f "/host_dir/.compile.whl" ]; then pip install -r /host_dir/.compile.whl; fi' >> /entrypoint.sh && \
echo 'python -m nuitka --standalone --follow-imports --onefile --lto=yes --python-flag=-OO /host_dir/"$@"' >> /entrypoint.sh && \
echo 'for file in $(find /tmp_dir -type f -name "*.bin"); do chmod +x "$file"; done' >> /entrypoint.sh && \
echo 'for file in $(find ;/tmp_dir -type f -name "*.bin"); do gzip "$file"; done' >> /entrypoint.sh && \
Expand Down
10 changes: 5 additions & 5 deletions src/python_compile/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ def parse_args() -> argparse.Namespace:
required=False,
)
parser.add_argument(
"--pip-install-path",
"--wheel",
type=Path,
help="Which pip install path to use",
help="Optional wheel file to install",
required=False,
)
return parser.parse_args()
Expand All @@ -52,11 +52,11 @@ def main() -> int:
os_system = cli_args.os
app_py = cli_args.input
requirements_txt = cli_args.requirements
pip_install_path = cli_args.pip_install_path
wheel = cli_args.wheel
args = Args(
app_py=app_py,
requirements=requirements_txt,
pip_install_path=pip_install_path,
wheel=wheel,
os=os_system,
)
return python_compile(args)
Expand All @@ -65,6 +65,6 @@ def main() -> int:
if __name__ == "__main__":
sys.argv.append("--os")
sys.argv.append("debian")
sys.argv.append("--py-path")
sys.argv.append("--input")
sys.argv.append("src/python_compile/assets/demo_http_server.py")
sys.exit(main())
35 changes: 10 additions & 25 deletions src/python_compile/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
from dataclasses import dataclass
from pathlib import Path

from docker_run_cmd.api import docker_run

from python_compile.docker_build import docker_build
from python_compile.native_build import run_native_build

HERE = Path(__file__).parent
Expand All @@ -25,7 +24,7 @@
class Args:
app_py: Path
requirements: Path | None = None
pip_install_path: Path | None = None
wheel: Path | None = None
os: str | None = None


Expand All @@ -38,7 +37,7 @@ def python_compile(args: Args) -> int:
os_system = args.os
app_py = args.app_py
requirements_txt = args.requirements
pip_install_path = args.pip_install_path
wheel = args.wheel
if os_system == "windows":
if os.name != "nt":
# Work in progress, compile windows apps from docker.
Expand All @@ -47,34 +46,20 @@ def python_compile(args: Args) -> int:
rtn = run_native_build(
app_py=app_py,
requirements_txt=requirements_txt,
pip_install_path=pip_install_path,
wheel=wheel,
)
return rtn
if os_system is None or os_system == "native":
rtn = run_native_build(
app_py=app_py,
requirements_txt=requirements_txt,
pip_install_path=pip_install_path,
wheel=wheel,
)
return rtn

dockerpath: Path | None = DOCKER_FILE_MAP.get(os_system)
if dockerpath is None:
print(f"OS {os_system} is not supported")
return 1
assert dockerpath.exists(), f"dockerpath {dockerpath} does not exist"
py_path = args.app_py
assert Path(py_path).as_posix(), "You must provide a python path"

extra_files: dict[Path, Path] = {}
if args.requirements:
extra_files[Path(args.requirements)] = Path("requirements.txt")

docker_run(
name=f"python-compile-{os_system}",
dockerfile_or_url=dockerpath,
cwd=os.getcwd(),
cmd_list=[py_path],
extra_files=extra_files,
docker_build(
os_system=os_system,
py_path=app_py,
requirements=requirements_txt,
wheel=wheel,
)
return 0
52 changes: 52 additions & 0 deletions src/python_compile/docker_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
Main entry point.
"""

import os
from dataclasses import dataclass
from pathlib import Path

from docker_run_cmd.api import docker_run

HERE = Path(__file__).parent
ASSETS = HERE / "assets"

DOCKER_FILE_MAP = {
"debian": ASSETS / "debian-dockerfile",
"windows": ASSETS
/ "windows-dockerfile", # Work in progress - cross compilation through fedora
"native": None,
}


@dataclass
class Args:
app_py: Path
requirements: Path | None = None
pip_install_path: Path | None = None
os: str | None = None


HERE = Path(__file__).parent
ASSETS = HERE / "assets"


def docker_build(
os_system: str, py_path: Path, requirements: Path | None, wheel: Path | None
) -> int:
dockerpath = DOCKER_FILE_MAP.get(os_system)
assert dockerpath is not None, f"Unknown os_system: {os_system}"
extra_files: dict[Path, Path] = {}
if requirements:
extra_files[requirements] = Path("requirements.txt")
if wheel:
extra_files[wheel] = Path(".compile.whl")

docker_run(
name=f"python-compile-{os_system}",
dockerfile_or_url=dockerpath,
cwd=os.getcwd(),
cmd_list=[str(py_path)],
extra_files=extra_files,
)
return 0
8 changes: 4 additions & 4 deletions src/python_compile/native_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def full_path(path: Path | str) -> str:


def run_native_build(
app_py: Path, requirements_txt: Path | None, pip_install_path: Path | None
app_py: Path, requirements_txt: Path | None, wheel: Path | None
) -> int:
"""Run the native windows build."""
print("Running native build")
Expand All @@ -72,9 +72,9 @@ def run_native_build(
if requirements_txt:
print(f"Installing requirements from {full_path(requirements_txt)}")
iso_env.run(["pip", "install", "-r", requirements_txt])
if pip_install_path:
print(f"Installing {full_path(pip_install_path)}")
iso_env.run(["pip", "install", pip_install_path])
if wheel:
print(f"Installing {full_path(wheel)}")
iso_env.run(["pip", "install", wheel])
cmd_list: list[str] = generate_cmd_list(app_py)
iso_env.run(cmd_list)
basename = app_py.stem
Expand Down
Binary file added tests/data.whl
Binary file not shown.
8 changes: 7 additions & 1 deletion tests/test_debian.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
HERE = Path(__file__).parent
PROJECT_ROOT = HERE.parent
DEMO_PY = PROJECT_ROOT / "src/python_compile/assets/demo_http_server.py"
WHEEL = HERE / "data.whl"

assert DEMO_PY.exists()
assert WHEEL.exists()


class NativeTester(unittest.TestCase):
Expand All @@ -34,6 +38,8 @@ def test_compile(self) -> None:
"src/python_compile/assets/demo_http_server.py",
"--os",
"debian",
"--wheel",
str(WHEEL),
]
cmd_str = subprocess.list2cmdline(cmd_list)
print(f"Running: {cmd_str}")
Expand All @@ -55,7 +61,7 @@ def test_compile_main(self) -> None:
os.chdir(tmp_dir)
try:
shutil.copy(DEMO_PY, DEMO_PY.name)
args = Args(app_py=Path(DEMO_PY.name), os="debian")
args = Args(app_py=Path(DEMO_PY.name), os="debian", wheel=WHEEL)
rtn = python_compile(args)
self.assertEqual(0, rtn)
files = os.listdir(tmp_dir)
Expand Down

0 comments on commit 2647064

Please sign in to comment.