#!/usr/bin/env python3
"""Generate a local make.env with image build settings."""
from __future__ import annotations
import argparse
import datetime as _dt
import os
import subprocess
import sys
from pathlib import Path
DEFAULT_CONFIG = "make.env"
def sanitize(value: str) -> str:
import re
sanitized = re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-")
return sanitized or "local"
def git_output(args: list[str]) -> str:
try:
result = subprocess.run(
args,
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
text=True,
)
except (subprocess.CalledProcessError, FileNotFoundError):
return ""
return result.stdout.strip()
def detect_repo_root(script_path: Path) -> Path:
root = git_output(["git", "rev-parse", "--show-toplevel"])
if root:
return Path(root)
return script_path.parent
def determine_defaults(repo_root: Path) -> dict[str, str]:
branch = git_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]) or "local"
sanitized_branch = sanitize(branch)
short_sha = git_output(["git", "rev-parse", "--short", "HEAD"]) or "latest"
if branch in {"master", "main"}:
tag = git_output(["git", "describe", "--tags", "--abbrev=0"]) or short_sha
# Ensure tag has 'v' prefix (e.g., v3.0.0 not 3.0.0)
if tag and not tag.startswith("v") and tag[0].isdigit():
tag = f"v{tag}"
else:
tag = f"{sanitized_branch}-{short_sha}"
user_hint = os.environ.get("USER", "")
if not user_hint:
git_user = git_output(["git", "config", "user.name"])
user_hint = git_user.replace(" ", "-") if git_user else "local"
registry_default = f"docker.io/{sanitize(user_hint)}"
image_name = repo_root.name
platform = "linux/amd64"
return {
"branch": branch,
"registry": registry_default,
"image_name": image_name,
"tag": tag,
"platform": platform,
}
def prompt(prompt_text: str, default: str) -> str:
if not sys.stdin.isatty():
return default
try:
response = input(f"{prompt_text} [{default}]: ").strip()
except EOFError:
return default
return response or default
def write_config(path: Path, registry: str, image_name: str, tag: str, platform: str) -> None:
timestamp = _dt.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
content = (
f"# Generated by init_make_config.py on {timestamp}\n"
f"REGISTRY={registry}\n"
f"IMAGE_NAME={image_name}\n"
f"TAG={tag}\n"
f"PLATFORM={platform}\n"
)
path.write_text(content, encoding="utf-8")
try:
path.chmod(0o600)
except (PermissionError, NotImplementedError):
pass
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Create or update make.env with build settings")
parser.add_argument("--output", default=DEFAULT_CONFIG, help="Destination file for configuration (default: make.env)")
parser.add_argument("--force", action="store_true", help="Overwrite the configuration file if it already exists")
parser.add_argument("--registry", default=None, help="Registry to use (e.g. docker.io/myuser). Skips the interactive prompt if provided.")
return parser.parse_args()
def main() -> None:
args = parse_args()
script_path = Path(__file__).resolve()
repo_root = detect_repo_root(script_path)
config_path = Path(args.output)
if not config_path.is_absolute():
config_path = repo_root / config_path
if config_path.exists() and not args.force:
raise SystemExit(f"error: {config_path} already exists. Use --force to overwrite.")
defaults = determine_defaults(repo_root)
if args.registry:
registry = args.registry.strip() or defaults["registry"]
else:
registry = prompt("Registry", defaults["registry"])
image_name = defaults["image_name"]
tag = defaults["tag"]
platform = defaults["platform"]
write_config(config_path, registry, image_name, tag, platform)
print("Wrote", config_path)
print(f" REGISTRY={registry}")
print(f" IMAGE_NAME={image_name}")
print(f" TAG={tag}")
print(f" PLATFORM={platform}")
if __name__ == "__main__":
main()