set up docker compose setup
This commit is contained in:
+118
-14
@@ -4,6 +4,7 @@ import os
|
||||
import subprocess
|
||||
import shutil
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
from enum import Enum
|
||||
from typing import List
|
||||
@@ -35,24 +36,130 @@ def get_distro_config(distro_type: DistroType) -> dict:
|
||||
"name": "Debian",
|
||||
"bin_path": "usr/local/bin",
|
||||
"pkg_suffix": "debian",
|
||||
"spec_file": "scripts/spec_scripts/android-file-handler-debian.spec"
|
||||
"spec_file": "scripts/spec_scripts/android-file-handler-debian.spec",
|
||||
"pkg_type": "deb",
|
||||
"architecture": "amd64",
|
||||
"postinstall": "scripts/debian_postinst.sh"
|
||||
},
|
||||
DistroType.ARCH: {
|
||||
"name": "Arch",
|
||||
"bin_path": "usr/bin",
|
||||
"pkg_suffix": "arch",
|
||||
"spec_file": "scripts/spec_scripts/android-file-handler-arch.spec"
|
||||
"spec_file": "scripts/spec_scripts/android-file-handler-arch.spec",
|
||||
"pkg_type": "pacman",
|
||||
"architecture": "x86_64",
|
||||
"postinstall": None
|
||||
},
|
||||
DistroType.RHEL: {
|
||||
"name": "RHEL",
|
||||
"bin_path": "usr/bin",
|
||||
"bin_path": "usr/bin",
|
||||
"pkg_suffix": "rhel",
|
||||
"spec_file": "scripts/spec_scripts/android-file-handler-rhel.spec"
|
||||
"spec_file": "scripts/spec_scripts/android-file-handler-rhel.spec",
|
||||
"pkg_type": "rpm",
|
||||
"architecture": "x86_64",
|
||||
"postinstall": "scripts/rhel_postinst.sh"
|
||||
}
|
||||
}
|
||||
return configs[distro_type]
|
||||
|
||||
|
||||
def validate_version(version: str) -> bool:
|
||||
"""Validate semantic version format."""
|
||||
semver_pattern = r'^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*)?(\+[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*)?$'
|
||||
return bool(re.match(semver_pattern, version))
|
||||
|
||||
|
||||
def get_version() -> str:
|
||||
"""Get version from Poetry and validate it."""
|
||||
result = subprocess.run(
|
||||
["poetry", "version", "-s"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
version = result.stdout.strip()
|
||||
|
||||
if not version:
|
||||
print("ERROR: Version is empty in pyproject.toml")
|
||||
sys.exit(1)
|
||||
|
||||
if not validate_version(version):
|
||||
print(f"ERROR: Invalid version format in pyproject.toml: {version}")
|
||||
print("Expected semantic version format (e.g., 1.2.3, 1.2.3-beta.1, 1.2.3+build.123)")
|
||||
sys.exit(1)
|
||||
|
||||
return version
|
||||
|
||||
|
||||
def package_with_fpm(distro_type: DistroType, version: str, project_root: Path) -> None:
|
||||
"""Package the built application using fpm."""
|
||||
config = get_distro_config(distro_type)
|
||||
pkg_dir = project_root / f"pkg_dist_{config['pkg_suffix']}"
|
||||
dist_dir = project_root / "dist"
|
||||
|
||||
print(f"\n=== Packaging {config['name']} with fpm ===")
|
||||
|
||||
# Ensure dist directory exists
|
||||
dist_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Check if icon exists
|
||||
icon_path = pkg_dir / "usr/share/icons/hicolor/256x256/apps/android-file-handler.png"
|
||||
icon_included = icon_path.exists()
|
||||
|
||||
# Build package items list
|
||||
pkg_items = [
|
||||
f"{config['bin_path']}/android-file-handler",
|
||||
"usr/share/applications/android-file-handler.desktop"
|
||||
]
|
||||
|
||||
if icon_included:
|
||||
pkg_items.append("usr/share/icons/hicolor/256x256/apps/android-file-handler.png")
|
||||
else:
|
||||
print("Note: icon not present, packaging without icon")
|
||||
|
||||
# Build fpm command based on distro type
|
||||
fpm_cmd = [
|
||||
"fpm",
|
||||
"-s", "dir",
|
||||
"-t", config["pkg_type"],
|
||||
"-n", "android-file-handler",
|
||||
"-v", version,
|
||||
"--architecture", config["architecture"],
|
||||
"-C", str(pkg_dir)
|
||||
]
|
||||
|
||||
# Add distro-specific options
|
||||
if distro_type == DistroType.DEBIAN:
|
||||
output_file = dist_dir / f"android-file-handler_{version}_{config['architecture']}.deb"
|
||||
fpm_cmd.extend([
|
||||
"--deb-user", "root",
|
||||
"--deb-group", "root",
|
||||
"--after-install", config["postinstall"],
|
||||
"-p", str(output_file)
|
||||
])
|
||||
elif distro_type == DistroType.ARCH:
|
||||
output_file = dist_dir / f"android-file-handler-{version}-1-{config['architecture']}.pkg.tar.zst"
|
||||
fpm_cmd.extend([
|
||||
"-p", str(output_file)
|
||||
])
|
||||
elif distro_type == DistroType.RHEL:
|
||||
output_file = dist_dir / f"android-file-handler-{version}.{config['architecture']}.rpm"
|
||||
fpm_cmd.extend([
|
||||
"--prefix", "/usr/bin",
|
||||
"--after-install", config["postinstall"],
|
||||
"-p", str(output_file)
|
||||
])
|
||||
|
||||
# Add package items
|
||||
fpm_cmd.extend(pkg_items)
|
||||
|
||||
# Run fpm
|
||||
print(f"Creating package: {output_file}")
|
||||
run_command(fpm_cmd, working_dir=str(project_root))
|
||||
|
||||
print(f"Package created successfully: {output_file}")
|
||||
|
||||
|
||||
def prompt_distro_selection() -> List[DistroType]:
|
||||
"""Prompt user for distro selection."""
|
||||
print("Select distribution(s) to build for:")
|
||||
@@ -60,7 +167,7 @@ def prompt_distro_selection() -> List[DistroType]:
|
||||
print("2. Arch")
|
||||
print("3. RHEL")
|
||||
print("4. All distributions")
|
||||
|
||||
|
||||
while True:
|
||||
choice = input("Enter choice (1-4): ").strip()
|
||||
if choice == "1":
|
||||
@@ -161,7 +268,7 @@ StartupNotify=true
|
||||
pkg_items.append("usr/share/icons/hicolor/256x256/apps/android-file-handler.png")
|
||||
|
||||
# Debug listing
|
||||
print(f"Packaging the following items for {config['name']} (relative to {pkg_dir}):")
|
||||
print(f"Prepared items for {config['name']} (relative to {pkg_dir}):")
|
||||
for item in pkg_items:
|
||||
print(f" - {item}")
|
||||
item_path = pkg_dir / item
|
||||
@@ -171,6 +278,9 @@ StartupNotify=true
|
||||
else:
|
||||
print(f" (missing) {item_path}")
|
||||
|
||||
# Package with fpm
|
||||
package_with_fpm(distro_type, version, project_root)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# Get project root (parent of scripts directory)
|
||||
@@ -211,14 +321,8 @@ def main() -> None:
|
||||
run_command(["poetry", "lock"])
|
||||
run_command(["poetry", "install"])
|
||||
|
||||
# Get version from Poetry
|
||||
result = subprocess.run(
|
||||
["poetry", "version", "-s"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
version = result.stdout.strip()
|
||||
# Get and validate version from Poetry
|
||||
version = get_version()
|
||||
print(f"Version: {version}")
|
||||
|
||||
# Build for selected distributions
|
||||
|
||||
@@ -48,7 +48,7 @@ ENV PATH="$PYENV_ROOT/bin:$PATH"
|
||||
|
||||
RUN git clone https://github.com/pyenv/pyenv.git /root/.pyenv
|
||||
|
||||
# Install Python 3.12 via pyenv with tkinter support
|
||||
# Install Python 3.13 via pyenv with tkinter support
|
||||
# The tk8-devel package must be installed before this step for _tkinter to be compiled
|
||||
RUN eval "$(pyenv init -)" && \
|
||||
LDFLAGS="-L/usr/lib64" \
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# Docker Build Environment
|
||||
|
||||
This directory contains Dockerfiles for building the Android File Handler on different Linux distributions. These images match exactly the images used in the CI/CD pipeline.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Using Docker Compose (Recommended)
|
||||
|
||||
Build for all distributions:
|
||||
```bash
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
Build for a specific distribution:
|
||||
```bash
|
||||
docker-compose up --build debian
|
||||
docker-compose up --build arch
|
||||
docker-compose up --build rhel
|
||||
```
|
||||
|
||||
Build all distributions in parallel:
|
||||
```bash
|
||||
docker-compose up --build --parallel
|
||||
```
|
||||
|
||||
### Manual Docker Build
|
||||
|
||||
Build the image:
|
||||
```bash
|
||||
# Debian
|
||||
docker build -f scripts/docker/Dockerfile.debian -t android-file-handler-debian-builder .
|
||||
|
||||
# Arch
|
||||
docker build -f scripts/docker/Dockerfile.arch -t android-file-handler-arch-builder .
|
||||
|
||||
# RHEL/Fedora
|
||||
docker build -f scripts/docker/Dockerfile.rhel -t android-file-handler-rhel-builder .
|
||||
```
|
||||
|
||||
Run the build:
|
||||
```bash
|
||||
# Debian
|
||||
docker run --rm -v $(pwd):/workspace -w /workspace android-file-handler-debian-builder
|
||||
|
||||
# Arch
|
||||
docker run --rm -v $(pwd):/workspace -w /workspace android-file-handler-arch-builder
|
||||
|
||||
# RHEL/Fedora
|
||||
docker run --rm -v $(pwd):/workspace -w /workspace android-file-handler-rhel-builder
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
After building, you'll find:
|
||||
|
||||
- `dist/` - Final packaged files (.deb, .rpm, .pkg.tar.zst)
|
||||
- `pkg_dist_{distro}/` - Staging directories for package contents
|
||||
- `dist_{distro}/` - PyInstaller build outputs
|
||||
|
||||
## Images
|
||||
|
||||
### Debian Builder
|
||||
- **Image**: `ghcr.io/jmr-dev/android-file-handler-debian-builder:debian13-trixie`
|
||||
- **Base**: `debian:13`
|
||||
- **Python**: 3.13 (via pyenv)
|
||||
- **Tools**: Poetry, fpm, PyInstaller
|
||||
|
||||
### Arch Builder
|
||||
- **Image**: `ghcr.io/jmr-dev/android-file-handler-arch-builder:latest`
|
||||
- **Base**: `archlinux:latest`
|
||||
- **Python**: 3.13 (via pyenv)
|
||||
- **Tools**: Poetry, fpm, PyInstaller
|
||||
|
||||
### RHEL Builder
|
||||
- **Image**: `ghcr.io/jmr-dev/android-file-handler-rhel-builder:fedora42`
|
||||
- **Base**: `fedora:42`
|
||||
- **Python**: 3.13 (via pyenv)
|
||||
- **Tools**: Poetry, fpm, PyInstaller
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Virtualenv Conflicts
|
||||
|
||||
The Docker Compose configuration automatically excludes the host's `.venv` directory to prevent conflicts between the host Python environment and the container Python environment. Each container creates its own virtualenv in `/tmp/poetry-cache`.
|
||||
|
||||
If you encounter virtualenv-related errors, ensure you're using the latest docker-compose.yml configuration.
|
||||
|
||||
## Cleaning Up
|
||||
|
||||
Remove build artifacts:
|
||||
```bash
|
||||
rm -rf dist pkg_dist_* dist_*
|
||||
```
|
||||
|
||||
Remove Docker volumes and containers:
|
||||
```bash
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
### Override FPM Version
|
||||
|
||||
Build with a specific fpm version:
|
||||
```bash
|
||||
docker-compose build --build-arg FPM_VERSION=1.15.0 debian
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
All builds use these environment variables:
|
||||
- `CI_CD=true` - Runs in CI/CD mode
|
||||
- `DISTRO_TYPE` - Set to `debian`, `arch`, or `rhel`
|
||||
- `FPM_VERSION` - Version of fpm to use (default: 1.16.0)
|
||||
|
||||
## Notes
|
||||
|
||||
- All images use Python 3.13 built from source with tkinter support
|
||||
- The builds are identical to what runs in GitHub Actions
|
||||
- Poetry and fpm are pre-installed in all images
|
||||
- The Python build script handles both PyInstaller and fpm packaging
|
||||
Reference in New Issue
Block a user