修复脚本注释,添加macOS支持,重构依赖管理和服务控制逻辑
This commit is contained in:
524
scripts/run.sh
524
scripts/run.sh
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# MaiCore & NapCat Adapter一键安装脚本 by Cookie_987
|
||||
# 适用于Arch/Ubuntu 24.10/Debian 12/CentOS 9
|
||||
# 适用于macOS/Arch/Ubuntu 24.10/Debian 12/CentOS 9
|
||||
# 请小心使用任何一键脚本!
|
||||
|
||||
INSTALLER_VERSION="0.0.5-refactor"
|
||||
@@ -15,36 +15,297 @@ GREEN="\e[32m"
|
||||
RED="\e[31m"
|
||||
RESET="\e[0m"
|
||||
|
||||
# 需要的基本软件包
|
||||
|
||||
declare -A REQUIRED_PACKAGES=(
|
||||
["common"]="git sudo python3 curl gnupg"
|
||||
["debian"]="python3-venv python3-pip build-essential"
|
||||
["ubuntu"]="python3-venv python3-pip build-essential"
|
||||
["centos"]="epel-release python3-pip python3-devel gcc gcc-c++ make"
|
||||
["arch"]="python-virtualenv python-pip base-devel"
|
||||
)
|
||||
|
||||
# 默认项目目录
|
||||
DEFAULT_INSTALL_DIR="/opt/maicore"
|
||||
# 需要的基本软件包(兼容 Bash 3,避免使用关联数组)
|
||||
REQUIRED_PACKAGES_COMMON="git sudo python3 curl gnupg"
|
||||
REQUIRED_PACKAGES_DEBIAN="python3-venv python3-pip build-essential"
|
||||
REQUIRED_PACKAGES_UBUNTU="python3-venv python3-pip build-essential"
|
||||
REQUIRED_PACKAGES_CENTOS="epel-release python3-pip python3-devel gcc gcc-c++ make"
|
||||
REQUIRED_PACKAGES_ARCH="python-virtualenv python-pip base-devel"
|
||||
REQUIRED_PACKAGES_MACOS="git gnupg python"
|
||||
|
||||
# 服务名称
|
||||
SERVICE_NAME="maicore"
|
||||
SERVICE_NAME_WEB="maicore-web"
|
||||
SERVICE_NAME_NBADAPTER="maibot-napcat-adapter"
|
||||
|
||||
SERVICE_USER="${SUDO_USER:-$USER}"
|
||||
SERVICE_HOME="$(eval echo "~${SERVICE_USER}" 2>/dev/null)"
|
||||
if [[ -z "$SERVICE_HOME" || "$SERVICE_HOME" == "~${SERVICE_USER}" ]]; then
|
||||
SERVICE_HOME="$HOME"
|
||||
fi
|
||||
|
||||
IS_MACOS=false
|
||||
[[ "$(uname -s)" == "Darwin" ]] && IS_MACOS=true
|
||||
|
||||
INSTALL_CONF="/etc/maicore_install.conf"
|
||||
|
||||
# 默认项目目录
|
||||
DEFAULT_INSTALL_DIR="/opt/maicore"
|
||||
if [[ "$IS_MACOS" == true ]]; then
|
||||
DEFAULT_INSTALL_DIR="${SERVICE_HOME}/maicore"
|
||||
INSTALL_CONF="${SERVICE_HOME}/.config/maicore/maicore_install.conf"
|
||||
fi
|
||||
|
||||
LAUNCHD_DOMAIN=""
|
||||
LAUNCHD_AGENT_DIR=""
|
||||
LAUNCHD_LABEL_MAIN="com.maicore.${SERVICE_NAME}"
|
||||
LAUNCHD_LABEL_NBADAPTER="com.maicore.${SERVICE_NAME_NBADAPTER}"
|
||||
LAUNCHD_PLIST_MAIN=""
|
||||
LAUNCHD_PLIST_NBADAPTER=""
|
||||
|
||||
if [[ "$IS_MACOS" == true ]]; then
|
||||
SERVICE_UID="$(id -u "${SERVICE_USER}" 2>/dev/null || id -u)"
|
||||
LAUNCHD_DOMAIN="gui/${SERVICE_UID}"
|
||||
LAUNCHD_AGENT_DIR="${SERVICE_HOME}/Library/LaunchAgents"
|
||||
LAUNCHD_PLIST_MAIN="${LAUNCHD_AGENT_DIR}/${LAUNCHD_LABEL_MAIN}.plist"
|
||||
LAUNCHD_PLIST_NBADAPTER="${LAUNCHD_AGENT_DIR}/${LAUNCHD_LABEL_NBADAPTER}.plist"
|
||||
fi
|
||||
|
||||
get_required_packages() {
|
||||
local distro="$1"
|
||||
case "$distro" in
|
||||
debian)
|
||||
echo "${REQUIRED_PACKAGES_COMMON} ${REQUIRED_PACKAGES_DEBIAN}"
|
||||
;;
|
||||
ubuntu)
|
||||
echo "${REQUIRED_PACKAGES_COMMON} ${REQUIRED_PACKAGES_UBUNTU}"
|
||||
;;
|
||||
centos)
|
||||
echo "${REQUIRED_PACKAGES_COMMON} ${REQUIRED_PACKAGES_CENTOS}"
|
||||
;;
|
||||
arch)
|
||||
echo "${REQUIRED_PACKAGES_COMMON} ${REQUIRED_PACKAGES_ARCH}"
|
||||
;;
|
||||
macos)
|
||||
echo "${REQUIRED_PACKAGES_MACOS}"
|
||||
;;
|
||||
*)
|
||||
echo "${REQUIRED_PACKAGES_COMMON}"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
IS_INSTALL_NAPCAT=false
|
||||
IS_INSTALL_DEPENDENCIES=false
|
||||
|
||||
resolve_brew_bin() {
|
||||
local brew_bin
|
||||
brew_bin="$(command -v brew)"
|
||||
[[ -z "$brew_bin" && -x /opt/homebrew/bin/brew ]] && brew_bin="/opt/homebrew/bin/brew"
|
||||
[[ -z "$brew_bin" && -x /usr/local/bin/brew ]] && brew_bin="/usr/local/bin/brew"
|
||||
[[ -n "$brew_bin" ]] && echo "$brew_bin"
|
||||
}
|
||||
|
||||
run_brew() {
|
||||
local brew_bin
|
||||
brew_bin="$(resolve_brew_bin)"
|
||||
|
||||
[[ -z "$brew_bin" ]] && return 1
|
||||
if [[ "$(id -u)" -eq 0 && -n "${SUDO_USER:-}" && "${SUDO_USER}" != "root" ]]; then
|
||||
sudo -u "${SUDO_USER}" "${brew_bin}" "$@"
|
||||
else
|
||||
"${brew_bin}" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
run_launchctl() {
|
||||
if [[ "$(id -u)" -eq 0 && -n "${SUDO_USER:-}" && "${SUDO_USER}" != "root" ]]; then
|
||||
sudo -u "${SUDO_USER}" launchctl "$@"
|
||||
else
|
||||
launchctl "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_writable_parent() {
|
||||
local path="$1"
|
||||
local parent
|
||||
parent="$(dirname "$path")"
|
||||
mkdir -p "$parent"
|
||||
if [[ "$IS_MACOS" == true && "$(id -u)" -eq 0 && -n "${SUDO_USER:-}" ]]; then
|
||||
chown "${SUDO_USER}" "$parent" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
save_install_info() {
|
||||
ensure_writable_parent "$INSTALL_CONF"
|
||||
cat > "$INSTALL_CONF" <<EOF
|
||||
INSTALLER_VERSION=${INSTALLER_VERSION}
|
||||
INSTALL_DIR=${INSTALL_DIR}
|
||||
BRANCH=${BRANCH}
|
||||
EOF
|
||||
}
|
||||
|
||||
compute_md5() {
|
||||
local file_path="$1"
|
||||
|
||||
if command -v md5sum &>/dev/null; then
|
||||
md5sum "$file_path" | awk '{print $1}'
|
||||
elif command -v md5 &>/dev/null; then
|
||||
md5 -q "$file_path"
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
launchd_label_for_service() {
|
||||
local service="$1"
|
||||
case "$service" in
|
||||
${SERVICE_NAME})
|
||||
echo "$LAUNCHD_LABEL_MAIN"
|
||||
;;
|
||||
${SERVICE_NAME_NBADAPTER})
|
||||
echo "$LAUNCHD_LABEL_NBADAPTER"
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
launchd_plist_for_service() {
|
||||
local service="$1"
|
||||
case "$service" in
|
||||
${SERVICE_NAME})
|
||||
echo "$LAUNCHD_PLIST_MAIN"
|
||||
;;
|
||||
${SERVICE_NAME_NBADAPTER})
|
||||
echo "$LAUNCHD_PLIST_NBADAPTER"
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
is_launchd_service_loaded() {
|
||||
local service="$1"
|
||||
local label
|
||||
label="$(launchd_label_for_service "$service")" || return 1
|
||||
run_launchctl print "${LAUNCHD_DOMAIN}/${label}" &>/dev/null
|
||||
}
|
||||
|
||||
start_service() {
|
||||
local service="$1"
|
||||
if [[ "$IS_MACOS" == true ]]; then
|
||||
local label
|
||||
local plist
|
||||
label="$(launchd_label_for_service "$service")" || return 1
|
||||
plist="$(launchd_plist_for_service "$service")" || return 1
|
||||
if [[ ! -f "$plist" && -d "${INSTALL_DIR}/MaiBot" ]]; then
|
||||
create_launchd_services
|
||||
fi
|
||||
if [[ ! -f "$plist" ]]; then
|
||||
echo -e "${RED}未找到服务配置文件:${plist}${RESET}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if is_launchd_service_loaded "$service"; then
|
||||
run_launchctl kickstart -k "${LAUNCHD_DOMAIN}/${label}"
|
||||
else
|
||||
run_launchctl bootstrap "${LAUNCHD_DOMAIN}" "$plist"
|
||||
fi
|
||||
else
|
||||
systemctl start "$service"
|
||||
fi
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
local service="$1"
|
||||
if [[ "$IS_MACOS" == true ]]; then
|
||||
local label
|
||||
label="$(launchd_label_for_service "$service")" || return 1
|
||||
if is_launchd_service_loaded "$service"; then
|
||||
run_launchctl bootout "${LAUNCHD_DOMAIN}/${label}"
|
||||
fi
|
||||
else
|
||||
systemctl stop "$service"
|
||||
fi
|
||||
}
|
||||
|
||||
restart_service() {
|
||||
local service="$1"
|
||||
if [[ "$IS_MACOS" == true ]]; then
|
||||
stop_service "$service"
|
||||
start_service "$service"
|
||||
else
|
||||
systemctl restart "$service"
|
||||
fi
|
||||
}
|
||||
|
||||
create_launchd_services() {
|
||||
mkdir -p "${LAUNCHD_AGENT_DIR}"
|
||||
mkdir -p "${INSTALL_DIR}/logs"
|
||||
|
||||
cat > "${LAUNCHD_PLIST_MAIN}" <<EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>${LAUNCHD_LABEL_MAIN}</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>${INSTALL_DIR}/venv/bin/python3</string>
|
||||
<string>bot.py</string>
|
||||
</array>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>${INSTALL_DIR}/MaiBot</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>${INSTALL_DIR}/logs/${SERVICE_NAME}.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>${INSTALL_DIR}/logs/${SERVICE_NAME}.error.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
cat > "${LAUNCHD_PLIST_NBADAPTER}" <<EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>${LAUNCHD_LABEL_NBADAPTER}</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>${INSTALL_DIR}/venv/bin/python3</string>
|
||||
<string>main.py</string>
|
||||
</array>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>${INSTALL_DIR}/MaiBot-Napcat-Adapter</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>${INSTALL_DIR}/logs/${SERVICE_NAME_NBADAPTER}.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>${INSTALL_DIR}/logs/${SERVICE_NAME_NBADAPTER}.error.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
if [[ "$(id -u)" -eq 0 && -n "${SUDO_USER:-}" && "${SUDO_USER}" != "root" ]]; then
|
||||
chown "${SUDO_USER}" "${LAUNCHD_PLIST_MAIN}" "${LAUNCHD_PLIST_NBADAPTER}" "${LAUNCHD_AGENT_DIR}" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查是否已安装
|
||||
check_installed() {
|
||||
[[ -f /etc/systemd/system/${SERVICE_NAME}.service ]]
|
||||
if [[ "$IS_MACOS" == true ]]; then
|
||||
[[ -f "$INSTALL_CONF" ]]
|
||||
else
|
||||
[[ -f /etc/systemd/system/${SERVICE_NAME}.service ]]
|
||||
fi
|
||||
}
|
||||
|
||||
# 加载安装信息
|
||||
load_install_info() {
|
||||
if [[ -f /etc/maicore_install.conf ]]; then
|
||||
source /etc/maicore_install.conf
|
||||
if [[ -f "$INSTALL_CONF" ]]; then
|
||||
source "$INSTALL_CONF"
|
||||
else
|
||||
INSTALL_DIR="$DEFAULT_INSTALL_DIR"
|
||||
BRANCH="refactor"
|
||||
@@ -69,27 +330,27 @@ show_menu() {
|
||||
|
||||
case "$choice" in
|
||||
1)
|
||||
systemctl start ${SERVICE_NAME}
|
||||
start_service "${SERVICE_NAME}"
|
||||
whiptail --msgbox "✅MaiCore已启动" 10 60
|
||||
;;
|
||||
2)
|
||||
systemctl stop ${SERVICE_NAME}
|
||||
stop_service "${SERVICE_NAME}"
|
||||
whiptail --msgbox "🛑MaiCore已停止" 10 60
|
||||
;;
|
||||
3)
|
||||
systemctl restart ${SERVICE_NAME}
|
||||
restart_service "${SERVICE_NAME}"
|
||||
whiptail --msgbox "🔄MaiCore已重启" 10 60
|
||||
;;
|
||||
4)
|
||||
systemctl start ${SERVICE_NAME_NBADAPTER}
|
||||
start_service "${SERVICE_NAME_NBADAPTER}"
|
||||
whiptail --msgbox "✅NapCat Adapter已启动" 10 60
|
||||
;;
|
||||
5)
|
||||
systemctl stop ${SERVICE_NAME_NBADAPTER}
|
||||
stop_service "${SERVICE_NAME_NBADAPTER}"
|
||||
whiptail --msgbox "🛑NapCat Adapter已停止" 10 60
|
||||
;;
|
||||
6)
|
||||
systemctl restart ${SERVICE_NAME_NBADAPTER}
|
||||
restart_service "${SERVICE_NAME_NBADAPTER}"
|
||||
whiptail --msgbox "🔄NapCat Adapter已重启" 10 60
|
||||
;;
|
||||
7)
|
||||
@@ -111,7 +372,7 @@ show_menu() {
|
||||
# 更新依赖
|
||||
update_dependencies() {
|
||||
whiptail --title "⚠" --msgbox "更新后请阅读教程" 10 60
|
||||
systemctl stop ${SERVICE_NAME}
|
||||
stop_service "${SERVICE_NAME}"
|
||||
cd "${INSTALL_DIR}/MaiBot" || {
|
||||
whiptail --msgbox "🚫 无法进入安装目录!" 10 60
|
||||
return 1
|
||||
@@ -157,23 +418,23 @@ switch_branch() {
|
||||
whiptail --msgbox "🚫 代码拉取失败!" 10 60
|
||||
return 1
|
||||
fi
|
||||
systemctl stop ${SERVICE_NAME}
|
||||
stop_service "${SERVICE_NAME}"
|
||||
source "${INSTALL_DIR}/venv/bin/activate"
|
||||
pip install -r requirements.txt
|
||||
deactivate
|
||||
|
||||
sed -i "s/^BRANCH=.*/BRANCH=${new_branch}/" /etc/maicore_install.conf
|
||||
BRANCH="${new_branch}"
|
||||
save_install_info
|
||||
check_eula
|
||||
whiptail --msgbox "✅ 已停止服务并切换到分支 ${new_branch} !" 10 60
|
||||
}
|
||||
|
||||
check_eula() {
|
||||
# 首先计算当前EULA的MD5值
|
||||
current_md5=$(md5sum "${INSTALL_DIR}/MaiBot/EULA.md" | awk '{print $1}')
|
||||
current_md5=$(compute_md5 "${INSTALL_DIR}/MaiBot/EULA.md")
|
||||
|
||||
# 首先计算当前隐私条款文件的哈希值
|
||||
current_md5_privacy=$(md5sum "${INSTALL_DIR}/MaiBot/PRIVACY.md" | awk '{print $1}')
|
||||
current_md5_privacy=$(compute_md5 "${INSTALL_DIR}/MaiBot/PRIVACY.md")
|
||||
|
||||
# 如果当前的md5值为空,则直接返回
|
||||
if [[ -z $current_md5 || -z $current_md5_privacy ]]; then
|
||||
@@ -183,7 +444,7 @@ check_eula() {
|
||||
# 检查eula.confirmed文件是否存在
|
||||
if [[ -f ${INSTALL_DIR}/MaiBot/eula.confirmed ]]; then
|
||||
# 如果存在则检查其中包含的md5与current_md5是否一致
|
||||
confirmed_md5=$(cat ${INSTALL_DIR}/MaiBot/eula.confirmed)
|
||||
confirmed_md5=$(cat "${INSTALL_DIR}/MaiBot/eula.confirmed")
|
||||
else
|
||||
confirmed_md5=""
|
||||
fi
|
||||
@@ -191,7 +452,7 @@ check_eula() {
|
||||
# 检查privacy.confirmed文件是否存在
|
||||
if [[ -f ${INSTALL_DIR}/MaiBot/privacy.confirmed ]]; then
|
||||
# 如果存在则检查其中包含的md5与current_md5是否一致
|
||||
confirmed_md5_privacy=$(cat ${INSTALL_DIR}/MaiBot/privacy.confirmed)
|
||||
confirmed_md5_privacy=$(cat "${INSTALL_DIR}/MaiBot/privacy.confirmed")
|
||||
else
|
||||
confirmed_md5_privacy=""
|
||||
fi
|
||||
@@ -200,8 +461,8 @@ check_eula() {
|
||||
if [[ $current_md5 != $confirmed_md5 || $current_md5_privacy != $confirmed_md5_privacy ]]; then
|
||||
whiptail --title "📜 使用协议更新" --yesno "检测到MaiCore EULA或隐私条款已更新。\nhttps://github.com/MaiM-with-u/MaiBot/blob/refactor/EULA.md\nhttps://github.com/MaiM-with-u/MaiBot/blob/refactor/PRIVACY.md\n\n您是否同意上述协议? \n\n " 12 70
|
||||
if [[ $? -eq 0 ]]; then
|
||||
echo -n $current_md5 > ${INSTALL_DIR}/MaiBot/eula.confirmed
|
||||
echo -n $current_md5_privacy > ${INSTALL_DIR}/MaiBot/privacy.confirmed
|
||||
echo -n "$current_md5" > "${INSTALL_DIR}/MaiBot/eula.confirmed"
|
||||
echo -n "$current_md5_privacy" > "${INSTALL_DIR}/MaiBot/privacy.confirmed"
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
@@ -209,6 +470,98 @@ check_eula() {
|
||||
|
||||
}
|
||||
|
||||
# 测速并选择PyPI源(仅当阿里云更快时使用阿里云)
|
||||
measure_url_latency() {
|
||||
local url="$1"
|
||||
local latency
|
||||
|
||||
latency=$(curl -sS -o /dev/null -w "%{time_total}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null)
|
||||
|
||||
if [[ $? -eq 0 && "$latency" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
|
||||
echo "$latency"
|
||||
return 0
|
||||
else
|
||||
echo "999999"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
resolve_default_pypi_index_url() {
|
||||
local default_url=""
|
||||
|
||||
if [[ -n "${PIP_INDEX_URL:-}" ]]; then
|
||||
default_url="$PIP_INDEX_URL"
|
||||
elif [[ -n "${UV_INDEX_URL:-}" ]]; then
|
||||
default_url="$UV_INDEX_URL"
|
||||
elif command -v pip &>/dev/null; then
|
||||
default_url=$(pip config get global.index-url 2>/dev/null | head -n 1)
|
||||
if [[ -z "$default_url" ]]; then
|
||||
default_url=$(pip config get install.index-url 2>/dev/null | head -n 1)
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "$default_url" ]]; then
|
||||
default_url="https://pypi.org/simple"
|
||||
fi
|
||||
|
||||
echo "$default_url"
|
||||
}
|
||||
|
||||
select_pypi_index_url() {
|
||||
local default_url
|
||||
local aliyun_url="https://mirrors.aliyun.com/pypi/simple"
|
||||
local default_latency
|
||||
local aliyun_latency
|
||||
local default_status
|
||||
local aliyun_status
|
||||
|
||||
default_url=$(resolve_default_pypi_index_url)
|
||||
default_latency=$(measure_url_latency "$default_url")
|
||||
default_status=$?
|
||||
aliyun_latency=$(measure_url_latency "$aliyun_url")
|
||||
aliyun_status=$?
|
||||
|
||||
if [[ $aliyun_status -eq 0 && $default_status -ne 0 ]]; then
|
||||
PYPI_INDEX_URL="$aliyun_url"
|
||||
PYPI_INDEX_NAME="阿里云镜像(默认源测速失败)"
|
||||
UV_PIP_INDEX_OPTION=(-i "$aliyun_url")
|
||||
echo -e "${RED}默认源测速失败,已选择${PYPI_INDEX_NAME}:${PYPI_INDEX_URL}${RESET}"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ $aliyun_status -ne 0 && $default_status -eq 0 ]]; then
|
||||
PYPI_INDEX_URL="$default_url"
|
||||
PYPI_INDEX_NAME="默认源(阿里云测速失败)"
|
||||
UV_PIP_INDEX_OPTION=()
|
||||
echo -e "${RED}阿里云测速失败,已选择${PYPI_INDEX_NAME}:不显式指定 -i 参数${RESET}"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ $aliyun_status -ne 0 && $default_status -ne 0 ]]; then
|
||||
PYPI_INDEX_URL="$default_url"
|
||||
PYPI_INDEX_NAME="默认源(双源测速失败)"
|
||||
UV_PIP_INDEX_OPTION=()
|
||||
echo -e "${RED}默认源和阿里云测速均失败,回退到${PYPI_INDEX_NAME}:不显式指定 -i 参数${RESET}"
|
||||
return
|
||||
fi
|
||||
|
||||
if awk "BEGIN {exit !(${aliyun_latency} < ${default_latency})}"; then
|
||||
PYPI_INDEX_URL="$aliyun_url"
|
||||
PYPI_INDEX_NAME="阿里云镜像"
|
||||
UV_PIP_INDEX_OPTION=(-i "$aliyun_url")
|
||||
else
|
||||
PYPI_INDEX_URL="$default_url"
|
||||
PYPI_INDEX_NAME="默认源"
|
||||
UV_PIP_INDEX_OPTION=()
|
||||
fi
|
||||
|
||||
if [[ ${#UV_PIP_INDEX_OPTION[@]} -gt 0 ]]; then
|
||||
echo -e "${GREEN}已选择${PYPI_INDEX_NAME}:${PYPI_INDEX_URL}${RESET}"
|
||||
else
|
||||
echo -e "${GREEN}已选择${PYPI_INDEX_NAME}:不显式指定 -i 参数${RESET}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ----------- 主安装流程 -----------
|
||||
run_installation() {
|
||||
# 1/6: 检测是否安装 whiptail
|
||||
@@ -221,10 +574,21 @@ run_installation() {
|
||||
pacman -Syu --noconfirm whiptail
|
||||
elif command -v yum &>/dev/null; then
|
||||
yum install -y whiptail
|
||||
elif command -v brew &>/dev/null || [[ -x /opt/homebrew/bin/brew ]] || [[ -x /usr/local/bin/brew ]]; then
|
||||
run_brew install newt
|
||||
|
||||
# 确保当前 shell 能找到 Homebrew 安装的 whiptail。
|
||||
[[ -x /opt/homebrew/bin/whiptail ]] && export PATH="/opt/homebrew/bin:${PATH}"
|
||||
[[ -x /usr/local/bin/whiptail ]] && export PATH="/usr/local/bin:${PATH}"
|
||||
else
|
||||
echo -e "${RED}[Error] 无受支持的包管理器,无法安装 whiptail!${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v whiptail &>/dev/null; then
|
||||
echo -e "${RED}[Error] whiptail 安装失败或不可用,请手动安装后重试。${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
whiptail --title "ℹ️ 提示" --msgbox "如果您没有特殊需求,请优先使用docker方式部署。" 10 60
|
||||
@@ -239,6 +603,13 @@ run_installation() {
|
||||
|
||||
# 系统检查
|
||||
check_system() {
|
||||
if [[ "$IS_MACOS" == true ]]; then
|
||||
ID="macos"
|
||||
VERSION_ID="$(sw_vers -productVersion 2>/dev/null)"
|
||||
PRETTY_NAME="macOS ${VERSION_ID}"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
whiptail --title "🚫 权限不足" --msgbox "请使用 root 用户运行此脚本!\n执行方式: sudo bash $0" 10 60
|
||||
exit 1
|
||||
@@ -278,6 +649,9 @@ run_installation() {
|
||||
# 添加arch包管理器
|
||||
PKG_MANAGER="pacman"
|
||||
;;
|
||||
macos)
|
||||
PKG_MANAGER="brew"
|
||||
;;
|
||||
esac
|
||||
|
||||
# 检查NapCat
|
||||
@@ -294,7 +668,7 @@ run_installation() {
|
||||
install_packages() {
|
||||
missing_packages=()
|
||||
# 检查 common 及当前系统专属依赖
|
||||
for package in ${REQUIRED_PACKAGES["common"]} ${REQUIRED_PACKAGES["$ID"]}; do
|
||||
for package in $(get_required_packages "$ID"); do
|
||||
case "$PKG_MANAGER" in
|
||||
apt)
|
||||
dpkg -s "$package" &>/dev/null || missing_packages+=("$package")
|
||||
@@ -305,6 +679,22 @@ run_installation() {
|
||||
pacman)
|
||||
pacman -Qi "$package" &>/dev/null || missing_packages+=("$package")
|
||||
;;
|
||||
brew)
|
||||
case "$package" in
|
||||
git)
|
||||
command -v git &>/dev/null || missing_packages+=("$package")
|
||||
;;
|
||||
gnupg)
|
||||
command -v gpg &>/dev/null || missing_packages+=("$package")
|
||||
;;
|
||||
python)
|
||||
command -v python3 &>/dev/null || missing_packages+=("$package")
|
||||
;;
|
||||
*)
|
||||
run_brew list --formula "$package" &>/dev/null || missing_packages+=("$package")
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -327,8 +717,12 @@ run_installation() {
|
||||
}
|
||||
}
|
||||
|
||||
# 仅在非Arch系统上安装NapCat
|
||||
[[ "$ID" != "arch" ]] && install_napcat
|
||||
# 仅在 Linux 非 Arch 系统上安装 NapCat,macOS 仅支持远程 NapCat。
|
||||
if [[ "$ID" == "macos" ]]; then
|
||||
whiptail --title "⚠️ NapCat 安装提示" --msgbox "当前为 macOS,暂不支持自动安装 NapCat。\n如需使用 NapCat,请配置远程实例后再连接。 " 10 60
|
||||
elif [[ "$ID" != "arch" ]]; then
|
||||
install_napcat
|
||||
fi
|
||||
|
||||
# Python版本检查
|
||||
check_python() {
|
||||
@@ -412,6 +806,9 @@ run_installation() {
|
||||
pacman)
|
||||
pacman -S --noconfirm "${missing_packages[@]}"
|
||||
;;
|
||||
brew)
|
||||
run_brew update && run_brew install "${missing_packages[@]}"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
@@ -448,35 +845,42 @@ run_installation() {
|
||||
|
||||
|
||||
echo -e "${GREEN}安装Python依赖...${RESET}"
|
||||
select_pypi_index_url
|
||||
pip install -r MaiBot/requirements.txt
|
||||
cd MaiBot
|
||||
pip install uv
|
||||
uv pip install -i https://mirrors.aliyun.com/pypi/simple -r requirements.txt
|
||||
uv pip install "${UV_PIP_INDEX_OPTION[@]}" -r requirements.txt
|
||||
cd ..
|
||||
|
||||
echo -e "${GREEN}安装maim_message依赖...${RESET}"
|
||||
cd maim_message
|
||||
uv pip install -i https://mirrors.aliyun.com/pypi/simple -e .
|
||||
uv pip install "${UV_PIP_INDEX_OPTION[@]}" -e .
|
||||
cd ..
|
||||
|
||||
echo -e "${GREEN}部署MaiBot Napcat Adapter...${RESET}"
|
||||
cd MaiBot-Napcat-Adapter
|
||||
uv pip install -i https://mirrors.aliyun.com/pypi/simple -r requirements.txt
|
||||
uv pip install "${UV_PIP_INDEX_OPTION[@]}" -r requirements.txt
|
||||
cd ..
|
||||
|
||||
echo -e "${GREEN}同意协议...${RESET}"
|
||||
|
||||
# 首先计算当前EULA的MD5值
|
||||
current_md5=$(md5sum "MaiBot/EULA.md" | awk '{print $1}')
|
||||
current_md5=$(compute_md5 "MaiBot/EULA.md")
|
||||
|
||||
# 首先计算当前隐私条款文件的哈希值
|
||||
current_md5_privacy=$(md5sum "MaiBot/PRIVACY.md" | awk '{print $1}')
|
||||
current_md5_privacy=$(compute_md5 "MaiBot/PRIVACY.md")
|
||||
|
||||
echo -n $current_md5 > MaiBot/eula.confirmed
|
||||
echo -n $current_md5_privacy > MaiBot/privacy.confirmed
|
||||
echo -n "$current_md5" > MaiBot/eula.confirmed
|
||||
echo -n "$current_md5_privacy" > MaiBot/privacy.confirmed
|
||||
|
||||
echo -e "${GREEN}创建系统服务...${RESET}"
|
||||
cat > /etc/systemd/system/${SERVICE_NAME}.service <<EOF
|
||||
if [[ "$IS_MACOS" == true ]]; then
|
||||
echo -e "${GREEN}创建 launchctl 服务...${RESET}"
|
||||
create_launchd_services
|
||||
stop_service "${SERVICE_NAME}" >/dev/null 2>&1 || true
|
||||
stop_service "${SERVICE_NAME_NBADAPTER}" >/dev/null 2>&1 || true
|
||||
else
|
||||
echo -e "${GREEN}创建系统服务...${RESET}"
|
||||
cat > /etc/systemd/system/${SERVICE_NAME}.service <<EOF
|
||||
[Unit]
|
||||
Description=MaiCore
|
||||
After=network.target ${SERVICE_NAME_NBADAPTER}.service
|
||||
@@ -508,7 +912,7 @@ EOF
|
||||
# WantedBy=multi-user.target
|
||||
# EOF
|
||||
|
||||
cat > /etc/systemd/system/${SERVICE_NAME_NBADAPTER}.service <<EOF
|
||||
cat > /etc/systemd/system/${SERVICE_NAME_NBADAPTER}.service <<EOF
|
||||
[Unit]
|
||||
Description=MaiBot Napcat Adapter
|
||||
After=network.target mongod.service ${SERVICE_NAME}.service
|
||||
@@ -524,22 +928,30 @@ RestartSec=10s
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
# 保存安装信息
|
||||
echo "INSTALLER_VERSION=${INSTALLER_VERSION}" > /etc/maicore_install.conf
|
||||
echo "INSTALL_DIR=${INSTALL_DIR}" >> /etc/maicore_install.conf
|
||||
echo "BRANCH=${BRANCH}" >> /etc/maicore_install.conf
|
||||
save_install_info
|
||||
|
||||
whiptail --title "🎉 安装完成" --msgbox "MaiCore安装完成!\n已创建系统服务:${SERVICE_NAME}、${SERVICE_NAME_WEB}、${SERVICE_NAME_NBADAPTER}\n\n使用以下命令管理服务:\n启动服务:systemctl start ${SERVICE_NAME}\n查看状态:systemctl status ${SERVICE_NAME}" 14 60
|
||||
if [[ "$IS_MACOS" == true ]]; then
|
||||
whiptail --title "🎉 安装完成" --msgbox "MaiCore安装完成!\n已创建 launchctl 服务:${LAUNCHD_LABEL_MAIN}、${LAUNCHD_LABEL_NBADAPTER}\n\n首次加载:launchctl bootstrap ${LAUNCHD_DOMAIN} ${LAUNCHD_PLIST_MAIN}\n重启服务:launchctl kickstart -k ${LAUNCHD_DOMAIN}/${LAUNCHD_LABEL_MAIN}\n查看状态:launchctl print ${LAUNCHD_DOMAIN}/${LAUNCHD_LABEL_MAIN}" 14 100
|
||||
else
|
||||
whiptail --title "🎉 安装完成" --msgbox "MaiCore安装完成!\n已创建系统服务:${SERVICE_NAME}、${SERVICE_NAME_WEB}、${SERVICE_NAME_NBADAPTER}\n\n使用以下命令管理服务:\n启动服务:systemctl start ${SERVICE_NAME}\n查看状态:systemctl status ${SERVICE_NAME}" 14 60
|
||||
fi
|
||||
}
|
||||
|
||||
# ----------- 主执行流程 -----------
|
||||
# 检查root权限
|
||||
[[ $(id -u) -ne 0 ]] && {
|
||||
# Linux 仍需 root,macOS 使用用户级 launchctl(无需 root)。
|
||||
if [[ "$IS_MACOS" == true && $(id -u) -eq 0 ]]; then
|
||||
echo -e "${RED}macOS 请勿使用 root/sudo 运行此脚本,请直接以当前登录用户执行。${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$IS_MACOS" != true && $(id -u) -ne 0 ]]; then
|
||||
echo -e "${RED}请使用root用户运行此脚本!${RESET}"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# 如果已安装显示菜单,并检查协议是否更新
|
||||
if check_installed; then
|
||||
@@ -550,7 +962,11 @@ else
|
||||
run_installation
|
||||
# 安装完成后询问是否启动
|
||||
if whiptail --title "安装完成" --yesno "是否立即启动MaiCore服务?" 10 60; then
|
||||
systemctl start ${SERVICE_NAME}
|
||||
whiptail --msgbox "✅ 服务已启动!\n使用 systemctl status ${SERVICE_NAME} 查看状态" 10 60
|
||||
start_service "${SERVICE_NAME}"
|
||||
if [[ "$IS_MACOS" == true ]]; then
|
||||
whiptail --msgbox "✅ 服务已启动!\n使用 launchctl print ${LAUNCHD_DOMAIN}/${LAUNCHD_LABEL_MAIN} 查看状态" 10 80
|
||||
else
|
||||
whiptail --msgbox "✅ 服务已启动!\n使用 systemctl status ${SERVICE_NAME} 查看状态" 10 60
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user