mirror of
https://github.com/rightup/pyMC_Repeater.git
synced 2026-05-03 12:12:14 +02:00
Split Buildroot flow into dedicated manager
This commit is contained in:
461
buildroot-manage.sh
Normal file
461
buildroot-manage.sh
Normal file
@@ -0,0 +1,461 @@
|
||||
#!/bin/bash
|
||||
# Buildroot/Luckfox management entrypoint for pyMC Repeater
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
INSTALL_DIR="/opt/pymc_repeater"
|
||||
VENV_DIR="$INSTALL_DIR/venv"
|
||||
VENV_PIP="$VENV_DIR/bin/pip"
|
||||
VENV_PYTHON="$VENV_DIR/bin/python"
|
||||
CONFIG_DIR="/etc/pymc_repeater"
|
||||
LOG_DIR="/var/log/pymc_repeater"
|
||||
DATA_DIR="/var/lib/pymc_repeater"
|
||||
SERVICE_USER="repeater"
|
||||
INIT_SCRIPT="/etc/init.d/S80pymc-repeater"
|
||||
PIDFILE="/var/run/pymc-repeater.pid"
|
||||
LOGFILE="$LOG_DIR/repeater.log"
|
||||
SERVICE_NAME="pymc-repeater"
|
||||
SILENT_MODE="${PYMC_SILENT:-${SILENT:-}}"
|
||||
|
||||
R2_BASE_URL="https://wheel.pymc.dev/pymc_build_deps"
|
||||
R2_ENABLED=1
|
||||
|
||||
stage() {
|
||||
printf '\n==> %s\n' "$1"
|
||||
}
|
||||
|
||||
info() {
|
||||
printf ' - %s\n' "$1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
printf ' - %s\n' "$1" >&2
|
||||
}
|
||||
|
||||
fail() {
|
||||
printf '%s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
need_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || fail "Missing required command: $1"
|
||||
}
|
||||
|
||||
is_buildroot() {
|
||||
[ -f /etc/pymc-image-build-id ] && return 0
|
||||
[ -f /etc/os-release ] && grep -q '^ID=buildroot$' /etc/os-release 2>/dev/null && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
ensure_root() {
|
||||
[ "${EUID}" -eq 0 ] || fail "This command must be run as root."
|
||||
}
|
||||
|
||||
group_exists() {
|
||||
grep -q "^$1:" /etc/group 2>/dev/null
|
||||
}
|
||||
|
||||
ensure_group_line() {
|
||||
local group_name="$1"
|
||||
local gid="$2"
|
||||
group_exists "$group_name" && return 0
|
||||
printf '%s:x:%s:\n' "$group_name" "$gid" >> /etc/group
|
||||
}
|
||||
|
||||
ensure_service_user() {
|
||||
if id "$SERVICE_USER" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v useradd >/dev/null 2>&1; then
|
||||
useradd --system --home "$DATA_DIR" --shell /sbin/nologin "$SERVICE_USER"
|
||||
return 0
|
||||
fi
|
||||
|
||||
ensure_group_line "$SERVICE_USER" 990
|
||||
printf '%s:x:990:990::%s:/sbin/nologin\n' "$SERVICE_USER" "$DATA_DIR" >> /etc/passwd
|
||||
if [ -f /etc/shadow ]; then
|
||||
printf '%s:!:19000:0:99999:7:::\n' "$SERVICE_USER" >> /etc/shadow
|
||||
fi
|
||||
}
|
||||
|
||||
add_user_to_group() {
|
||||
local user_name="$1"
|
||||
local group_name="$2"
|
||||
local current_line current_members gid escaped_line new_members
|
||||
|
||||
group_exists "$group_name" || return 0
|
||||
current_line=$(grep "^${group_name}:" /etc/group 2>/dev/null || true)
|
||||
[ -n "$current_line" ] || return 0
|
||||
current_members=$(printf '%s' "$current_line" | cut -d: -f4)
|
||||
case ",${current_members}," in
|
||||
*,"${user_name}",*) return 0 ;;
|
||||
esac
|
||||
|
||||
if [ -n "$current_members" ]; then
|
||||
new_members="${current_members},${user_name}"
|
||||
else
|
||||
new_members="${user_name}"
|
||||
fi
|
||||
gid=$(printf '%s' "$current_line" | cut -d: -f3)
|
||||
escaped_line=$(printf '%s\n' "$current_line" | sed 's/[].[^$\\*]/\\&/g')
|
||||
sed -i "s/^${escaped_line}\$/${group_name}:x:${gid}:${new_members}/" /etc/group
|
||||
}
|
||||
|
||||
install_system_packages() {
|
||||
if is_buildroot; then
|
||||
info "Buildroot image detected; using preinstalled packages."
|
||||
return 0
|
||||
fi
|
||||
|
||||
apt-get update -qq
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
||||
libffi-dev libusb-1.0-0 sudo jq pip python3-venv python3-rrdtool wget swig build-essential python3-dev
|
||||
}
|
||||
|
||||
ensure_yq() {
|
||||
local yq_version="v4.40.5"
|
||||
local yq_binary="yq_linux_arm64"
|
||||
|
||||
if command -v yq >/dev/null 2>&1 && yq --version 2>&1 | grep -q 'mikefarah/yq'; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
case "$(uname -m)" in
|
||||
x86_64) yq_binary="yq_linux_amd64" ;;
|
||||
armv7*|armv6*|armhf) yq_binary="yq_linux_arm" ;;
|
||||
aarch64|arm64) yq_binary="yq_linux_arm64" ;;
|
||||
esac
|
||||
|
||||
wget -qO /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/${yq_version}/${yq_binary}"
|
||||
chmod +x /usr/local/bin/yq
|
||||
}
|
||||
|
||||
ensure_venv() {
|
||||
if [ ! -x "$VENV_PYTHON" ]; then
|
||||
stage "Creating virtual environment"
|
||||
python3 -m venv --system-site-packages "$VENV_DIR"
|
||||
"$VENV_PIP" install --upgrade pip setuptools wheel >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
preinstall_r2_wheels() {
|
||||
local machine_arch arch_tag platform_tag py_tag wheel_base
|
||||
|
||||
[ "$R2_ENABLED" -eq 1 ] || return 0
|
||||
|
||||
machine_arch=$(uname -m)
|
||||
case "$machine_arch" in
|
||||
aarch64) arch_tag="arm64"; platform_tag="aarch64" ;;
|
||||
armv7l|armv7) arch_tag="armv7"; platform_tag="armv7l" ;;
|
||||
x86_64) arch_tag="x86_64"; platform_tag="x86_64" ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
|
||||
py_tag=$("$VENV_PYTHON" -c 'import sys; v=f"cp{sys.version_info.major}{sys.version_info.minor}"; print(f"{v}-{v}")' 2>/dev/null || echo "cp311-cp311")
|
||||
wheel_base="${R2_BASE_URL}/${arch_tag}/${platform_tag}/${py_tag}"
|
||||
"$VENV_PIP" install --find-links "${wheel_base}/index.html" --no-cache-dir \
|
||||
"pycryptodome>=3.23.0" "PyNaCl>=1.5.0" cffi "pyyaml>=6.0.0" >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
create_init_script() {
|
||||
cat > "$INIT_SCRIPT" <<EOF
|
||||
#!/bin/sh
|
||||
DAEMON="${VENV_PYTHON}"
|
||||
PIDFILE="${PIDFILE}"
|
||||
LOGFILE="${LOGFILE}"
|
||||
WORKDIR="${DATA_DIR}"
|
||||
CONFIG_FILE="${CONFIG_DIR}/config.yaml"
|
||||
RUN_AS="${SERVICE_USER}"
|
||||
|
||||
start() {
|
||||
mkdir -p "$(dirname "\$PIDFILE")" "$(dirname "\$LOGFILE")" "\$WORKDIR"
|
||||
if [ -f "\$PIDFILE" ] && kill -0 "$(cat "\$PIDFILE")" 2>/dev/null; then
|
||||
echo "${SERVICE_NAME} is already running."
|
||||
return 0
|
||||
fi
|
||||
start-stop-daemon --start --quiet --background --make-pidfile --pidfile "\$PIDFILE" \\
|
||||
--chuid "\$RUN_AS" --exec /bin/sh -- -c "cd \"\$WORKDIR\" && exec \"\$DAEMON\" -m repeater.main --config \"\$CONFIG_FILE\" >>\"\$LOGFILE\" 2>&1"
|
||||
}
|
||||
|
||||
stop() {
|
||||
if [ ! -f "\$PIDFILE" ]; then
|
||||
echo "${SERVICE_NAME} is not running."
|
||||
return 0
|
||||
fi
|
||||
start-stop-daemon --stop --quiet --retry 5 --pidfile "\$PIDFILE" || true
|
||||
rm -f "\$PIDFILE"
|
||||
}
|
||||
|
||||
status() {
|
||||
if [ -f "\$PIDFILE" ] && kill -0 "$(cat "\$PIDFILE")" 2>/dev/null; then
|
||||
echo "${SERVICE_NAME} is running."
|
||||
return 0
|
||||
fi
|
||||
echo "${SERVICE_NAME} is stopped."
|
||||
return 1
|
||||
}
|
||||
|
||||
case "\${1:-}" in
|
||||
start) start ;;
|
||||
stop) stop ;;
|
||||
restart) stop; start ;;
|
||||
status) status ;;
|
||||
*)
|
||||
echo "Usage: \$0 {start|stop|restart|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
chmod 0755 "$INIT_SCRIPT"
|
||||
}
|
||||
|
||||
service_exists() {
|
||||
[ -x "$INIT_SCRIPT" ]
|
||||
}
|
||||
|
||||
is_installed() {
|
||||
[ -d "$INSTALL_DIR" ] && service_exists
|
||||
}
|
||||
|
||||
is_running() {
|
||||
[ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null
|
||||
}
|
||||
|
||||
get_version() {
|
||||
if [ -x "$VENV_PYTHON" ]; then
|
||||
"$VENV_PYTHON" -c "from importlib.metadata import version; print(version('pymc_repeater'))" 2>/dev/null || echo "not installed"
|
||||
else
|
||||
echo "not installed"
|
||||
fi
|
||||
}
|
||||
|
||||
doctor() {
|
||||
stage "Checking Buildroot image baseline"
|
||||
|
||||
for cmd in bash git python3 dialog jq wget sudo sqlite3 start-stop-daemon; do
|
||||
if command -v "$cmd" >/dev/null 2>&1; then
|
||||
info "found $cmd"
|
||||
else
|
||||
warn "missing $cmd"
|
||||
fi
|
||||
done
|
||||
|
||||
if python3 -m venv --help >/dev/null 2>&1; then
|
||||
info "python venv support available"
|
||||
else
|
||||
warn "python venv support missing"
|
||||
fi
|
||||
|
||||
if python3 - <<'PY'
|
||||
modules = [
|
||||
"sqlite3",
|
||||
"yaml",
|
||||
"cherrypy",
|
||||
"cherrypy_cors",
|
||||
"autocommand",
|
||||
"jaraco.collections",
|
||||
"jaraco.text",
|
||||
"paho.mqtt.client",
|
||||
"psutil",
|
||||
"jwt",
|
||||
"ws4py",
|
||||
"nacl",
|
||||
"periphery",
|
||||
"spidev",
|
||||
"serial",
|
||||
"usb",
|
||||
"Crypto",
|
||||
]
|
||||
for module in modules:
|
||||
__import__(module)
|
||||
PY
|
||||
then
|
||||
info "python runtime packages are present"
|
||||
else
|
||||
warn "python runtime packages are missing"
|
||||
fi
|
||||
|
||||
for path in /dev/spidev* /dev/gpiochip*; do
|
||||
[ -e "$path" ] && info "detected $path"
|
||||
done
|
||||
}
|
||||
|
||||
install_repeater() {
|
||||
local git_version machine_arch arch_tag platform_tag py_tag wheel_base ip_address
|
||||
|
||||
ensure_root
|
||||
stage "Preparing Buildroot installation"
|
||||
install_system_packages
|
||||
ensure_service_user
|
||||
|
||||
for grp in plugdev dialout gpio i2c spi; do
|
||||
add_user_to_group "$SERVICE_USER" "$grp"
|
||||
done
|
||||
|
||||
mkdir -p "$INSTALL_DIR" "$CONFIG_DIR" "$LOG_DIR" "$DATA_DIR" "$DATA_DIR/.config/pymc_repeater"
|
||||
chown -R "$SERVICE_USER:$SERVICE_USER" "$CONFIG_DIR" "$LOG_DIR" "$DATA_DIR"
|
||||
chmod 755 "$INSTALL_DIR" "$DATA_DIR"
|
||||
chmod 750 "$CONFIG_DIR" "$LOG_DIR"
|
||||
|
||||
cp "$SCRIPT_DIR/config.yaml.example" "$CONFIG_DIR/config.yaml.example"
|
||||
[ -f "$CONFIG_DIR/config.yaml" ] || cp "$SCRIPT_DIR/config.yaml.example" "$CONFIG_DIR/config.yaml"
|
||||
cp "$SCRIPT_DIR/radio-settings.json" "$DATA_DIR/" 2>/dev/null || true
|
||||
cp "$SCRIPT_DIR/radio-presets.json" "$DATA_DIR/" 2>/dev/null || true
|
||||
|
||||
ensure_yq
|
||||
ensure_venv
|
||||
|
||||
if [ -d "$SCRIPT_DIR/.git" ]; then
|
||||
git -C "$SCRIPT_DIR" fetch --tags 2>/dev/null || true
|
||||
git_version=$(python3 -m setuptools_scm 2>/dev/null || echo "1.0.5")
|
||||
export SETUPTOOLS_SCM_PRETEND_VERSION="$git_version"
|
||||
else
|
||||
export SETUPTOOLS_SCM_PRETEND_VERSION="1.0.5"
|
||||
fi
|
||||
|
||||
if ! grep -q "Luckfox Pico" /proc/device-tree/model 2>/dev/null; then
|
||||
export PIP_ONLY_BINARY=pycryptodome,cffi,PyNaCl,psutil
|
||||
fi
|
||||
|
||||
preinstall_r2_wheels
|
||||
|
||||
stage "Installing pyMC Repeater into venv"
|
||||
(cd "$SCRIPT_DIR" && "$VENV_PIP" install --upgrade --no-cache-dir .[hardware])
|
||||
|
||||
create_init_script
|
||||
|
||||
stage "Starting service"
|
||||
"$INIT_SCRIPT" restart
|
||||
|
||||
ip_address=$(hostname -I | awk '{print $1}')
|
||||
if is_running; then
|
||||
printf '\nService is running on: http://%s:8000\n' "${ip_address}"
|
||||
else
|
||||
fail "Installation completed but the service failed to start. Check: sh $0 logs"
|
||||
fi
|
||||
}
|
||||
|
||||
upgrade_repeater() {
|
||||
ensure_root
|
||||
is_installed || fail "Service is not installed."
|
||||
|
||||
ensure_venv
|
||||
preinstall_r2_wheels
|
||||
|
||||
stage "Upgrading pyMC Repeater"
|
||||
(cd "$SCRIPT_DIR" && "$VENV_PIP" install --upgrade --no-cache-dir .[hardware])
|
||||
"$INIT_SCRIPT" restart
|
||||
}
|
||||
|
||||
uninstall_repeater() {
|
||||
ensure_root
|
||||
|
||||
stage "Removing service"
|
||||
service_exists && "$INIT_SCRIPT" stop || true
|
||||
rm -f "$INIT_SCRIPT"
|
||||
rm -rf "$INSTALL_DIR" "$CONFIG_DIR" "$LOG_DIR" "$DATA_DIR"
|
||||
}
|
||||
|
||||
manage_service() {
|
||||
local action="$1"
|
||||
ensure_root
|
||||
service_exists || fail "Service is not installed."
|
||||
"$INIT_SCRIPT" "$action"
|
||||
}
|
||||
|
||||
show_status() {
|
||||
local ip_address version
|
||||
version=$(get_version)
|
||||
ip_address=$(hostname -I | awk '{print $1}')
|
||||
|
||||
if ! is_installed; then
|
||||
printf 'Installation Status: Not Installed\n'
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf 'Installation Status: Installed\n'
|
||||
printf 'Version: %s\n' "$version"
|
||||
printf 'Install Directory: %s\n' "$INSTALL_DIR"
|
||||
printf 'Config Directory: %s\n' "$CONFIG_DIR"
|
||||
printf 'Log File: %s\n' "$LOGFILE"
|
||||
printf 'Dashboard: http://%s:8000\n' "$ip_address"
|
||||
if is_running; then
|
||||
printf 'Service Status: Running\n'
|
||||
else
|
||||
printf 'Service Status: Stopped\n'
|
||||
fi
|
||||
}
|
||||
|
||||
show_logs() {
|
||||
mkdir -p "$LOG_DIR"
|
||||
touch "$LOGFILE"
|
||||
tail -f "$LOGFILE"
|
||||
}
|
||||
|
||||
run_debug() {
|
||||
ensure_root
|
||||
mkdir -p "$LOG_DIR" "$DATA_DIR"
|
||||
exec "$VENV_PYTHON" -m repeater.main --config "$CONFIG_DIR/config.yaml"
|
||||
}
|
||||
|
||||
delegate_to_stock_manage() {
|
||||
exec bash "$SCRIPT_DIR/manage.sh" "$@"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: bash buildroot-manage.sh <command>
|
||||
|
||||
Commands:
|
||||
doctor Check Buildroot/Luckfox prerequisites
|
||||
install Install pyMC Repeater on the Buildroot image
|
||||
upgrade Upgrade the Buildroot installation from the checked-out repo
|
||||
config Run the stock interactive config flow
|
||||
start Start the init.d service
|
||||
stop Stop the init.d service
|
||||
restart Restart the init.d service
|
||||
status Show Buildroot service status
|
||||
logs Tail the Buildroot log file
|
||||
uninstall Remove the Buildroot installation
|
||||
debug Run repeater.main in the foreground
|
||||
EOF
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
doctor)
|
||||
doctor
|
||||
;;
|
||||
install)
|
||||
install_repeater
|
||||
;;
|
||||
upgrade)
|
||||
upgrade_repeater
|
||||
;;
|
||||
config)
|
||||
shift
|
||||
delegate_to_stock_manage config "$@"
|
||||
;;
|
||||
start|stop|restart)
|
||||
manage_service "$1"
|
||||
;;
|
||||
status)
|
||||
show_status
|
||||
;;
|
||||
logs)
|
||||
show_logs
|
||||
;;
|
||||
uninstall)
|
||||
uninstall_repeater
|
||||
;;
|
||||
debug)
|
||||
run_debug
|
||||
;;
|
||||
""|help|-h|--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
fail "Unknown command: ${1}"
|
||||
;;
|
||||
esac
|
||||
191
manage.sh
191
manage.sh
@@ -17,134 +17,6 @@ SILENT_MODE="${PYMC_SILENT:-${SILENT:-}}"
|
||||
R2_BASE_URL="https://wheel.pymc.dev/pymc_build_deps"
|
||||
R2_ENABLED=1 # Set to 0 to disable R2 wheels and always build from source
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Platform detection / compatibility helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
is_buildroot() {
|
||||
[ -f /etc/pymc-image-build-id ] && return 0
|
||||
[ -f /etc/os-release ] && grep -q '^ID=buildroot$' /etc/os-release 2>/dev/null && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
group_exists() {
|
||||
local group_name="$1"
|
||||
if command -v getent >/dev/null 2>&1; then
|
||||
getent group "$group_name" >/dev/null 2>&1
|
||||
else
|
||||
grep -q "^${group_name}:" /etc/group 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_group_line() {
|
||||
local group_name="$1"
|
||||
local gid="$2"
|
||||
group_exists "$group_name" && return 0
|
||||
printf '%s:x:%s:\n' "$group_name" "$gid" >> /etc/group
|
||||
}
|
||||
|
||||
ensure_service_user() {
|
||||
if id "$SERVICE_USER" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v useradd >/dev/null 2>&1; then
|
||||
useradd --system --home /var/lib/pymc_repeater --shell /sbin/nologin "$SERVICE_USER"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if is_buildroot; then
|
||||
ensure_group_line "$SERVICE_USER" 990
|
||||
printf '%s:x:990:990::/var/lib/pymc_repeater:/sbin/nologin\n' "$SERVICE_USER" >> /etc/passwd
|
||||
if [ -f /etc/shadow ]; then
|
||||
printf '%s:!:19000:0:99999:7:::\n' "$SERVICE_USER" >> /etc/shadow
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Error: useradd is not available on this system." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
add_user_to_group() {
|
||||
local user_name="$1"
|
||||
local group_name="$2"
|
||||
|
||||
group_exists "$group_name" || return 0
|
||||
|
||||
if command -v usermod >/dev/null 2>&1; then
|
||||
usermod -a -G "$group_name" "$user_name" 2>/dev/null || true
|
||||
return 0
|
||||
fi
|
||||
|
||||
if is_buildroot; then
|
||||
local current_line current_members gid new_members escaped_line
|
||||
current_line=$(grep "^${group_name}:" /etc/group 2>/dev/null || true)
|
||||
[ -n "$current_line" ] || return 0
|
||||
current_members=$(printf '%s' "$current_line" | cut -d: -f4)
|
||||
case ",${current_members}," in
|
||||
*,"${user_name}",*) return 0 ;;
|
||||
esac
|
||||
if [ -n "$current_members" ]; then
|
||||
new_members="${current_members},${user_name}"
|
||||
else
|
||||
new_members="${user_name}"
|
||||
fi
|
||||
gid=$(printf '%s' "$current_line" | cut -d: -f3)
|
||||
escaped_line=$(printf '%s\n' "$current_line" | sed 's/[].[^$\\*]/\\&/g')
|
||||
sed -i "s/^${escaped_line}\$/${group_name}:x:${gid}:${new_members}/" /etc/group
|
||||
fi
|
||||
}
|
||||
|
||||
install_system_packages() {
|
||||
if is_buildroot; then
|
||||
echo " Buildroot image detected; using preinstalled system packages."
|
||||
return 0
|
||||
fi
|
||||
|
||||
apt-get update -qq
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
||||
libffi-dev libusb-1.0-0 sudo jq pip python3-venv python3-rrdtool wget swig build-essential python3-dev
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y policykit-1 2>/dev/null \
|
||||
|| DEBIAN_FRONTEND=noninteractive apt-get install -y polkitd pkexec 2>/dev/null \
|
||||
|| echo " Warning: Could not install polkit (sudo fallback will be used)"
|
||||
}
|
||||
|
||||
install_bootstrap_python_packages() {
|
||||
if is_buildroot; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
pip install --break-system-packages setuptools_scm >/dev/null 2>&1 \
|
||||
|| python3 -m pip install --break-system-packages setuptools_scm >/dev/null 2>&1 \
|
||||
|| true
|
||||
}
|
||||
|
||||
ensure_yq() {
|
||||
if command -v yq &>/dev/null && [[ "$(yq --version 2>&1)" == *"mikefarah/yq"* ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ">>> Installing yq..."
|
||||
local yq_version="v4.40.5"
|
||||
local yq_binary="yq_linux_arm64"
|
||||
|
||||
case "$(uname -m)" in
|
||||
x86_64)
|
||||
yq_binary="yq_linux_amd64"
|
||||
;;
|
||||
armv7*|armv6*|armhf)
|
||||
yq_binary="yq_linux_arm"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
yq_binary="yq_linux_arm64"
|
||||
;;
|
||||
esac
|
||||
|
||||
wget -qO /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/${yq_version}/${yq_binary}" 2>/dev/null \
|
||||
&& chmod +x /usr/local/bin/yq
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Virtual-environment helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -231,18 +103,13 @@ elif command -v dialog &> /dev/null; then
|
||||
DIALOG="dialog"
|
||||
else
|
||||
echo "TUI interface requires whiptail or dialog."
|
||||
if [ "$EUID" -eq 0 ] && ! is_buildroot; then
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
echo "Installing whiptail..."
|
||||
apt-get update -qq && apt-get install -y whiptail
|
||||
DIALOG="whiptail"
|
||||
else
|
||||
echo ""
|
||||
if is_buildroot; then
|
||||
echo "This Buildroot image is expected to ship with dialog preinstalled."
|
||||
echo "Please rebuild the image with dialog enabled, or run from a system that has dialog."
|
||||
else
|
||||
echo "Please install whiptail: sudo apt-get install -y whiptail"
|
||||
fi
|
||||
echo "Please install whiptail: sudo apt-get install -y whiptail"
|
||||
echo "Then run this script again."
|
||||
exit 1
|
||||
fi
|
||||
@@ -459,25 +326,44 @@ install_repeater() {
|
||||
echo ""
|
||||
|
||||
echo ">>> Creating service user..."
|
||||
ensure_service_user
|
||||
if ! id "$SERVICE_USER" &>/dev/null; then
|
||||
useradd --system --home /var/lib/pymc_repeater --shell /sbin/nologin "$SERVICE_USER"
|
||||
fi
|
||||
|
||||
(
|
||||
echo "10"; echo "# Adding user to hardware groups..."
|
||||
for grp in plugdev dialout gpio i2c spi; do
|
||||
add_user_to_group "$SERVICE_USER" "$grp"
|
||||
getent group "$grp" >/dev/null 2>&1 && usermod -a -G "$grp" "$SERVICE_USER" 2>/dev/null || true
|
||||
done
|
||||
|
||||
echo "20"; echo "# Creating directories..."
|
||||
mkdir -p "$INSTALL_DIR" "$CONFIG_DIR" "$LOG_DIR" /var/lib/pymc_repeater
|
||||
|
||||
echo "25"; echo "# Installing system dependencies..."
|
||||
install_system_packages
|
||||
install_bootstrap_python_packages
|
||||
apt-get update -qq
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y libffi-dev libusb-1.0-0 sudo jq pip python3-venv python3-rrdtool wget swig build-essential python3-dev
|
||||
# Install polkit (package name varies by distro version)
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y policykit-1 2>/dev/null \
|
||||
|| DEBIAN_FRONTEND=noninteractive apt-get install -y polkitd pkexec 2>/dev/null \
|
||||
|| echo " Warning: Could not install polkit (sudo fallback will be used)"
|
||||
# setuptools_scm needed for git version detection during build
|
||||
pip install --break-system-packages setuptools_scm >/dev/null 2>&1 || python3 -m pip install --break-system-packages setuptools_scm >/dev/null 2>&1 || true
|
||||
|
||||
echo "28"; echo "# Creating virtual environment..."
|
||||
ensure_venv
|
||||
|
||||
ensure_yq
|
||||
# Install mikefarah yq v4 if not already installed
|
||||
if ! command -v yq &> /dev/null || [[ "$(yq --version 2>&1)" != *"mikefarah/yq"* ]]; then
|
||||
echo ">>> Installing yq..."
|
||||
YQ_VERSION="v4.40.5"
|
||||
YQ_BINARY="yq_linux_arm64"
|
||||
if [[ "$(uname -m)" == "x86_64" ]]; then
|
||||
YQ_BINARY="yq_linux_amd64"
|
||||
elif [[ "$(uname -m)" == "armv7"* ]]; then
|
||||
YQ_BINARY="yq_linux_arm"
|
||||
fi
|
||||
wget -qO /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${YQ_BINARY}" 2>/dev/null && chmod +x /usr/local/bin/yq
|
||||
fi
|
||||
|
||||
echo "29"; echo "# Installing files..."
|
||||
cp "$SCRIPT_DIR/manage.sh" "$INSTALL_DIR/" 2>/dev/null || true
|
||||
@@ -858,9 +744,26 @@ upgrade_repeater() {
|
||||
fi
|
||||
|
||||
echo "[3/9] Updating system dependencies..."
|
||||
install_system_packages
|
||||
install_bootstrap_python_packages
|
||||
ensure_yq
|
||||
apt-get update -qq
|
||||
|
||||
apt-get install -y libffi-dev libusb-1.0-0 sudo jq pip python3-venv python3-rrdtool wget swig build-essential python3-dev
|
||||
# Install polkit (package name varies by distro version)
|
||||
apt-get install -y policykit-1 2>/dev/null \
|
||||
|| apt-get install -y polkitd pkexec 2>/dev/null \
|
||||
|| echo " Warning: Could not install polkit (sudo fallback will be used)"
|
||||
pip install --break-system-packages setuptools_scm >/dev/null 2>&1 || python3 -m pip install --break-system-packages setuptools_scm >/dev/null 2>&1 || true
|
||||
|
||||
# Install mikefarah yq v4 if not already installed
|
||||
if ! command -v yq &> /dev/null || [[ "$(yq --version 2>&1)" != *"mikefarah/yq"* ]]; then
|
||||
YQ_VERSION="v4.40.5"
|
||||
YQ_BINARY="yq_linux_arm64"
|
||||
if [[ "$(uname -m)" == "x86_64" ]]; then
|
||||
YQ_BINARY="yq_linux_amd64"
|
||||
elif [[ "$(uname -m)" == "armv7"* ]]; then
|
||||
YQ_BINARY="yq_linux_arm"
|
||||
fi
|
||||
wget -qO /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${YQ_BINARY}" && chmod +x /usr/local/bin/yq
|
||||
fi
|
||||
echo " ✓ Dependencies updated"
|
||||
|
||||
echo "[4/9] Installing files..."
|
||||
@@ -881,7 +784,7 @@ upgrade_repeater() {
|
||||
|
||||
echo "[5.5/9] Ensuring user groups and udev rules..."
|
||||
for grp in plugdev dialout gpio i2c spi; do
|
||||
add_user_to_group "$SERVICE_USER" "$grp"
|
||||
getent group "$grp" >/dev/null 2>&1 && usermod -a -G "$grp" "$SERVICE_USER" 2>/dev/null || true
|
||||
done
|
||||
# Install/update CH341 udev rules
|
||||
SCRIPT_DIR_UPGRADE="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
Reference in New Issue
Block a user