Files
computer-playbook/utils/install/lint/actionlint.py

96 lines
3.0 KiB
Python

"""Install actionlint via GitHub-release prebuilt binary."""
from __future__ import annotations
import os
import platform
import tarfile
import tempfile
from pathlib import Path
from utils.install.github_release import download_release_asset
from utils.install.lint.pinned import resolve_release
from utils.install.primitives import (
ensure_dir_on_path,
install_with_optional_sudo,
log,
which,
)
_DEFAULT_INSTALL_DIR = os.environ.get("ACTIONLINT_INSTALL_DIR", "/usr/local/bin")
def _detect_os() -> str:
system = platform.system()
if system == "Linux":
return "linux"
if system == "Darwin":
return "darwin"
if system == "FreeBSD":
return "freebsd"
raise RuntimeError(f"Unsupported OS for actionlint prebuilt binary: {system}")
def _detect_arch() -> str:
machine = platform.machine().lower()
if machine in ("x86_64", "amd64"):
return "amd64"
if machine in ("i386", "i486", "i586", "i686"):
return "386"
if machine in ("aarch64", "arm64"):
return "arm64"
if machine in ("armv6l", "armv7l"):
return "armv6"
raise RuntimeError(
f"Unsupported architecture for actionlint prebuilt binary: {machine}"
)
def _install_binary() -> None:
slug, version = resolve_release("actionlint")
os_name = _detect_os()
arch = _detect_arch()
archive_name = f"actionlint_{version}_{os_name}_{arch}.tar.gz"
url = f"https://github.com/{slug}/releases/download/v{version}/{archive_name}"
log(f"Installing actionlint v{version} from GitHub releases")
with tempfile.TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
archive_path = tmp_path / archive_name
download_release_asset(url, str(archive_path))
with tarfile.open(archive_path) as tar:
dest_root = tmp_path.resolve()
for member in tar.getmembers():
member_path = (tmp_path / member.name).resolve()
if not member_path.is_relative_to(dest_root):
raise RuntimeError(
f"Archive {archive_name} contains an unsafe path: {member.name}"
)
tar.extractall(tmpdir, filter="data")
binary_src = tmp_path / "actionlint"
if not binary_src.is_file():
raise RuntimeError(
f"Archive {archive_name} did not contain an actionlint binary."
)
install_with_optional_sudo(["install", "-d", _DEFAULT_INSTALL_DIR])
dst = str(Path(_DEFAULT_INSTALL_DIR) / "actionlint")
install_with_optional_sudo(["install", "-m", "0755", str(binary_src), dst])
def ensure() -> None:
if which("actionlint"):
return
log("Missing command 'actionlint'. Installing official prebuilt binary.")
_install_binary()
ensure_dir_on_path(_DEFAULT_INSTALL_DIR)
if not which("actionlint"):
raise RuntimeError(
"Command 'actionlint' is still unavailable after installation."
)