130 lines
3.8 KiB
Python
130 lines
3.8 KiB
Python
"""
|
|
构建并上传 forge 编译环境镜像
|
|
|
|
默认仓库是 docker.pchuan.top/forge
|
|
|
|
1. 读取目标容器配置
|
|
2. 检查目标 Dockerfile
|
|
3. 根据目标目录源码时间生成 SOURCE_VERSION
|
|
4. 执行 docker build 并打上目标 tag
|
|
5. 默认执行 docker push 上传镜像
|
|
|
|
- target 支持 ubuntu 和 bun
|
|
- --no-push 只构建不上传
|
|
- --force-build 使用 docker build --no-cache
|
|
- --platform linux/amd64 指定构建平台
|
|
"""
|
|
|
|
import argparse
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
|
|
# 基础配置
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
REGISTRY = "docker.pchuan.top"
|
|
NAMESPACE = "forge"
|
|
|
|
# 目标容器配置
|
|
TARGETS = {
|
|
"ubuntu": {
|
|
"context": "ubuntu",
|
|
"image_name": "ubuntu",
|
|
"build_args": {},
|
|
},
|
|
"bun": {
|
|
"context": "bun",
|
|
"image_name": "bun",
|
|
"build_args": {
|
|
"BASE_IMAGE": "docker.pchuan.top/forge/ubuntu:latest",
|
|
"BUN_REGISTRY": "https://registry.npmmirror.com/",
|
|
},
|
|
},
|
|
}
|
|
|
|
|
|
parser = argparse.ArgumentParser(description="构建并上传 forge 编译环境镜像")
|
|
parser.add_argument("target", choices=TARGETS.keys(), help="目标容器")
|
|
parser.add_argument("--registry", default=REGISTRY, help="镜像仓库地址")
|
|
parser.add_argument("--namespace", default=NAMESPACE, help="镜像命名空间")
|
|
parser.add_argument("--tag", default="latest", help="镜像 tag")
|
|
parser.add_argument("--no-push", action="store_true", help="只构建不上传")
|
|
parser.add_argument("--force-build", action="store_true", help="强制无缓存构建")
|
|
parser.add_argument("--platform", default="", help="目标平台,例如 linux/amd64")
|
|
parser.add_argument("--base-image", default="", help="覆盖 bun 的基础镜像")
|
|
parser.add_argument("--bun-registry", default="", help="覆盖 bun 的 npm registry")
|
|
args = parser.parse_args()
|
|
|
|
target = TARGETS[args.target]
|
|
context = ROOT / target["context"]
|
|
dockerfile = context / "Dockerfile"
|
|
image = (
|
|
f"{args.registry.rstrip('/')}/"
|
|
f"{args.namespace.strip('/')}/"
|
|
f"{target['image_name']}:{args.tag}"
|
|
)
|
|
|
|
if not dockerfile.exists():
|
|
print(f"[NO] {args.target} Dockerfile exists")
|
|
print(f"reason: not found: {dockerfile}")
|
|
raise SystemExit(1)
|
|
|
|
# 真实 .env 和 logs 不参与 SOURCE_VERSION
|
|
source_files = [
|
|
path
|
|
for path in context.rglob("*")
|
|
if path.is_file()
|
|
and path.name != ".env"
|
|
and "logs" not in path.relative_to(context).parts
|
|
]
|
|
source_version = str(max((path.stat().st_mtime_ns for path in source_files), default=0))
|
|
|
|
build_args = dict(target["build_args"])
|
|
build_args["SOURCE_VERSION"] = source_version
|
|
|
|
if args.target == "bun" and args.base_image:
|
|
build_args["BASE_IMAGE"] = args.base_image
|
|
|
|
if args.target == "bun" and args.bun_registry:
|
|
build_args["BUN_REGISTRY"] = args.bun_registry
|
|
|
|
# 直接使用 Dockerfile 构建,不读取目标目录里的 .env
|
|
build_command = [
|
|
"docker",
|
|
"build",
|
|
"--file",
|
|
str(dockerfile),
|
|
"--tag",
|
|
image,
|
|
]
|
|
|
|
for name, value in build_args.items():
|
|
build_command += ["--build-arg", f"{name}={value}"]
|
|
|
|
if args.platform:
|
|
build_command += ["--platform", args.platform]
|
|
|
|
if args.force_build:
|
|
build_command += ["--no-cache"]
|
|
|
|
build_command += [str(context)]
|
|
|
|
print(f"[INFO] target={args.target}")
|
|
print(f"[INFO] image={image}")
|
|
print("[RUN] Build image")
|
|
print("[INFO] " + " ".join(build_command))
|
|
subprocess.run(build_command, cwd=ROOT, check=True)
|
|
print("[PASS] Build image")
|
|
|
|
# 默认上传镜像,使用 --no-push 可以只构建不上传
|
|
if not args.no_push:
|
|
push_command = ["docker", "push", image]
|
|
print("[RUN] Push image")
|
|
print("[INFO] " + " ".join(push_command))
|
|
subprocess.run(push_command, cwd=ROOT, check=True)
|
|
print("[PASS] Push image")
|
|
else:
|
|
print("[INFO] --no-push, skip docker push")
|
|
|
|
print("[PASS] build script completed")
|