Adds requirements, streamlines CLI helper procedures
This commit is contained in:
350
tools/setup.sh
Executable file
350
tools/setup.sh
Executable file
@@ -0,0 +1,350 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -u
|
||||
|
||||
ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
VENV_DIR="${HOME}/.local/share/ffx.venv"
|
||||
VENV_BIN_DIR="${VENV_DIR}/bin"
|
||||
VENV_PYTHON="${VENV_BIN_DIR}/python"
|
||||
VENV_PIP="${VENV_BIN_DIR}/pip"
|
||||
VENV_FFX="${VENV_BIN_DIR}/ffx"
|
||||
BASHRC_FILE="${HOME}/.bashrc"
|
||||
ALIAS_BLOCK_BEGIN="# >>> ffx alias >>>"
|
||||
ALIAS_BLOCK_END="# <<< ffx alias <<<"
|
||||
ALIAS_LINE="alias ffx=\"${VENV_FFX}\""
|
||||
|
||||
CHECK_ONLY=0
|
||||
READINESS_FAILURES=0
|
||||
INSTALL_FAILURES=0
|
||||
|
||||
COLOR_RESET=""
|
||||
COLOR_GREEN=""
|
||||
COLOR_YELLOW=""
|
||||
COLOR_RED=""
|
||||
|
||||
if [ -t 1 ]; then
|
||||
COLOR_RESET="$(printf '\033[0m')"
|
||||
COLOR_GREEN="$(printf '\033[32m')"
|
||||
COLOR_YELLOW="$(printf '\033[33m')"
|
||||
COLOR_RED="$(printf '\033[31m')"
|
||||
fi
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [--check] [--help]
|
||||
|
||||
Prepare the persistent FFX bundle virtualenv at:
|
||||
${VENV_DIR}
|
||||
|
||||
Actions:
|
||||
- create or reuse ${VENV_DIR}
|
||||
- install this repository into the venv with pip --editable
|
||||
- ensure ${BASHRC_FILE} exposes alias ffx -> ${VENV_FFX}
|
||||
|
||||
Options:
|
||||
--check Report readiness only. Do not create or modify anything.
|
||||
--help Show this help text.
|
||||
EOF
|
||||
}
|
||||
|
||||
status_ok() {
|
||||
printf '%sok%s' "${COLOR_GREEN}" "${COLOR_RESET}"
|
||||
}
|
||||
|
||||
status_warn() {
|
||||
printf '%swarn%s' "${COLOR_YELLOW}" "${COLOR_RESET}"
|
||||
}
|
||||
|
||||
status_fail() {
|
||||
printf '%sfailed%s' "${COLOR_RED}" "${COLOR_RESET}"
|
||||
}
|
||||
|
||||
report_component() {
|
||||
local level="$1"
|
||||
local label="$2"
|
||||
local detail="$3"
|
||||
local rendered_status=""
|
||||
|
||||
case "${level}" in
|
||||
ok)
|
||||
rendered_status="$(status_ok)"
|
||||
;;
|
||||
warn)
|
||||
rendered_status="$(status_warn)"
|
||||
;;
|
||||
*)
|
||||
rendered_status="$(status_fail)"
|
||||
;;
|
||||
esac
|
||||
|
||||
printf '[%s] %s%s\n' "${rendered_status}" "${label}" "${detail:+: $detail}"
|
||||
}
|
||||
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
check_python3() {
|
||||
command_exists python3
|
||||
}
|
||||
|
||||
check_venv_dir() {
|
||||
[ -x "${VENV_PYTHON}" ]
|
||||
}
|
||||
|
||||
check_venv_pip() {
|
||||
check_venv_dir && "${VENV_PIP}" --version >/dev/null 2>&1
|
||||
}
|
||||
|
||||
check_venv_ffx() {
|
||||
[ -x "${VENV_FFX}" ]
|
||||
}
|
||||
|
||||
check_bashrc_file() {
|
||||
[ -f "${BASHRC_FILE}" ]
|
||||
}
|
||||
|
||||
check_bashrc_alias() {
|
||||
check_bashrc_file && grep -Fqx "${ALIAS_LINE}" "${BASHRC_FILE}"
|
||||
}
|
||||
|
||||
detail_python3() {
|
||||
command -v python3 || printf "command 'python3' not found"
|
||||
}
|
||||
|
||||
detail_venv_dir() {
|
||||
if check_venv_dir; then
|
||||
printf '%s' "${VENV_DIR}"
|
||||
else
|
||||
printf 'missing %s' "${VENV_DIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
detail_venv_pip() {
|
||||
if check_venv_pip; then
|
||||
"${VENV_PIP}" --version
|
||||
else
|
||||
printf 'missing pip in %s' "${VENV_DIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
detail_venv_ffx() {
|
||||
if check_venv_ffx; then
|
||||
printf '%s' "${VENV_FFX}"
|
||||
else
|
||||
printf 'missing %s' "${VENV_FFX}"
|
||||
fi
|
||||
}
|
||||
|
||||
detail_bashrc_file() {
|
||||
if check_bashrc_file; then
|
||||
printf '%s' "${BASHRC_FILE}"
|
||||
else
|
||||
printf 'missing %s; prep can create it' "${BASHRC_FILE}"
|
||||
fi
|
||||
}
|
||||
|
||||
detail_bashrc_alias() {
|
||||
if check_bashrc_alias; then
|
||||
printf '%s' "${ALIAS_LINE}"
|
||||
else
|
||||
printf 'missing alias line for %s' "${VENV_FFX}"
|
||||
fi
|
||||
}
|
||||
|
||||
print_status_report() {
|
||||
READINESS_FAILURES=0
|
||||
|
||||
echo "Dependency status:"
|
||||
if check_python3; then
|
||||
report_component ok "python3" "$(detail_python3)"
|
||||
else
|
||||
report_component failed "python3" "$(detail_python3)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Bundle venv status:"
|
||||
if check_venv_dir; then
|
||||
report_component ok "bundle virtualenv" "$(detail_venv_dir)"
|
||||
else
|
||||
report_component failed "bundle virtualenv" "$(detail_venv_dir)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
if check_venv_pip; then
|
||||
report_component ok "bundle pip" "$(detail_venv_pip)"
|
||||
else
|
||||
report_component failed "bundle pip" "$(detail_venv_pip)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
if check_venv_ffx; then
|
||||
report_component ok "bundle ffx" "$(detail_venv_ffx)"
|
||||
else
|
||||
report_component failed "bundle ffx" "$(detail_venv_ffx)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Shell exposure status:"
|
||||
if check_bashrc_file; then
|
||||
report_component ok ".bashrc" "$(detail_bashrc_file)"
|
||||
else
|
||||
report_component warn ".bashrc" "$(detail_bashrc_file)"
|
||||
fi
|
||||
|
||||
if check_bashrc_alias; then
|
||||
report_component ok "ffx alias" "$(detail_bashrc_alias)"
|
||||
else
|
||||
report_component failed "ffx alias" "$(detail_bashrc_alias)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_bundle_venv() {
|
||||
mkdir -p "${HOME}/.local/share"
|
||||
|
||||
if ! check_venv_dir; then
|
||||
printf 'Creating bundle virtualenv at %s...\n' "${VENV_DIR}"
|
||||
if ! python3 -m venv "${VENV_DIR}"; then
|
||||
printf 'Failed to create virtualenv at %s.\n' "${VENV_DIR}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! check_venv_pip; then
|
||||
printf 'Missing pip in %s.\n' "${VENV_DIR}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf 'Installing FFX package into %s...\n' "${VENV_DIR}"
|
||||
if ! "${VENV_PIP}" install --editable "${ROOT_DIR}"; then
|
||||
printf 'Failed to install FFX package into %s.\n' "${VENV_DIR}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
write_alias_block() {
|
||||
local bashrc_dir
|
||||
bashrc_dir="$(dirname "${BASHRC_FILE}")"
|
||||
mkdir -p "${bashrc_dir}"
|
||||
touch "${BASHRC_FILE}"
|
||||
|
||||
if grep -Fq "${ALIAS_BLOCK_BEGIN}" "${BASHRC_FILE}" || grep -Fq "${ALIAS_BLOCK_END}" "${BASHRC_FILE}"; then
|
||||
if ! python3 - "${BASHRC_FILE}" "${ALIAS_BLOCK_BEGIN}" "${ALIAS_BLOCK_END}" "${ALIAS_LINE}" <<'PY'
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
path = pathlib.Path(sys.argv[1])
|
||||
begin = sys.argv[2]
|
||||
end = sys.argv[3]
|
||||
alias_line = sys.argv[4]
|
||||
|
||||
content = path.read_text()
|
||||
block = f"{begin}\n{alias_line}\n{end}\n"
|
||||
|
||||
start = content.find(begin)
|
||||
stop = content.find(end)
|
||||
|
||||
if start != -1 and stop != -1 and stop >= start:
|
||||
stop += len(end)
|
||||
if stop < len(content) and content[stop] == "\n":
|
||||
stop += 1
|
||||
content = content[:start] + block + content[stop:]
|
||||
else:
|
||||
if content and not content.endswith("\n"):
|
||||
content += "\n"
|
||||
content += block
|
||||
|
||||
path.write_text(content)
|
||||
PY
|
||||
then
|
||||
printf 'Failed to update managed alias block in %s.\n' "${BASHRC_FILE}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
elif check_bashrc_alias; then
|
||||
:
|
||||
else
|
||||
{
|
||||
if [ -s "${BASHRC_FILE}" ] && [ "$(tail -c 1 "${BASHRC_FILE}" 2>/dev/null || true)" != "" ]; then
|
||||
printf '\n'
|
||||
fi
|
||||
printf '%s\n' "${ALIAS_BLOCK_BEGIN}"
|
||||
printf '%s\n' "${ALIAS_LINE}"
|
||||
printf '%s\n' "${ALIAS_BLOCK_END}"
|
||||
} >>"${BASHRC_FILE}" || {
|
||||
printf 'Failed to append alias block to %s.\n' "${BASHRC_FILE}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
ensure_bashrc_alias() {
|
||||
printf 'Ensuring ffx alias in %s...\n' "${BASHRC_FILE}"
|
||||
write_alias_block
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--check)
|
||||
CHECK_ONLY=1
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
printf 'Unknown option: %s\n\n' "$1" >&2
|
||||
usage >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
main() {
|
||||
parse_args "$@"
|
||||
|
||||
print_status_report
|
||||
|
||||
if [ "${CHECK_ONLY}" -eq 0 ]; then
|
||||
if ! check_python3; then
|
||||
printf '\npython3 is required before the bundle venv can be prepared.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
ensure_bundle_venv
|
||||
ensure_bashrc_alias
|
||||
|
||||
echo
|
||||
print_status_report
|
||||
fi
|
||||
|
||||
echo
|
||||
if [ "${INSTALL_FAILURES}" -gt 0 ]; then
|
||||
echo "One or more bundle preparation steps failed; see the status checks above." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${READINESS_FAILURES}" -gt 0 ]; then
|
||||
echo "The FFX bundle virtualenv and/or alias setup is incomplete." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "The FFX bundle virtualenv is ready."
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user