Skip to content

Instantly share code, notes, and snippets.

@hbina
Created November 1, 2025 05:45
Show Gist options
  • Select an option

  • Save hbina/e56dff3be980004187b275d85f15f34f to your computer and use it in GitHub Desktop.

Select an option

Save hbina/e56dff3be980004187b275d85f15f34f to your computer and use it in GitHub Desktop.
Python script to manage docker builds
#!/usr/bin/env python3
"""
Docker management script for GCC 15.2.0 builder.
Replaces docker-compose with simple Python commands.
"""
import subprocess
import sys
import argparse
IMAGE_NAME = "gcc15-builder:latest"
VOLUMES = ["gcc-build", "gcc-install", "yaml-cpp-build"]
MEMORY_LIMIT = "8g"
SHM_SIZE = "2g"
PROJECT_DIR = "/yaml-cpp"
def run_command(cmd, check=True, stream_output=False):
"""Run a shell command and handle errors."""
print(f"Running: {' '.join(cmd)}")
try:
if stream_output:
# Stream output in real-time for long-running commands
result = subprocess.run(cmd, check=check, text=True)
return result.returncode == 0
else:
result = subprocess.run(cmd, check=check, text=True, capture_output=True)
if result.stdout:
print(result.stdout)
return result.returncode == 0
except subprocess.CalledProcessError as e:
if hasattr(e, 'stderr') and e.stderr:
print(f"Error: {e.stderr}", file=sys.stderr)
if check:
sys.exit(1)
return False
def build():
"""Build the Docker image."""
print("Building Docker image...")
cmd = ["docker", "build", "-t", IMAGE_NAME, "."]
run_command(cmd)
print(f"✓ Image '{IMAGE_NAME}' built successfully")
def create_volumes():
"""Create Docker volumes if they don't exist."""
for volume in VOLUMES:
# Check if volume exists
check_cmd = ["docker", "volume", "inspect", volume]
exists = run_command(check_cmd, check=False)
if not exists:
print(f"Creating volume '{volume}'...")
create_cmd = ["docker", "volume", "create", volume]
run_command(create_cmd)
else:
print(f"Volume '{volume}' already exists")
def run():
"""Run the GCC build non-interactively inside the container."""
# Create volumes first
create_volumes()
print("Starting GCC compilation in container...")
print("This will take 30-60 minutes depending on your CPU.")
print("Output will be streamed in real-time.\n")
cmd = [
"docker", "run",
"--rm", # Remove container when it exits
"-v", f"{VOLUMES[0]}:/gcc-build",
"-v", f"{VOLUMES[1]}:/gcc-install",
"-w", "/gcc-build",
"--memory", MEMORY_LIMIT,
"--shm-size", SHM_SIZE,
IMAGE_NAME,
"/home/builder/build-gcc.sh" # Run the build script automatically
]
# Stream output in real-time
run_command(cmd, stream_output=True)
print("\n✓ Build complete! GCC installed to gcc-install volume")
print("Run './docker-manager.py test' to verify the installation")
def clean():
"""Remove Docker volumes."""
print("Removing Docker volumes...")
for volume in VOLUMES:
# Check if volume exists before trying to remove
check_cmd = ["docker", "volume", "inspect", volume]
exists = run_command(check_cmd, check=False)
if exists:
print(f"Removing volume '{volume}'...")
remove_cmd = ["docker", "volume", "rm", volume]
run_command(remove_cmd)
else:
print(f"Volume '{volume}' does not exist, skipping")
print("✓ Cleanup complete")
def test():
"""Test the built GCC by running gcc --version."""
print("Testing GCC installation...")
cmd = [
"docker", "run",
"--rm",
"-v", f"{VOLUMES[1]}:/gcc-install",
IMAGE_NAME,
"/gcc-install/bin/gcc", "--version"
]
run_command(cmd, stream_output=True)
def build_yaml_cpp():
"""Build yaml-cpp project using the built GCC 15."""
# Create volumes first
create_volumes()
print("Building yaml-cpp with GCC 15...")
print("This will compile the yaml-cpp library and tools.\\n")
# Get the current directory (yaml-cpp source)
import os
yaml_cpp_source = os.path.abspath(os.path.dirname(__file__))
cmd = [
"docker", "run",
"--rm",
"--user", "root", # Run as root to fix permissions
"-v", f"{VOLUMES[1]}:/gcc-install", # GCC installation
"-v", f"{VOLUMES[2]}:/yaml-cpp-build", # yaml-cpp build output
"-v", f"{yaml_cpp_source}:{PROJECT_DIR}:ro", # yaml-cpp source (read-only)
"-w", "/yaml-cpp-build",
"--memory", MEMORY_LIMIT,
"--shm-size", SHM_SIZE,
IMAGE_NAME,
"/bin/bash", "-c",
"""
# Fix ownership of build directory
chown -R builder:builder /yaml-cpp-build
# Switch to builder user and run the build
su - builder -c '
export PATH=/gcc-install/bin:$PATH
export LD_LIBRARY_PATH=/gcc-install/lib64:/gcc-install/lib:$LD_LIBRARY_PATH
cd /yaml-cpp-build
echo "=== GCC Version ==="
gcc --version
echo ""
echo "=== Configuring yaml-cpp with CMake ==="
cmake {project_dir} \\
-DCMAKE_C_COMPILER=/gcc-install/bin/gcc \\
-DCMAKE_CXX_COMPILER=/gcc-install/bin/g++ \\
-DCMAKE_BUILD_TYPE=Release \\
-DYAML_CPP_BUILD_TESTS=ON \\
-DYAML_CPP_BUILD_TOOLS=ON \\
-DYAML_BUILD_SHARED_LIBS=OFF
echo ""
echo "=== Building yaml-cpp ==="
make -j$(nproc)
echo ""
echo "=== Build Summary ==="
ls -lh libyaml-cpp.a 2>/dev/null || echo "Static library not found"
ls -lh util/ 2>/dev/null || echo "Tools not found"
'
""".format(project_dir=PROJECT_DIR)
]
run_command(cmd, stream_output=True)
print("\\n✓ yaml-cpp build complete! Output saved to yaml-cpp-build volume")
print("Run './builder.py test-yaml-cpp' to verify the build")
def test_yaml_cpp():
"""Test the built yaml-cpp by checking the library and running parse tool."""
print("Testing yaml-cpp build...")
cmd = [
"docker", "run",
"--rm",
"-v", f"{VOLUMES[1]}:/gcc-install",
"-v", f"{VOLUMES[2]}:/yaml-cpp-build",
IMAGE_NAME,
"/bin/bash", "-c",
"""
export LD_LIBRARY_PATH=/gcc-install/lib64:/gcc-install/lib:$LD_LIBRARY_PATH
echo "=== Library Info ==="
file /yaml-cpp-build/libyaml-cpp.a
ls -lh /yaml-cpp-build/libyaml-cpp.a
echo ""
echo "=== Parse Tool ==="
if [ -f /yaml-cpp-build/util/parse ]; then
/yaml-cpp-build/util/parse --help 2>&1 || echo "Parse tool exists"
else
echo "Parse tool not found"
fi
"""
]
run_command(cmd, stream_output=True)
def build_all():
"""Build GCC 15 first, then build yaml-cpp with it."""
print("=== Stage 1: Building GCC 15 from source ===\\n")
run()
print("\\n=== Stage 2: Building yaml-cpp with GCC 15 ===\\n")
build_yaml_cpp()
print("\\n=== All builds complete! ===")
print("GCC 15 is in gcc-install volume")
print("yaml-cpp build is in yaml-cpp-build volume")
def shell():
"""Start an interactive shell in the container."""
create_volumes()
print("Starting interactive shell in container...")
print("Type 'exit' to leave the container.\n")
cmd = [
"docker", "run", "-it",
"--rm",
"-v", f"{VOLUMES[0]}:/gcc-build",
"-v", f"{VOLUMES[1]}:/gcc-install",
"-w", "/gcc-build",
"--memory", MEMORY_LIMIT,
"--shm-size", SHM_SIZE,
IMAGE_NAME,
"/bin/bash"
]
subprocess.call(cmd)
def status():
"""Show status of volumes and images."""
print("=== Docker Image ===")
cmd = ["docker", "images", IMAGE_NAME]
run_command(cmd, check=False)
print("\n=== Docker Volumes ===")
for volume in VOLUMES:
cmd = ["docker", "volume", "inspect", volume]
if run_command(cmd, check=False):
# Get volume size
size_cmd = ["docker", "system", "df", "-v", "--format", "{{.Name}}\t{{.Size}}"]
run_command(size_cmd, check=False)
def main():
parser = argparse.ArgumentParser(
description="Manage GCC 15.2.0 builder and yaml-cpp compilation",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s build Build the Docker image
%(prog)s run Compile GCC inside container (non-interactive)
%(prog)s test Test the built GCC version
%(prog)s build-yaml-cpp Build yaml-cpp with GCC 15
%(prog)s test-yaml-cpp Test the yaml-cpp build
%(prog)s build-all Build GCC 15 and then yaml-cpp
%(prog)s shell Start interactive bash shell in container
%(prog)s clean Remove all volumes (clears build data)
%(prog)s status Show current status
"""
)
parser.add_argument(
"command",
choices=["build", "run", "test", "build-yaml-cpp", "test-yaml-cpp",
"build-all", "shell", "clean", "status"],
help="Command to execute"
)
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
# Execute the requested command
commands = {
"build": build,
"run": run,
"test": test,
"build-yaml-cpp": build_yaml_cpp,
"test-yaml-cpp": test_yaml_cpp,
"build-all": build_all,
"shell": shell,
"clean": clean,
"status": status,
}
commands[args.command]()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment