#!/usr/bin/python3
# coding: utf-8
# Copyright (c) 2024 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
"""自动化构建 openUBMC Docker 镜像并安全注入 SDK/凭据。"""
from __future__ import annotations

import argparse
import os
import pathlib
import subprocess
import sys
import tempfile
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="构建 openUBMC Docker 镜像，避免在 Dockerfile 中暴露凭据。",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    parser.add_argument(
        "-s",
        "--sdk",
        required=True,
        help="bmc_sdk.zip 的绝对路径（可自定义文件名）",
    )
    parser.add_argument(
        "-u",
        "--username",
        default=os.environ.get("OPENUBMC_USER", ""),
        help="Conan/openUBMC 用户名（也可通过 OPENUBMC_USER 环境变量传入）",
    )
    parser.add_argument(
        "-p",
        "--password",
        default=os.environ.get("OPENUBMC_PASS", ""),
        help="Conan/openUBMC 密码（也可通过 OPENUBMC_PASS 环境变量传入）",
    )
    parser.add_argument(
        "-t", "--tag", default="openubmc/dev:latest", help="生成镜像的标签"
    )
    parser.add_argument(
        "--context",
        default=pathlib.Path(__file__).resolve().parent,
        help="Docker build context（默认 manifest 仓根目录）",
    )
    parser.add_argument(
        "--dockerfile",
        default=pathlib.Path(__file__).resolve().parent / "dockerfile",
        help="Dockerfile 路径",
    )
    return parser.parse_args()


def ensure_file(path: str) -> pathlib.Path:
    file_path = pathlib.Path(path).expanduser().resolve()
    if not file_path.is_file():
        raise FileNotFoundError(f"找不到 SDK 文件: {file_path}")
    return file_path


def write_secret_file(content: str, directory: pathlib.Path, name: str) -> pathlib.Path:
    secret_path = directory / name
    secret_path.write_text(content or "", encoding="utf-8")
    return secret_path


def run_build(args: argparse.Namespace) -> None:
    sdk_file = ensure_file(args.sdk)
    context_dir = pathlib.Path(args.context).resolve()
    dockerfile_path = pathlib.Path(args.dockerfile).resolve()

    if not args.username or not args.password:
        raise Exception(f"用户名或密码为空，请通过-u、-p参数或环境变量传入conan仓用户配置")

    if not dockerfile_path.exists():
        raise FileNotFoundError(f"找不到 Dockerfile: {dockerfile_path}")

    with tempfile.TemporaryDirectory(prefix="openubmc-build-") as tmp_dir:
        tmp_path = pathlib.Path(tmp_dir)
        user_secret = write_secret_file(args.username, tmp_path, "user.secret")
        pass_secret = write_secret_file(args.password, tmp_path, "pass.secret")

        env = os.environ.copy()
        env.setdefault("DOCKER_BUILDKIT", "1")

        cmd = [
            "docker", 
            "build",
            "--file",
            str(dockerfile_path),
            "--tag",
            args.tag,
            "--secret",
            f"id=openubmc_user,src={user_secret}",
            "--secret",
            f"id=openubmc_pass,src={pass_secret}",
            "--build-context",
            f"sdk={sdk_file.parent}",
            "--build-arg",
            f"SDK_ARCHIVE={sdk_file.name}",
            str(context_dir),
        ]

        logging.info("执行: %s", " ".join(cmd))
        subprocess.run(cmd, check=True, env=env)


def main() -> int:
    try:
        args = parse_args()
        run_build(args)
    except subprocess.CalledProcessError as exc:
        logging.error(f"docker 构建失败，退出码 {exc.returncode}")
        return exc.returncode
    except Exception as exc:
        logging.error(f"{exc}")
        return 1
    return 0


if __name__ == "__main__":
    sys.exit(main())

