Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

513 lines
16 KiB
Bash
Executable File

#!/usr/bin/env bash
# pip-install-from-git.sh — install perfxpert from the rocm-systems monorepo
# while scoping git submodule init down to the opencode subtree only.
#
# Usage:
# bash scripts/pip-install-from-git.sh
# bash scripts/pip-install-from-git.sh v0.2.0
# bash scripts/pip-install-from-git.sh <SHA> --user
# bash scripts/pip-install-from-git.sh --extras '' --no-deps
#
# Notes:
# - Does not install OS prerequisites by default. If a package is missing,
# the wrapper prints the distro command to run first. Use
# --auto-install-prereqs or PERFXPERT_AUTO_INSTALL_PREREQS=1 only when
# package-manager mutation is intentional.
# - Requires Python 3 + `python -m pip` in the active environment.
# - On Ubuntu 24+ and other externally managed Python environments,
# create and activate a virtual environment first.
# - Prefers the active `python`, then `python3`, then any other
# already-installed `python3.10+` interpreter on PATH. It never
# downloads or installs Python for you.
set -euo pipefail
readonly _DEFAULT_REPO_URL="https://github.com/ROCm/rocm-systems.git"
readonly _SUBDIRECTORY="experimental/python/perfxpert"
readonly _SUBMODULE_SCOPE="experimental/python/perfxpert/opencode"
_AUTO_INSTALL_PREREQS="${PERFXPERT_AUTO_INSTALL_PREREQS:-0}"
_truthy() {
case "${1:-}" in
1|true|TRUE|yes|YES|on|ON)
return 0
;;
*)
return 1
;;
esac
}
_print_python_prereqs() {
cat <<'EOF'
Install the prerequisites first:
Ubuntu 22.04 / 24.04:
apt install -y curl git unzip python3-venv python3-pip
python3 -m venv .venv
RHEL 9:
command -v curl >/dev/null || dnf install -y curl
dnf install -y git unzip python3.11 python3.11-pip
python3.11 -m venv .venv
RHEL 10:
command -v curl >/dev/null || dnf install -y curl
dnf install -y git unzip python3 python3-pip
python3 -m venv .venv
SLES 15.6:
zypper install -y curl git unzip python311 python311-pip
python3.11 -m venv .venv
. .venv/bin/activate
EOF
}
_print_help() {
cat <<'EOF'
pip-install-from-git.sh — install perfxpert from the rocm-systems monorepo
while scoping git submodule init down to the opencode subtree only.
Usage:
bash scripts/pip-install-from-git.sh
bash scripts/pip-install-from-git.sh v0.2.0
bash scripts/pip-install-from-git.sh <SHA> --user
bash scripts/pip-install-from-git.sh --extras '' --no-deps
Options:
--extras <name> Optional extras to install (default: all).
Use `--extras ''` to install the base package only.
--repo-url <url> Override the git remote (default: ROCm/rocm-systems).
--auto-install-prereqs
Explicitly allow apt/dnf/zypper prerequisite installs.
By default the wrapper prints the command and exits.
-h, --help Show this help.
Interpreter selection:
The wrapper prefers the active `python`, then `python3`, then any other
already-installed `python3.10+` interpreter on PATH. It never downloads
or installs a different Python runtime.
OS prerequisite handling:
If git, a supported Python/pip pair, or bun-bootstrap prerequisites
(`curl`/`unzip` when PERFXPERT_AUTO_INSTALL_BUN=1) are missing, the wrapper
prints the exact package-manager command to run first and exits non-zero.
It never runs apt, dnf, zypper, or sudo unless --auto-install-prereqs or
PERFXPERT_AUTO_INSTALL_PREREQS=1 is explicitly set.
Patched perfxpert-code guarantee:
The pip build hook builds the bundled patched opencode binary from the
pinned perfxpert submodule. If bun is missing, pip fails closed with an
actionable message unless PERFXPERT_AUTO_INSTALL_BUN=1 is explicitly set.
The wrapper exits non-zero if that bundled binary is still missing after
install or if the `perfxpert-code` console entry point cannot run.
Supported Ubuntu 24+ flow:
apt install -y curl git unzip python3-venv python3-pip
python3 -m venv .venv
. .venv/bin/activate
bun --version # install bun from your approved package source if this fails
REF=develop; curl -fsSL "https://raw.githubusercontent.com/ROCm/rocm-systems/${REF}/experimental/python/perfxpert/scripts/pip-install-from-git.sh" | bash -s -- "${REF}"
Prerequisite package examples by distro:
Ubuntu 22.04 / 24.04:
apt install -y curl git unzip python3-venv python3-pip
python3 -m venv .venv
RHEL 9:
command -v curl >/dev/null || dnf install -y curl
dnf install -y git unzip python3.11 python3.11-pip
python3.11 -m venv .venv
RHEL 10:
command -v curl >/dev/null || dnf install -y curl
dnf install -y git unzip python3 python3-pip
python3 -m venv .venv
SLES 15.6:
zypper install -y curl git unzip python311 python311-pip
python3.11 -m venv .venv
# SLES ships the supported interpreter as python3.11 after installing
# the python311 packages.
Pin a specific ref, tag, or commit hash:
REF=develop; curl -fsSL "https://raw.githubusercontent.com/ROCm/rocm-systems/${REF}/experimental/python/perfxpert/scripts/pip-install-from-git.sh" | bash -s -- "${REF}"
REF=v0.2.0; curl -fsSL "https://raw.githubusercontent.com/ROCm/rocm-systems/${REF}/experimental/python/perfxpert/scripts/pip-install-from-git.sh" | bash -s -- "${REF}"
REF=<SHA>; curl -fsSL "https://raw.githubusercontent.com/ROCm/rocm-systems/${REF}/experimental/python/perfxpert/scripts/pip-install-from-git.sh" | bash -s -- "${REF}"
If you are NOT using this wrapper and `perfxpert-code` later reports that
the bundled opencode binary is missing, reinstall with the OS prerequisites
available and bun on PATH, or explicitly set PERFXPERT_AUTO_INSTALL_BUN=1
so pip can bootstrap bun and build the pinned submodule bundle.
EOF
}
_die() {
echo "pip-install-from-git: $*" >&2
exit 2
}
_supported_python_with_pip_available() {
local candidate
for candidate in python python3 python3.14 python3.13 python3.12 python3.11 python3.10; do
if ! command -v "${candidate}" >/dev/null 2>&1; then
continue
fi
if "${candidate}" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)' >/dev/null 2>&1 \
&& "${candidate}" -m pip --version >/dev/null 2>&1; then
return 0
fi
done
return 1
}
_run_with_privilege() {
local uid
uid="${EUID:-$(id -u 2>/dev/null || echo 1)}"
if [ "${uid}" = "0" ]; then
"$@"
return
fi
if command -v sudo >/dev/null 2>&1; then
sudo "$@"
return
fi
return 127
}
_install_os_prereqs_if_needed() {
local -a missing
missing=()
local need_curl need_git need_unzip need_python need_bun_bootstrap_prereqs
need_curl=0
need_git=0
need_unzip=0
need_python=0
need_bun_bootstrap_prereqs=0
if ! command -v bun >/dev/null 2>&1 && _truthy "${PERFXPERT_AUTO_INSTALL_BUN:-0}"; then
need_bun_bootstrap_prereqs=1
fi
if [ "${need_bun_bootstrap_prereqs}" = "1" ] && ! command -v curl >/dev/null 2>&1; then
missing+=("curl")
need_curl=1
fi
if ! command -v git >/dev/null 2>&1; then
missing+=("git")
need_git=1
fi
if [ "${need_bun_bootstrap_prereqs}" = "1" ] && ! command -v unzip >/dev/null 2>&1; then
missing+=("unzip")
need_unzip=1
fi
if ! _supported_python_with_pip_available; then
missing+=("python3.10+ with pip")
need_python=1
fi
if [ "${#missing[@]}" -eq 0 ]; then
return 0
fi
echo "pip-install-from-git: missing OS prerequisites: ${missing[*]}" >&2
if ! _truthy "${_AUTO_INSTALL_PREREQS}"; then
{
echo "pip-install-from-git: refusing to auto-install prerequisites by default."
echo "pip-install-from-git: install the packages manually, then rerun the wrapper:"
echo
_print_python_prereqs
echo
echo "To allow this wrapper to run apt/dnf/zypper explicitly, rerun with:"
echo " PERFXPERT_AUTO_INSTALL_PREREQS=1 bash scripts/pip-install-from-git.sh ..."
echo "or:"
echo " bash scripts/pip-install-from-git.sh --auto-install-prereqs ..."
} >&2
exit 2
fi
echo "pip-install-from-git: explicit prerequisite auto-install enabled; attempting package-manager install" >&2
if command -v apt-get >/dev/null 2>&1; then
local -a apt_packages
apt_packages=()
[ "${need_curl}" = "1" ] && apt_packages+=("curl")
[ "${need_git}" = "1" ] && apt_packages+=("git")
[ "${need_unzip}" = "1" ] && apt_packages+=("unzip")
[ "${need_python}" = "1" ] && apt_packages+=("python3-venv" "python3-pip")
if ! _run_with_privilege apt-get update; then
_die "failed to run apt-get update. Install prerequisites manually:
$(_print_python_prereqs)"
fi
if ! _run_with_privilege apt-get install -y "${apt_packages[@]}"; then
_die "failed to install prerequisites with apt-get. Install them manually:
$(_print_python_prereqs)"
fi
return 0
fi
if command -v dnf >/dev/null 2>&1; then
local version_major
local -a dnf_packages
version_major=""
dnf_packages=()
if [ -r /etc/os-release ]; then
version_major="$( (. /etc/os-release; printf '%s' "${VERSION_ID%%.*}") 2>/dev/null || true )"
fi
[ "${need_curl}" = "1" ] && dnf_packages+=("curl")
[ "${need_git}" = "1" ] && dnf_packages+=("git")
[ "${need_unzip}" = "1" ] && dnf_packages+=("unzip")
if [ "${version_major}" = "9" ]; then
[ "${need_python}" = "1" ] && dnf_packages+=("python3.11" "python3.11-pip")
if ! _run_with_privilege dnf install -y "${dnf_packages[@]}"; then
_die "failed to install prerequisites with dnf. Install them manually:
$(_print_python_prereqs)"
fi
else
[ "${need_python}" = "1" ] && dnf_packages+=("python3" "python3-pip")
if ! _run_with_privilege dnf install -y "${dnf_packages[@]}"; then
_die "failed to install prerequisites with dnf. Install them manually:
$(_print_python_prereqs)"
fi
fi
return 0
fi
if command -v zypper >/dev/null 2>&1; then
local -a zypper_packages
zypper_packages=()
[ "${need_curl}" = "1" ] && zypper_packages+=("curl")
[ "${need_git}" = "1" ] && zypper_packages+=("git")
[ "${need_unzip}" = "1" ] && zypper_packages+=("unzip")
[ "${need_python}" = "1" ] && zypper_packages+=("python311" "python311-pip")
if ! _run_with_privilege zypper --non-interactive install -y "${zypper_packages[@]}"; then
_die "failed to install prerequisites with zypper. Install them manually:
$(_print_python_prereqs)"
fi
return 0
fi
_die "no supported package manager found for missing prerequisites. Install them manually:
$(_print_python_prereqs)"
}
for _arg in "$@"; do
case "${_arg}" in
--auto-install-prereqs)
_AUTO_INSTALL_PREREQS=1
;;
--)
break
;;
-h|--help)
_print_help
exit 0
;;
esac
done
_verify_bundled_perfxpert_code() {
"${_PYTHON}" -c '
from importlib import resources
import os
import sys
path = resources.files("perfxpert") / "_bundled" / "opencode"
if not path.is_file():
print(f"missing bundled opencode: {path}", file=sys.stderr)
raise SystemExit(1)
if not os.access(path, os.X_OK):
print(f"bundled opencode is not executable: {path}", file=sys.stderr)
raise SystemExit(1)
print(path)
'
}
_pip_args_include_user() {
local arg
for arg in "${_PIP_ARGS[@]:-}"; do
if [ "${arg}" = "--user" ]; then
return 0
fi
done
return 1
}
_python_scripts_dir() {
if _pip_args_include_user; then
"${_PYTHON}" -c 'import site; print(site.USER_BASE + "/bin")'
else
"${_PYTHON}" -c 'import sysconfig; print(sysconfig.get_path("scripts"))'
fi
}
_verify_perfxpert_code_entrypoint() {
local scripts_dir exe
if ! scripts_dir="$(_python_scripts_dir)" || [ -z "${scripts_dir}" ]; then
echo "could not resolve the selected Python scripts directory" >&2
return 1
fi
exe="${scripts_dir%/}/perfxpert-code"
if [ ! -x "${exe}" ]; then
echo "missing executable perfxpert-code console script at ${exe}" >&2
return 1
fi
if ! "${exe}" --version >/dev/null 2>&1; then
echo "perfxpert-code console script exists but failed --version: ${exe}" >&2
return 1
fi
printf '%s\n' "${exe}"
}
_install_os_prereqs_if_needed
_PYTHON=""
for _candidate in python python3 python3.14 python3.13 python3.12 python3.11 python3.10; do
if ! command -v "${_candidate}" >/dev/null 2>&1; then
continue
fi
if "${_candidate}" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)' >/dev/null 2>&1 \
&& "${_candidate}" -m pip --version >/dev/null 2>&1; then
_PYTHON="${_candidate}"
break
fi
done
if [ -z "${_PYTHON}" ]; then
{
echo "pip-install-from-git: Python 3.10+ is required."
echo
_print_python_prereqs
} >&2
exit 2
fi
if ! command -v git >/dev/null 2>&1; then
{
cat <<'EOF'
pip-install-from-git: `git` is required for the GitHub install path.
EOF
echo
_print_python_prereqs
} >&2
exit 2
fi
if ! "${_PYTHON}" -m pip --version >/dev/null 2>&1; then
{
cat <<'EOF'
pip-install-from-git: `python -m pip` is unavailable in the current environment.
EOF
echo
_print_python_prereqs
} >&2
exit 2
fi
_IN_VENV="$("${_PYTHON}" -c 'import sys; print("1" if sys.prefix != getattr(sys, "base_prefix", sys.prefix) or hasattr(sys, "real_prefix") else "0")')"
_EXTERNALLY_MANAGED="$("${_PYTHON}" -c 'import pathlib, sysconfig; print(pathlib.Path(sysconfig.get_path("stdlib")) / "EXTERNALLY-MANAGED")')"
if [ "${_IN_VENV}" != "1" ] && [ -f "${_EXTERNALLY_MANAGED}" ]; then
{
cat <<'EOF'
pip-install-from-git: the current Python is externally managed.
EOF
echo
echo "Use a virtual environment first:"
_print_python_prereqs
echo ' REF=develop; curl -fsSL "https://raw.githubusercontent.com/ROCm/rocm-systems/${REF}/experimental/python/perfxpert/scripts/pip-install-from-git.sh" | bash -s -- "${REF}"'
} >&2
exit 2
fi
_REF=""
_EXTRAS="all"
_REPO_URL="${_DEFAULT_REPO_URL}"
declare -a _PIP_ARGS=()
while [ "$#" -gt 0 ]; do
case "$1" in
-h|--help)
_print_help
exit 0
;;
--extras)
[ "$#" -ge 2 ] || _die "--extras requires a value"
_EXTRAS="$2"
shift 2
;;
--repo-url)
[ "$#" -ge 2 ] || _die "--repo-url requires a value"
_REPO_URL="$2"
shift 2
;;
--auto-install-prereqs)
shift
;;
--)
shift
while [ "$#" -gt 0 ]; do
_PIP_ARGS+=("$1")
shift
done
;;
-*)
_PIP_ARGS+=("$1")
shift
;;
*)
if [ -z "${_REF}" ]; then
_REF="$1"
else
_PIP_ARGS+=("$1")
fi
shift
;;
esac
done
_PACKAGE="perfxpert"
if [ -n "${_EXTRAS}" ]; then
_PACKAGE="${_PACKAGE}[${_EXTRAS}]"
fi
_VCS_TARGET="git+${_REPO_URL}"
if [ -n "${_REF}" ]; then
_VCS_TARGET="${_VCS_TARGET}@${_REF}"
fi
if [[ "${_REPO_URL}" == file://* ]]; then
# Older pip releases reject the PEP 508 direct-reference form for
# git+file URLs. Keep the customer HTTPS path on PEP 508, but use pip's
# VCS URL form for local validation and air-gap mirrors.
_SPEC="${_VCS_TARGET}#egg=${_PACKAGE}&subdirectory=${_SUBDIRECTORY}"
else
_SPEC="${_PACKAGE} @ ${_VCS_TARGET}#subdirectory=${_SUBDIRECTORY}"
fi
echo "pip-install-from-git: installing ${_SPEC}" >&2
GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0=submodule.active \
GIT_CONFIG_VALUE_0="${_SUBMODULE_SCOPE}" \
"${_PYTHON}" -m pip install "${_PIP_ARGS[@]}" "${_SPEC}"
if ! _BUNDLED_OPENCODE="$(_verify_bundled_perfxpert_code)"; then
cat >&2 <<'EOF'
pip-install-from-git: install finished, but the bundled patched opencode binary was not produced.
`perfxpert analyze`, `perfxpert-mcp`, and the Python API may still be installed,
but this wrapper requires `perfxpert-code` to be ready end-to-end.
Check the build output above, then retry the same command.
EOF
exit 2
fi
if ! _PERFXPERT_CODE="$(_verify_perfxpert_code_entrypoint)"; then
cat >&2 <<'EOF'
pip-install-from-git: install finished, but the `perfxpert-code` console entry point is not usable.
`perfxpert analyze`, `perfxpert-mcp`, and the Python API may still be installed,
but this wrapper requires `perfxpert-code --version` to run and the bundled
patched opencode binary to exist. Check the build output above, then retry the same command.
EOF
exit 2
fi
echo "pip-install-from-git: perfxpert-code ready at ${_PERFXPERT_CODE}" >&2
echo "pip-install-from-git: bundled patched opencode ready at ${_BUNDLED_OPENCODE}" >&2