mirror of
https://gitee.com/SuperManito/LinuxMirrors
synced 2025-11-02 23:40:25 +08:00
全局引入高级交互式选择器封装并更新交互内容设计
This commit is contained in:
600
ChangeMirrors.sh
600
ChangeMirrors.sh
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
## Author: SuperManito
|
||||
## Modified: 2024-12-05
|
||||
## Modified: 2024-12-06
|
||||
## License: MIT
|
||||
## GitHub: https://github.com/SuperManito/LinuxMirrors
|
||||
## Website: https://linuxmirrors.cn
|
||||
@@ -182,8 +182,8 @@ File_LinuxRelease=/etc/os-release
|
||||
File_RedHatRelease=/etc/redhat-release
|
||||
File_DebianVersion=/etc/debian_version
|
||||
File_ArmbianRelease=/etc/armbian-release
|
||||
File_OpenCloudOSRelease=/etc/opencloudos-release
|
||||
File_openEulerRelease=/etc/openEuler-release
|
||||
File_OpenCloudOSRelease=/etc/opencloudos-release
|
||||
File_AnolisOSRelease=/etc/anolis-release
|
||||
File_openKylinVersion=/etc/kylin-version/kylin-system-version.conf
|
||||
File_ArchLinuxRelease=/etc/arch-release
|
||||
@@ -229,13 +229,13 @@ PURPLE='\033[35m'
|
||||
AZURE='\033[36m'
|
||||
PLAIN='\033[0m'
|
||||
BOLD='\033[1m'
|
||||
SUCCESS="\033[1;32m✔${PLAIN}"
|
||||
COMPLETE="\033[1;32m✔${PLAIN}"
|
||||
WARN="\033[1;43m 警告 ${PLAIN}"
|
||||
ERROR="\033[1;31m✘${PLAIN}"
|
||||
FAIL="\033[1;31m✘${PLAIN}"
|
||||
TIP="\033[1;44m 提示 ${PLAIN}"
|
||||
WORKING="\033[1;36m>_${PLAIN}"
|
||||
SUCCESS=" \033[1;32m✔${PLAIN}"
|
||||
COMPLETE=" \033[1;32m✔${PLAIN}"
|
||||
WARN=" \033[1;43m 警告 ${PLAIN}"
|
||||
ERROR=" \033[1;31m✘${PLAIN}"
|
||||
FAIL=" \033[1;31m✘${PLAIN}"
|
||||
TIP=" \033[1;44m 提示 ${PLAIN}"
|
||||
WORKING=" \033[1;36m>_${PLAIN}"
|
||||
# SUCCESS="[\033[1;32m成功${PLAIN}]"
|
||||
# COMPLETE="[\033[1;32m完成${PLAIN}]"
|
||||
# WARN="[\033[1;5;33m注意${PLAIN}]"
|
||||
@@ -634,7 +634,7 @@ function run_start() {
|
||||
}
|
||||
|
||||
function run_end() {
|
||||
echo -e "\n✨️ \033[1;34mPowered by https://linuxmirrors.cn\033[0m\n"
|
||||
echo -e "\n ✨️ \033[1;34mPowered by https://linuxmirrors.cn\033[0m\n"
|
||||
}
|
||||
|
||||
## 报错退出
|
||||
@@ -666,10 +666,10 @@ function collect_system_info() {
|
||||
SYSTEM_FACTIONS="${SYSTEM_DEBIAN}"
|
||||
elif [ -s $File_RedHatRelease ]; then
|
||||
SYSTEM_FACTIONS="${SYSTEM_REDHAT}"
|
||||
elif [ -s $File_OpenCloudOSRelease ]; then
|
||||
SYSTEM_FACTIONS="${SYSTEM_OPENCLOUDOS}" # 自 9.0 版本起不再基于红帽
|
||||
elif [ -s $File_openEulerRelease ]; then
|
||||
SYSTEM_FACTIONS="${SYSTEM_OPENEULER}"
|
||||
elif [ -s $File_OpenCloudOSRelease ]; then
|
||||
SYSTEM_FACTIONS="${SYSTEM_OPENCLOUDOS}" # 自 9.0 版本起不再基于红帽
|
||||
elif [ -s $File_AnolisOSRelease ]; then
|
||||
SYSTEM_FACTIONS="${SYSTEM_ANOLISOS}" # 自 8.8 版本起不再基于红帽
|
||||
elif [ -s $File_openKylinVersion ]; then
|
||||
@@ -747,13 +747,13 @@ function collect_system_info() {
|
||||
is_supported="false"
|
||||
fi
|
||||
;;
|
||||
"${SYSTEM_OPENCLOUDOS}")
|
||||
if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != [8-9] && "${SYSTEM_VERSION_NUMBER_MAJOR}" != 23 ]] || [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" == 8 && "$SYSTEM_VERSION_NUMBER_MINOR" -lt 6 ]]; then
|
||||
"${SYSTEM_OPENEULER}")
|
||||
if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != 2[1-4] ]]; then
|
||||
is_supported="false"
|
||||
fi
|
||||
;;
|
||||
"${SYSTEM_OPENEULER}")
|
||||
if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != 2[1-4] ]]; then
|
||||
"${SYSTEM_OPENCLOUDOS}")
|
||||
if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != [8-9] && "${SYSTEM_VERSION_NUMBER_MAJOR}" != 23 ]] || [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" == 8 && "$SYSTEM_VERSION_NUMBER_MINOR" -lt 6 ]]; then
|
||||
is_supported="false"
|
||||
fi
|
||||
;;
|
||||
@@ -884,7 +884,7 @@ function collect_system_info() {
|
||||
"${SYSTEM_DEBIAN}" | "${SYSTEM_ALPINE}" | "${SYSTEM_OPENKYLIN}")
|
||||
SYNC_MIRROR_TEXT="更新软件源"
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
SYNC_MIRROR_TEXT="生成软件源缓存"
|
||||
;;
|
||||
"${SYSTEM_OPENSUSE}")
|
||||
@@ -894,6 +894,11 @@ function collect_system_info() {
|
||||
SYNC_MIRROR_TEXT="同步软件源"
|
||||
;;
|
||||
esac
|
||||
## 判断是否可以使用高级交互式选择器
|
||||
CAN_USE_ADVANCED_INTERACTIVE_SELECTION="false"
|
||||
if [ ! -z "$(command -v tput)" ]; then
|
||||
CAN_USE_ADVANCED_INTERACTIVE_SELECTION="true"
|
||||
fi
|
||||
}
|
||||
|
||||
## 命令选项兼容性判断
|
||||
@@ -975,8 +980,8 @@ function choose_mirrors() {
|
||||
done
|
||||
else
|
||||
for ((i = 0; i < ${#list_arr[@]}; i++)); do
|
||||
tmp_mirror_name=$(echo "${list_arr[i]}" | awk -F '@' '{print$1}') # 软件源名称
|
||||
tmp_mirror_url=$(echo "${list_arr[i]}" | awk -F '@' '{print$2}') # 软件源地址
|
||||
tmp_mirror_name="${list_arr[i]%@*}" # 软件源名称
|
||||
tmp_mirror_url="${list_arr[i]#*@}" # 软件源地址
|
||||
arr_num=$((i + 1))
|
||||
echo -e " ❖ $arr_num. ${tmp_mirror_url} | ${tmp_mirror_name}"
|
||||
done
|
||||
@@ -991,26 +996,35 @@ function choose_mirrors() {
|
||||
for ((i = 0; i < ${#mirror_list_extranet[@]}; i++)); do
|
||||
if [[ "${SOURCE}" == "${mirror_list_extranet[i]}" ]]; then
|
||||
intranet_source="${mirror_list_intranet[i]}"
|
||||
ONLY_HTTP="True"
|
||||
ONLY_HTTP="true" # 内网地址一般不支持 HTTPS 协议
|
||||
break
|
||||
else
|
||||
continue
|
||||
fi
|
||||
done
|
||||
if [[ -z "${USE_INTRANET_SOURCE}" ]]; then
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 默认使用软件源的公网地址,是否继续? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss]) ;;
|
||||
[Nn] | [Nn][Oo])
|
||||
SOURCE="${intranet_source}"
|
||||
echo -e "\n$WARN 已切换至内网专用地址,仅限在特定环境下使用!"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不使用内网地址!"
|
||||
;;
|
||||
esac
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
echo ''
|
||||
interactive_select_boolean "${BOLD}默认使用软件源的公网地址,是否继续?${PLAIN}"
|
||||
if [[ "${_SELECT_RESULT}" == "false" ]]; then
|
||||
SOURCE="${intranet_source}"
|
||||
echo -e "\n$WARN 已切换至内网专用地址,仅限在特定环境下使用!"
|
||||
fi
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 默认使用软件源的公网地址,是否继续? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss]) ;;
|
||||
[Nn] | [Nn][Oo])
|
||||
SOURCE="${intranet_source}"
|
||||
echo -e "\n$WARN 已切换至内网专用地址,仅限在特定环境下使用!"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不使用内网地址!"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
elif [[ "${USE_INTRANET_SOURCE}" == "true" ]]; then
|
||||
SOURCE="${intranet_source}"
|
||||
fi
|
||||
@@ -1034,39 +1048,44 @@ function choose_mirrors() {
|
||||
if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ ${USE_ABROAD_SOURCE} = "true" ]]; then
|
||||
local mirror_list_name="mirror_list_abroad"
|
||||
print_mirrors_list "${mirror_list_name}" 60
|
||||
elif [[ ${USE_EDU_SOURCE} = "true" ]]; then
|
||||
local mirror_list_name="mirror_list_edu"
|
||||
print_mirrors_list "${mirror_list_name}" 31
|
||||
local mirror_list_name mirror_list_print_length
|
||||
if [[ "${USE_ABROAD_SOURCE}" = "true" ]]; then
|
||||
mirror_list_name="mirror_list_abroad"
|
||||
mirror_list_print_length=60
|
||||
elif [[ "${USE_EDU_SOURCE}" = "true" ]]; then
|
||||
mirror_list_name="mirror_list_edu"
|
||||
mirror_list_print_length=31
|
||||
else
|
||||
local mirror_list_name="mirror_list_default"
|
||||
print_mirrors_list "${mirror_list_name}" 31
|
||||
mirror_list_name="mirror_list_default"
|
||||
mirror_list_print_length=31
|
||||
fi
|
||||
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 请选择并输入你想使用的软件源 [ 1-$(eval echo \${#$mirror_list_name[@]}) ]:${PLAIN}")
|
||||
while true; do
|
||||
read -rp "${CHOICE}" INPUT
|
||||
case "${INPUT}" in
|
||||
[1-9] | [1-9][0-9] | [1-9][0-9][0-9])
|
||||
local tmp_source
|
||||
tmp_source="$(eval echo \${${mirror_list_name}[$((INPUT - 1))]})"
|
||||
if [[ -z "${tmp_source}" ]]; then
|
||||
echo -e "\n$WARN 请输入有效的数字序号!"
|
||||
else
|
||||
SOURCE="$(eval echo \${${mirror_list_name}[$((INPUT - 1))]} | awk -F '@' '{print$2}')"
|
||||
# echo "${SOURCE}"
|
||||
# exit
|
||||
break
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 请输入数字序号以选择你想使用的软件源!"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
eval "interactive_select_mirror \"\${${mirror_list_name}[@]}\" \"\\n \${BOLD}请选择你想使用的软件源:\${PLAIN}\\n\""
|
||||
SOURCE="${_SELECT_RESULT#*@}"
|
||||
echo -e "\n ${GREEN}➜${PLAIN} ${BOLD}${_SELECT_RESULT%@*}${PLAIN}" | sed "s| · | |g"
|
||||
else
|
||||
print_mirrors_list "${mirror_list_name}" $mirror_list_print_length
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 请选择并输入你想使用的软件源 [ 1-$(eval echo \${#$mirror_list_name[@]}) ]:${PLAIN}")
|
||||
while true; do
|
||||
read -rp "${CHOICE}" INPUT
|
||||
case "${INPUT}" in
|
||||
[1-9] | [1-9][0-9] | [1-9][0-9][0-9])
|
||||
local tmp_source
|
||||
tmp_source="$(eval echo \${${mirror_list_name}[$((INPUT - 1))]})"
|
||||
if [[ -z "${tmp_source}" ]]; then
|
||||
echo -e "\n$WARN 请输入有效的数字序号!"
|
||||
else
|
||||
SOURCE="$(eval echo \${${mirror_list_name}[$((INPUT - 1))]} | awk -F '@' '{print$2}')"
|
||||
break
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 请输入数字序号以选择你想使用的软件源!"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
## 选择软件源内网地址
|
||||
@@ -1078,24 +1097,34 @@ function choose_mirrors() {
|
||||
## 选择同步或更新软件源所使用的 WEB 协议( HTTP/HTTPS)
|
||||
function choose_protocol() {
|
||||
if [[ -z "${WEB_PROTOCOL}" ]]; then
|
||||
if [[ "${ONLY_HTTP}" == "True" ]]; then
|
||||
if [[ "${ONLY_HTTP}" == "true" ]]; then
|
||||
WEB_PROTOCOL="http"
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 软件源是否使用 HTTP 协议? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
WEB_PROTOCOL="http"
|
||||
;;
|
||||
[Nn] | [Nn][Oo])
|
||||
WEB_PROTOCOL="https"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认使用 HTTPS 协议!"
|
||||
WEB_PROTOCOL="https"
|
||||
;;
|
||||
esac
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
echo ''
|
||||
interactive_select_boolean "${BOLD}软件源是否使用 HTTP 协议?${PLAIN}"
|
||||
if [[ "${_SELECT_RESULT}" == "true" ]]; then
|
||||
WEB_PROTOCOL="http"
|
||||
else
|
||||
WEB_PROTOCOL="https"
|
||||
fi
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 软件源是否使用 HTTP 协议? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
WEB_PROTOCOL="http"
|
||||
;;
|
||||
[Nn] | [Nn][Oo])
|
||||
WEB_PROTOCOL="https"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认使用 HTTPS 协议!"
|
||||
WEB_PROTOCOL="https"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
WEB_PROTOCOL="${WEB_PROTOCOL,,}"
|
||||
@@ -1132,25 +1161,39 @@ function choose_install_epel_packages() {
|
||||
esac
|
||||
## 选择是否安装 EPEL 附加软件包
|
||||
if [[ -z "${INSTALL_EPEL}" ]]; then
|
||||
if [ $VERIFICATION_EPEL -eq 0 ]; then
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 检测到系统已安装 EPEL 附加软件包,是否替换/覆盖软件源? [Y/n] ${PLAIN}")
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
echo ''
|
||||
if [ $VERIFICATION_EPEL -eq 0 ]; then
|
||||
interactive_select_boolean "${BOLD}检测到系统已安装 EPEL 附加软件包,是否替换/覆盖软件源?${PLAIN}"
|
||||
else
|
||||
interactive_select_boolean "${BOLD}是否安装 EPEL 附加软件包?${PLAIN}"
|
||||
fi
|
||||
if [[ "${_SELECT_RESULT}" == "true" ]]; then
|
||||
INSTALL_EPEL="true"
|
||||
else
|
||||
INSTALL_EPEL="false"
|
||||
fi
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 是否安装 EPEL 附加软件包? [Y/n] ${PLAIN}")
|
||||
if [ $VERIFICATION_EPEL -eq 0 ]; then
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 检测到系统已安装 EPEL 附加软件包,是否替换/覆盖软件源? [Y/n] ${PLAIN}")
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 是否安装 EPEL 附加软件包? [Y/n] ${PLAIN}")
|
||||
fi
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
INSTALL_EPEL="true"
|
||||
;;
|
||||
[Nn] | [Nn][Oo])
|
||||
INSTALL_EPEL="false"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不更换!"
|
||||
INSTALL_EPEL="false"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
INSTALL_EPEL="true"
|
||||
;;
|
||||
[Nn] | [Nn][Oo])
|
||||
INSTALL_EPEL="false"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不更换!"
|
||||
INSTALL_EPEL="false"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1161,18 +1204,26 @@ function close_firewall_service() {
|
||||
fi
|
||||
if [[ "$(systemctl is-active firewalld)" == "active" ]]; then
|
||||
if [[ -z "${CLOSE_FIREWALL}" ]]; then
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 是否关闭防火墙和 SELinux ? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
CLOSE_FIREWALL="true"
|
||||
;;
|
||||
[Nn] | [Nn][Oo]) ;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不关闭!"
|
||||
;;
|
||||
esac
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
echo ''
|
||||
interactive_select_boolean "${BOLD}是否关闭防火墙和 SELinux ?${PLAIN}"
|
||||
if [[ "${_SELECT_RESULT}" == "true" ]]; then
|
||||
CLOSE_FIREWALL="true"
|
||||
fi
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 是否关闭防火墙和 SELinux ? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
CLOSE_FIREWALL="true"
|
||||
;;
|
||||
[Nn] | [Nn][Oo]) ;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不关闭!"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
if [[ "${CLOSE_FIREWALL}" == "true" ]]; then
|
||||
local SelinuxConfig=/etc/selinux/config
|
||||
@@ -1199,20 +1250,30 @@ function backup_original_mirrors() {
|
||||
if [[ "${IGNORE_BACKUP_TIPS}" != "false" ]]; then
|
||||
return
|
||||
fi
|
||||
local CHOICE_BACKUP=$(echo -e "\n${BOLD}└─ 检测到系统中存在已备份的 ${type} 源文件,是否跳过覆盖备份? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE_BACKUP}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss]) ;;
|
||||
[Nn] | [Nn][Oo])
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
echo ''
|
||||
cp -rvf "${target_file}" "${backup_file}" 2>&1
|
||||
BACKED_UP="true"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不覆盖!"
|
||||
;;
|
||||
esac
|
||||
interactive_select_boolean "${BOLD}检测到系统中存在已备份的 ${type} 源文件,是否跳过覆盖备份?${PLAIN}"
|
||||
if [[ "${_SELECT_RESULT}" == "false" ]]; then
|
||||
echo ''
|
||||
cp -rvf "${target_file}" "${backup_file}" 2>&1
|
||||
BACKED_UP="true"
|
||||
fi
|
||||
else
|
||||
local CHOICE_BACKUP=$(echo -e "\n${BOLD}└─ 检测到系统中存在已备份的 ${type} 源文件,是否跳过覆盖备份? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE_BACKUP}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss]) ;;
|
||||
[Nn] | [Nn][Oo])
|
||||
echo ''
|
||||
cp -rvf "${target_file}" "${backup_file}" 2>&1
|
||||
BACKED_UP="true"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不覆盖!"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else
|
||||
echo ''
|
||||
cp -rvf "${target_file}" "${backup_file}" 2>&1
|
||||
@@ -1237,20 +1298,30 @@ function backup_original_mirrors() {
|
||||
if [[ "${IGNORE_BACKUP_TIPS}" != "false" ]]; then
|
||||
return
|
||||
fi
|
||||
local CHOICE_BACKUP=$(echo -e "\n${BOLD}└─ 检测到系统中存在已备份的 repo 源文件,是否跳过覆盖备份? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE_BACKUP}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss]) ;;
|
||||
[Nn] | [Nn][Oo])
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
echo ''
|
||||
cp -rvf $target_dir/* "${backup_dir}" 2>&1
|
||||
BACKED_UP="true"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不覆盖!"
|
||||
;;
|
||||
esac
|
||||
interactive_select_boolean "${BOLD}检测到系统中存在已备份的 repo 源文件,是否跳过覆盖备份?${PLAIN}"
|
||||
if [[ "${_SELECT_RESULT}" == "false" ]]; then
|
||||
echo ''
|
||||
cp -rvf $target_dir/* "${backup_dir}" 2>&1
|
||||
BACKED_UP="true"
|
||||
fi
|
||||
else
|
||||
local CHOICE_BACKUP=$(echo -e "\n${BOLD}└─ 检测到系统中存在已备份的 repo 源文件,是否跳过覆盖备份? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE_BACKUP}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss]) ;;
|
||||
[Nn] | [Nn][Oo])
|
||||
echo ''
|
||||
cp -rvf $target_dir/* "${backup_dir}" 2>&1
|
||||
BACKED_UP="true"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不覆盖!"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else
|
||||
echo ''
|
||||
cp -rvf $target_dir/* "${backup_dir}" 2>&1
|
||||
@@ -1290,7 +1361,7 @@ function backup_original_mirrors() {
|
||||
backup_file $File_LinuxMintSourceList $File_LinuxMintSourceListBackup "official-package-repositories.list"
|
||||
fi
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
# /etc/yum.repos.d
|
||||
backup_dir $Dir_YumRepos $Dir_YumReposBackup
|
||||
;;
|
||||
@@ -1415,13 +1486,6 @@ function remove_original_mirrors() {
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
"${SYSTEM_OPENCLOUDOS}")
|
||||
if [ ! -d $Dir_YumRepos ]; then
|
||||
mkdir -p $Dir_YumRepos
|
||||
return
|
||||
fi
|
||||
rm -rf $Dir_YumRepos/OpenCloudOS*
|
||||
;;
|
||||
"${SYSTEM_OPENEULER}")
|
||||
if [ ! -d $Dir_YumRepos ]; then
|
||||
mkdir -p $Dir_YumRepos
|
||||
@@ -1429,6 +1493,13 @@ function remove_original_mirrors() {
|
||||
fi
|
||||
rm -rf $Dir_YumRepos/openEuler.repo
|
||||
;;
|
||||
"${SYSTEM_OPENCLOUDOS}")
|
||||
if [ ! -d $Dir_YumRepos ]; then
|
||||
mkdir -p $Dir_YumRepos
|
||||
return
|
||||
fi
|
||||
rm -rf $Dir_YumRepos/OpenCloudOS*
|
||||
;;
|
||||
"${SYSTEM_ANOLISOS}")
|
||||
if [ ! -d $Dir_YumRepos ]; then
|
||||
mkdir -p $Dir_YumRepos
|
||||
@@ -1494,7 +1565,7 @@ function change_mirrors_main() {
|
||||
diff_file $File_LinuxMintSourceListBackup $File_LinuxMintSourceList
|
||||
fi
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
diff_dir $Dir_YumReposBackup $Dir_YumRepos
|
||||
;;
|
||||
"${SYSTEM_OPENSUSE}")
|
||||
@@ -1522,12 +1593,12 @@ function change_mirrors_main() {
|
||||
"${SYSTEM_REDHAT}")
|
||||
change_mirrors_RedHat
|
||||
;;
|
||||
"${SYSTEM_OPENCLOUDOS}")
|
||||
change_mirrors_OpenCloudOS
|
||||
;;
|
||||
"${SYSTEM_OPENEULER}")
|
||||
change_mirrors_openEuler
|
||||
;;
|
||||
"${SYSTEM_OPENCLOUDOS}")
|
||||
change_mirrors_OpenCloudOS
|
||||
;;
|
||||
"${SYSTEM_ANOLISOS}")
|
||||
change_mirrors_AnolisOS
|
||||
;;
|
||||
@@ -1557,7 +1628,7 @@ function change_mirrors_main() {
|
||||
"${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}")
|
||||
apt-get update
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
local package_manager="$(get_package_manager)"
|
||||
$package_manager makecache
|
||||
;;
|
||||
@@ -1595,18 +1666,26 @@ function upgrade_software() {
|
||||
## 交互确认
|
||||
if [[ -z "${CLEAN_CACHE}" ]]; then
|
||||
CLEAN_CACHE="false"
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 是否清理已下载的软件包缓存? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
CLEAN_CACHE="true"
|
||||
;;
|
||||
[Nn] | [Nn][Oo]) ;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不清理!"
|
||||
;;
|
||||
esac
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
echo ''
|
||||
interactive_select_boolean "${BOLD}是否清理已下载的软件包缓存?${PLAIN}"
|
||||
if [[ "${_SELECT_RESULT}" == "true" ]]; then
|
||||
CLEAN_CACHE="true"
|
||||
fi
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 是否清理已下载的软件包缓存? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
CLEAN_CACHE="true"
|
||||
;;
|
||||
[Nn] | [Nn][Oo]) ;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不清理!"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
if [[ "${CLEAN_CACHE}" == "false" ]]; then
|
||||
return
|
||||
@@ -1617,7 +1696,7 @@ function upgrade_software() {
|
||||
apt-get autoremove -y >/dev/null 2>&1
|
||||
apt-get clean >/dev/null 2>&1
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
local package_manager="$(get_package_manager)"
|
||||
$package_manager autoremove -y >/dev/null 2>&1
|
||||
$package_manager clean packages -y >/dev/null 2>&1
|
||||
@@ -1646,18 +1725,26 @@ function upgrade_software() {
|
||||
## 交互确认
|
||||
if [[ -z "${UPGRADE_SOFTWARE}" ]]; then
|
||||
UPGRADE_SOFTWARE="false"
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 是否跳过更新软件包? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss]) ;;
|
||||
[Nn] | [Nn][Oo])
|
||||
UPGRADE_SOFTWARE="true"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不更新!"
|
||||
;;
|
||||
esac
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
echo ''
|
||||
interactive_select_boolean "${BOLD}是否跳过更新软件包?${PLAIN}"
|
||||
if [[ "${_SELECT_RESULT}" == "false" ]]; then
|
||||
UPGRADE_SOFTWARE="true"
|
||||
fi
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 是否跳过更新软件包? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss]) ;;
|
||||
[Nn] | [Nn][Oo])
|
||||
UPGRADE_SOFTWARE="true"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不更新!"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
if [[ "${UPGRADE_SOFTWARE}" == "false" ]]; then
|
||||
return
|
||||
@@ -1668,7 +1755,7 @@ function upgrade_software() {
|
||||
"${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}")
|
||||
apt-get upgrade -y
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
local package_manager="$(get_package_manager)"
|
||||
$package_manager update -y --skip-broken
|
||||
;;
|
||||
@@ -2336,13 +2423,178 @@ function get_package_manager() {
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"${SYSTEM_FEDORA}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_FEDORA}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
command="dnf"
|
||||
;;
|
||||
esac
|
||||
echo "${command}"
|
||||
}
|
||||
|
||||
function interactive_select_mirror() {
|
||||
_SELECT_RESULT=""
|
||||
local options=("$@")
|
||||
local message="${options[${#options[@]} - 1]}"
|
||||
unset options[${#options[@]}-1]
|
||||
local selected=0
|
||||
local start=0
|
||||
local page_size=$(($(tput lines) - 3)) # 减去1行用于显示提示信息
|
||||
function clear_menu() {
|
||||
tput rc
|
||||
for ((i = 0; i < ${#options[@]} + 1; i++)); do
|
||||
echo -e "\r\033[K"
|
||||
done
|
||||
tput rc
|
||||
}
|
||||
function cleanup() {
|
||||
clear_menu
|
||||
tput rc
|
||||
tput cnorm
|
||||
tput rmcup
|
||||
exit
|
||||
}
|
||||
function draw_menu() {
|
||||
tput clear
|
||||
tput cup 0 0
|
||||
echo -e "${message}"
|
||||
local end=$((start + page_size - 1))
|
||||
if [ $end -ge ${#options[@]} ]; then
|
||||
end=${#options[@]}-1
|
||||
fi
|
||||
for ((i = start; i <= end; i++)); do
|
||||
if [ "$i" -eq "$selected" ]; then
|
||||
echo -e "\e[34;4m➤ ${options[$i]%@*}\e[0m"
|
||||
else
|
||||
echo -e " ${options[$i]%@*}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
function read_key() {
|
||||
IFS= read -rsn1 key
|
||||
if [[ $key == $'\x1b' ]]; then
|
||||
IFS= read -rsn2 key
|
||||
key="$key"
|
||||
fi
|
||||
echo "$key"
|
||||
}
|
||||
tput smcup # 保存当前屏幕并切换到新屏幕
|
||||
tput sc # 保存光标位置
|
||||
tput civis # 隐藏光标
|
||||
trap "cleanup" INT TERM # 捕捉脚本结束时恢复光标
|
||||
draw_menu # 初始化菜单位置
|
||||
# 处理选择
|
||||
while true; do
|
||||
key=$(read_key)
|
||||
case "$key" in
|
||||
"[A")
|
||||
# 上箭头
|
||||
if [ "$selected" -gt 0 ]; then
|
||||
selected=$((selected - 1))
|
||||
if [ "$selected" -lt "$start" ]; then
|
||||
start=$((start - 1))
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
"[B")
|
||||
# 下箭头
|
||||
if [ "$selected" -lt $((${#options[@]} - 1)) ]; then
|
||||
selected=$((selected + 1))
|
||||
if [ "$selected" -ge $((start + page_size)) ]; then
|
||||
start=$((start + 1))
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
"")
|
||||
# Enter 键
|
||||
tput rmcup
|
||||
break
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
draw_menu
|
||||
done
|
||||
# clear_menu # 清除菜单
|
||||
tput cnorm # 恢复光标
|
||||
tput rmcup # 恢复之前的屏幕
|
||||
# tput rc # 恢复光标位置
|
||||
# 处理结果
|
||||
_SELECT_RESULT="${options[$selected]}"
|
||||
}
|
||||
|
||||
function interactive_select_boolean() {
|
||||
_SELECT_RESULT=""
|
||||
local selected=0
|
||||
local message="$1"
|
||||
function clear_menu() {
|
||||
tput rc
|
||||
for ((i = 0; i < 2 + 2; i++)); do
|
||||
echo -e "\r\033[K"
|
||||
done
|
||||
tput rc
|
||||
}
|
||||
function cleanup() {
|
||||
clear_menu
|
||||
tput rc
|
||||
tput cnorm
|
||||
tput rmcup
|
||||
exit
|
||||
}
|
||||
function draw_menu() {
|
||||
tput rc
|
||||
echo -e "╭─ ${message}"
|
||||
echo -e "│"
|
||||
if [ "$selected" -eq 0 ]; then
|
||||
echo -e "╰─ \033[32m●\033[0m 是\033[2m / ○ 否\033[0m"
|
||||
else
|
||||
echo -e "╰─ \033[2m○ 是 / \033[0m\033[32m●\033[0m 否"
|
||||
fi
|
||||
}
|
||||
function read_key() {
|
||||
IFS= read -rsn1 key
|
||||
if [[ $key == $'\x1b' ]]; then
|
||||
IFS= read -rsn2 key
|
||||
key="$key"
|
||||
fi
|
||||
echo "$key"
|
||||
}
|
||||
tput sc # 保存光标位置
|
||||
tput civis # 隐藏光标
|
||||
trap "cleanup" INT TERM # 捕捉脚本结束时恢复光标
|
||||
draw_menu # 初始化菜单位置
|
||||
# 处理选择
|
||||
while true; do
|
||||
key=$(read_key)
|
||||
case "$key" in
|
||||
"[D")
|
||||
# 左箭头
|
||||
if [ "$selected" -gt 0 ]; then
|
||||
selected=$((selected - 1))
|
||||
fi
|
||||
;;
|
||||
"[C")
|
||||
# 右箭头
|
||||
if [ "$selected" -lt 1 ]; then
|
||||
selected=$((selected + 1))
|
||||
fi
|
||||
;;
|
||||
"")
|
||||
# Enter 键
|
||||
break
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
draw_menu
|
||||
done
|
||||
# clear_menu # 清除菜单
|
||||
tput cnorm # 恢复光标
|
||||
# tput rc # 恢复光标位置
|
||||
# 处理结果
|
||||
if [ "$selected" -eq 0 ]; then
|
||||
_SELECT_RESULT="true"
|
||||
else
|
||||
_SELECT_RESULT="false"
|
||||
fi
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
|
||||
## 生成 CentOS 官方 repo 源文件
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
## Author: SuperManito
|
||||
## Modified: 2024-12-05
|
||||
## Modified: 2024-12-06
|
||||
## License: MIT
|
||||
## GitHub: https://github.com/SuperManito/LinuxMirrors
|
||||
## Website: https://linuxmirrors.cn
|
||||
@@ -83,8 +83,8 @@ File_LinuxRelease=/etc/os-release
|
||||
File_RedHatRelease=/etc/redhat-release
|
||||
File_DebianVersion=/etc/debian_version
|
||||
File_ArmbianRelease=/etc/armbian-release
|
||||
File_OpenCloudOSRelease=/etc/opencloudos-release
|
||||
File_openEulerRelease=/etc/openEuler-release
|
||||
File_OpenCloudOSRelease=/etc/opencloudos-release
|
||||
File_AnolisOSRelease=/etc/anolis-release
|
||||
File_ArchLinuxRelease=/etc/arch-release
|
||||
File_AlpineRelease=/etc/alpine-release
|
||||
@@ -112,13 +112,13 @@ PURPLE='\033[35m'
|
||||
AZURE='\033[36m'
|
||||
PLAIN='\033[0m'
|
||||
BOLD='\033[1m'
|
||||
SUCCESS="\033[1;32m✔${PLAIN}"
|
||||
COMPLETE="\033[1;32m✔${PLAIN}"
|
||||
WARN="\033[1;43m 警告 ${PLAIN}"
|
||||
ERROR="\033[1;31m✘${PLAIN}"
|
||||
FAIL="\033[1;31m✘${PLAIN}"
|
||||
TIP="\033[1;44m 提示 ${PLAIN}"
|
||||
WORKING="\033[1;36m>_${PLAIN}"
|
||||
SUCCESS=" \033[1;32m✔${PLAIN}"
|
||||
COMPLETE=" \033[1;32m✔${PLAIN}"
|
||||
WARN=" \033[1;43m 警告 ${PLAIN}"
|
||||
ERROR=" \033[1;31m✘${PLAIN}"
|
||||
FAIL=" \033[1;31m✘${PLAIN}"
|
||||
TIP=" \033[1;44m 提示 ${PLAIN}"
|
||||
WORKING=" \033[1;36m>_${PLAIN}"
|
||||
# SUCCESS="[\033[1;32m成功${PLAIN}]"
|
||||
# COMPLETE="[\033[1;32m完成${PLAIN}]"
|
||||
# WARN="[\033[1;5;33m注意${PLAIN}]"
|
||||
@@ -264,7 +264,7 @@ function run_start() {
|
||||
|
||||
## 运行结束
|
||||
function run_end() {
|
||||
echo -e "\n✨️ \033[1;34mPowered by https://linuxmirrors.cn\033[0m\n"
|
||||
echo -e "\n ✨️ \033[1;34mPowered by https://linuxmirrors.cn\033[0m\n"
|
||||
# echo -e "\n ------ 脚本运行结束 ------"
|
||||
# echo -e ' \033[0;1;35;95m┌─\033[0;1;31;91m──\033[0;1;33;93m──\033[0;1;32;92m──\033[0;1;36;96m──\033[0;1;34;94m──\033[0;1;35;95m──\033[0;1;31;91m──\033[0;1;33;93m──\033[0;1;32;92m──\033[0;1;36;96m──\033[0;1;34;94m──\033[0;1;35;95m──\033[0;1;31;91m──\033[0;1;33;93m──\033[0;1;32;92m──\033[0;1;36;96m┐\033[0m'
|
||||
# echo -e ' \033[0;1;31;91m│▞\033[0;1;33;93m▀▖\033[0m \033[0;1;32;92m▙▗\033[0;1;36;96m▌\033[0m \033[0;1;31;91m▗\033[0;1;33;93m▐\033[0m \033[0;1;34;94m│\033[0m'
|
||||
@@ -304,14 +304,14 @@ function collect_system_info() {
|
||||
SYSTEM_FACTIONS="${SYSTEM_DEBIAN}"
|
||||
elif [ -s $File_RedHatRelease ]; then
|
||||
SYSTEM_FACTIONS="${SYSTEM_REDHAT}"
|
||||
elif [ -s $File_openEulerRelease ]; then
|
||||
SYSTEM_FACTIONS="${SYSTEM_OPENEULER}"
|
||||
elif [ -s $File_OpenCloudOSRelease ]; then
|
||||
# 拦截 OpenCloudOS 9 及以上版本,非红帽版本不支持从 Docker 官方仓库安装
|
||||
if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" -ge 9 ]]; then
|
||||
output_error "不支持当前操作系统,请参考如下命令自行安装:\n\ndnf install -y docker\nsystemctl enable --now docker"
|
||||
fi
|
||||
SYSTEM_FACTIONS="${SYSTEM_OPENCLOUDOS}" # 自 9.0 版本起不再基于红帽
|
||||
elif [ -s $File_openEulerRelease ]; then
|
||||
SYSTEM_FACTIONS="${SYSTEM_OPENEULER}"
|
||||
elif [ -s $File_AnolisOSRelease ]; then
|
||||
# 拦截 Anolis OS 8 版本,不支持从 Docker 官方仓库安装
|
||||
if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" == 8 ]]; then
|
||||
@@ -415,7 +415,7 @@ function collect_system_info() {
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
SOURCE_BRANCH="centos"
|
||||
;;
|
||||
esac
|
||||
@@ -424,10 +424,15 @@ function collect_system_info() {
|
||||
"${SYSTEM_DEBIAN}")
|
||||
SYNC_MIRROR_TEXT="更新软件源"
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
SYNC_MIRROR_TEXT="生成软件源缓存"
|
||||
;;
|
||||
esac
|
||||
## 判断是否可以使用高级交互式选择器
|
||||
CAN_USE_ADVANCED_INTERACTIVE_SELECTION="false"
|
||||
if [ ! -z "$(command -v tput)" ]; then
|
||||
CAN_USE_ADVANCED_INTERACTIVE_SELECTION="true"
|
||||
fi
|
||||
}
|
||||
|
||||
function choose_mirrors() {
|
||||
@@ -468,8 +473,8 @@ function choose_mirrors() {
|
||||
done
|
||||
else
|
||||
for ((i = 0; i < ${#list_arr[@]}; i++)); do
|
||||
tmp_mirror_name=$(echo "${list_arr[i]}" | awk -F '@' '{print$1}') # 软件源名称
|
||||
tmp_mirror_url=$(echo "${list_arr[i]}" | awk -F '@' '{print$2}') # 软件源地址
|
||||
tmp_mirror_name="${list_arr[i]%@*}" # 软件源名称
|
||||
tmp_mirror_url="${list_arr[i]#*@}" # 软件源地址
|
||||
arr_num=$((i + 1))
|
||||
echo -e " ❖ $arr_num. ${tmp_mirror_url} | ${tmp_mirror_name}"
|
||||
done
|
||||
@@ -491,74 +496,95 @@ function choose_mirrors() {
|
||||
print_title
|
||||
if [[ -z "${INSTALL_LATESTED_DOCKER}" ]]; then
|
||||
## 是否手动选择安装版本
|
||||
local CHOICE_A=$(echo -e "\n${BOLD}└─ 是否安装最新版本的 Docker Engine? [Y/n] ${PLAIN}")
|
||||
read -p "${CHOICE_A}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case $INPUT in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
INSTALL_LATESTED_DOCKER="true"
|
||||
;;
|
||||
[Nn] | [Nn][Oo])
|
||||
## 安装旧版本只有官方仓库有
|
||||
INSTALL_LATESTED_DOCKER="false"
|
||||
SOURCE="download.docker.com"
|
||||
;;
|
||||
*)
|
||||
INSTALL_LATESTED_DOCKER="true"
|
||||
echo -e "\n$WARN 输入错误,默认安装最新版本!"
|
||||
;;
|
||||
esac
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
echo ''
|
||||
interactive_select_boolean "${BOLD}是否安装最新版本的 Docker Engine?${PLAIN}"
|
||||
if [[ "${_SELECT_RESULT}" == "true" ]]; then
|
||||
INSTALL_LATESTED_DOCKER="true"
|
||||
else
|
||||
## 安装旧版本只有官方仓库有
|
||||
INSTALL_LATESTED_DOCKER="false"
|
||||
SOURCE="download.docker.com"
|
||||
fi
|
||||
else
|
||||
local CHOICE_A=$(echo -e "\n${BOLD}└─ 是否安装最新版本的 Docker Engine? [Y/n] ${PLAIN}")
|
||||
read -p "${CHOICE_A}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case $INPUT in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
INSTALL_LATESTED_DOCKER="true"
|
||||
;;
|
||||
[Nn] | [Nn][Oo])
|
||||
## 安装旧版本只有官方仓库有
|
||||
INSTALL_LATESTED_DOCKER="false"
|
||||
SOURCE="download.docker.com"
|
||||
;;
|
||||
*)
|
||||
INSTALL_LATESTED_DOCKER="true"
|
||||
echo -e "\n$WARN 输入错误,默认安装最新版本!"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
local mirror_list_name
|
||||
|
||||
if [[ -z "${SOURCE}" ]]; then
|
||||
local mirror_list_name="mirror_list_docker_ce"
|
||||
print_mirrors_list "${mirror_list_name}" 38
|
||||
local CHOICE_B=$(echo -e "\n${BOLD}└─ 请选择并输入你想使用的 Docker CE 源 [ 1-$(eval echo \${#$mirror_list_name[@]}) ]:${PLAIN}")
|
||||
while true; do
|
||||
read -p "${CHOICE_B}" INPUT
|
||||
case "${INPUT}" in
|
||||
[1-9] | [1-9][0-9] | [1-9][0-9][0-9])
|
||||
local tmp_source="$(eval echo \${${mirror_list_name}[$(($INPUT - 1))]})"
|
||||
if [[ -z "${tmp_source}" ]]; then
|
||||
echo -e "\n$WARN 请输入有效的数字序号!"
|
||||
else
|
||||
SOURCE="$(eval echo \${${mirror_list_name}[$(($INPUT - 1))]} | awk -F '@' '{print$2}')"
|
||||
# echo "${SOURCE}"
|
||||
# exit
|
||||
break
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 请输入数字序号以选择你想使用的软件源!"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
mirror_list_name="mirror_list_docker_ce"
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
eval "interactive_select_mirror \"\${${mirror_list_name}[@]}\" \"\\n \${BOLD}请选择你想使用的 Docker CE 源:\${PLAIN}\\n\""
|
||||
SOURCE="${_SELECT_RESULT#*@}"
|
||||
echo -e "\n ${GREEN}➜${PLAIN} ${BOLD}${_SELECT_RESULT%@*}${PLAIN}"
|
||||
else
|
||||
print_mirrors_list "${mirror_list_name}" 38
|
||||
local CHOICE_B=$(echo -e "\n${BOLD}└─ 请选择并输入你想使用的 Docker CE 源 [ 1-$(eval echo \${#$mirror_list_name[@]}) ]:${PLAIN}")
|
||||
while true; do
|
||||
read -p "${CHOICE_B}" INPUT
|
||||
case "${INPUT}" in
|
||||
[1-9] | [1-9][0-9] | [1-9][0-9][0-9])
|
||||
local tmp_source="$(eval echo \${${mirror_list_name}[$(($INPUT - 1))]})"
|
||||
if [[ -z "${tmp_source}" ]]; then
|
||||
echo -e "\n$WARN 请输入有效的数字序号!"
|
||||
else
|
||||
SOURCE="$(eval echo \${${mirror_list_name}[$(($INPUT - 1))]} | awk -F '@' '{print$2}')"
|
||||
break
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 请输入数字序号以选择你想使用的软件源!"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "${SOURCE_REGISTRY}" ]]; then
|
||||
mirror_list_name="mirror_list_registry"
|
||||
print_mirrors_list "${mirror_list_name}" 44
|
||||
local CHOICE_C=$(echo -e "\n${BOLD}└─ 请选择并输入你想使用的 Docker Registry 源 [ 1-$(eval echo \${#$mirror_list_name[@]}) ]:${PLAIN}")
|
||||
while true; do
|
||||
read -p "${CHOICE_C}" INPUT
|
||||
case "${INPUT}" in
|
||||
[1-9] | [1-9][0-9] | [1-9][0-9][0-9])
|
||||
local tmp_source="$(eval echo \${${mirror_list_name}[$(($INPUT - 1))]})"
|
||||
if [[ -z "${tmp_source}" ]]; then
|
||||
echo -e "\n$WARN 请输入有效的数字序号!"
|
||||
else
|
||||
SOURCE_REGISTRY="$(eval echo \${${mirror_list_name}[$(($INPUT - 1))]} | awk -F '@' '{print$2}')"
|
||||
# echo "${SOURCE_REGISTRY}"
|
||||
# exit
|
||||
break
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 请输入数字序号以选择你想使用的软件源!"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
eval "interactive_select_mirror \"\${${mirror_list_name}[@]}\" \"\\n \${BOLD}请选择你想使用的 Docker Registry 源:\${PLAIN}\\n\""
|
||||
SOURCE_REGISTRY="${_SELECT_RESULT#*@}"
|
||||
echo -e "\n ${GREEN}➜${PLAIN} Docker Registry:${BOLD}${_SELECT_RESULT%@*}${PLAIN}"
|
||||
else
|
||||
print_mirrors_list "${mirror_list_name}" 44
|
||||
local CHOICE_C=$(echo -e "\n${BOLD}└─ 请选择并输入你想使用的 Docker Registry 源 [ 1-$(eval echo \${#$mirror_list_name[@]}) ]:${PLAIN}")
|
||||
while true; do
|
||||
read -p "${CHOICE_C}" INPUT
|
||||
case "${INPUT}" in
|
||||
[1-9] | [1-9][0-9] | [1-9][0-9][0-9])
|
||||
local tmp_source="$(eval echo \${${mirror_list_name}[$(($INPUT - 1))]})"
|
||||
if [[ -z "${tmp_source}" ]]; then
|
||||
echo -e "\n$WARN 请输入有效的数字序号!"
|
||||
else
|
||||
SOURCE_REGISTRY="$(eval echo \${${mirror_list_name}[$(($INPUT - 1))]} | awk -F '@' '{print$2}')"
|
||||
break
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo -e "\n$WARN 请输入数字序号以选择你想使用的软件源!"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -569,19 +595,26 @@ function close_firewall_service() {
|
||||
fi
|
||||
if [[ "$(systemctl is-active firewalld)" == "active" ]]; then
|
||||
if [[ -z "${CLOSE_FIREWALL}" ]]; then
|
||||
local CHOICE
|
||||
CHOICE=$(echo -e "\n${BOLD}└─ 是否关闭防火墙和 SELinux ? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
CLOSE_FIREWALL="true"
|
||||
;;
|
||||
[Nn] | [Nn][Oo]) ;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不关闭!"
|
||||
;;
|
||||
esac
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
echo ''
|
||||
interactive_select_boolean "${BOLD}是否关闭防火墙和 SELinux ?${PLAIN}"
|
||||
if [[ "${_SELECT_RESULT}" == "true" ]]; then
|
||||
CLOSE_FIREWALL="true"
|
||||
fi
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 是否关闭防火墙和 SELinux ? [Y/n] ${PLAIN}")
|
||||
read -rp "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case "${INPUT}" in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
CLOSE_FIREWALL="true"
|
||||
;;
|
||||
[Nn] | [Nn][Oo]) ;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不关闭!"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
if [[ "${CLOSE_FIREWALL}" == "true" ]]; then
|
||||
local SelinuxConfig=/etc/selinux/config
|
||||
@@ -600,7 +633,7 @@ function install_dependency_packages() {
|
||||
sed -i '/docker-ce/d' $File_DebianSourceList
|
||||
rm -rf $Dir_DebianExtendSource/docker.list
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
rm -rf $Dir_YumRepos/*docker*.repo
|
||||
;;
|
||||
esac
|
||||
@@ -610,7 +643,7 @@ function install_dependency_packages() {
|
||||
package_manager="apt-get"
|
||||
$package_manager update
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
package_manager="$(get_package_manager)"
|
||||
$package_manager makecache
|
||||
;;
|
||||
@@ -649,7 +682,7 @@ function get_package_manager() {
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"${SYSTEM_FEDORA}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_FEDORA}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
command="dnf"
|
||||
;;
|
||||
esac
|
||||
@@ -674,7 +707,7 @@ function uninstall_original_version() {
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
case "${SYSTEM_JUDGMENT}" in
|
||||
"${SYSTEM_FEDORA}" | "${SYSTEM_RHEL}")
|
||||
package_list="docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine podman runc"
|
||||
@@ -691,7 +724,7 @@ function uninstall_original_version() {
|
||||
apt-get remove -y $package_list >/dev/null 2>&1
|
||||
apt-get autoremove -y >/dev/null 2>&1
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
local package_manager="$(get_package_manager)"
|
||||
$package_manager remove -y $package_list >/dev/null 2>&1
|
||||
$package_manager autoremove -y >/dev/null 2>&1
|
||||
@@ -717,7 +750,7 @@ function configure_docker_ce_mirror() {
|
||||
echo "deb [arch=${SOURCE_ARCH} signed-by=${file_keyring}] https://${SOURCE}/linux/${SOURCE_BRANCH} ${SYSTEM_VERSION_CODENAME} stable" | tee $Dir_DebianExtendSource/docker.list >/dev/null 2>&1
|
||||
apt-get update
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
yum-config-manager -y --add-repo https://${SOURCE}/linux/${SOURCE_BRANCH}/docker-ce.repo
|
||||
sed -i "s|download.docker.com|${SOURCE}|g" $Dir_YumRepos/docker-ce.repo
|
||||
## 兼容处理版本号
|
||||
@@ -749,7 +782,7 @@ function install_docker_engine() {
|
||||
apt-cache madison docker-ce-cli | awk '{print $3}' | grep -Eo "[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}" >$DockerCECLIVersionFile
|
||||
grep -wf $DockerCEVersionFile $DockerCECLIVersionFile >$DockerVersionFile
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
yum list docker-ce --showduplicates | sort -r | awk '{print $2}' | grep -Eo "[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}" >$DockerCEVersionFile
|
||||
yum list docker-ce-cli --showduplicates | sort -r | awk '{print $2}' | grep -Eo "[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}" >$DockerCECLIVersionFile
|
||||
grep -wf $DockerCEVersionFile $DockerCECLIVersionFile >$DockerVersionFile
|
||||
@@ -765,7 +798,7 @@ function install_docker_engine() {
|
||||
"${SYSTEM_DEBIAN}")
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
local package_manager="$(get_package_manager)"
|
||||
$package_manager install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
;;
|
||||
@@ -810,7 +843,7 @@ function install_docker_engine() {
|
||||
esac
|
||||
apt-get install -y docker-ce=${INSTALL_JUDGMENT}${DOCKER_VERSION}* docker-ce-cli=5:${DOCKER_VERSION}* containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
local package_manager="$(get_package_manager)"
|
||||
$package_manager install -y docker-ce-${DOCKER_VERSION} docker-ce-cli-${DOCKER_VERSION} containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
;;
|
||||
@@ -820,10 +853,20 @@ function install_docker_engine() {
|
||||
|
||||
## 修改 Docker Registry 镜像仓库源
|
||||
function change_docker_registry_mirror() {
|
||||
if [[ "${REGISTRY_SOURCEL}" != "registry.hub.docker.com" ]]; then
|
||||
if [ -d $DockerDir ] && [ -e $DockerConfig ]; then
|
||||
if [ -e $DockerConfigBackup ]; then
|
||||
if [[ "${IGNORE_BACKUP_TIPS}" == "false" ]]; then
|
||||
if [[ "${REGISTRY_SOURCEL}" == "registry.hub.docker.com" ]]; then
|
||||
return
|
||||
fi
|
||||
if [ -d $DockerDir ] && [ -e $DockerConfig ]; then
|
||||
if [ -e $DockerConfigBackup ]; then
|
||||
if [[ "${IGNORE_BACKUP_TIPS}" == "false" ]]; then
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
echo ''
|
||||
interactive_select_boolean "${BOLD}检测到已备份的 Docker 配置文件,是否跳过覆盖备份?${PLAIN}"
|
||||
if [[ "${_SELECT_RESULT}" == "false" ]]; then
|
||||
echo ''
|
||||
cp -rvf $DockerConfig $DockerConfigBackup 2>&1
|
||||
fi
|
||||
else
|
||||
local CHOICE_BACKUP=$(echo -e "\n${BOLD}└─ 检测到已备份的 Docker 配置文件,是否跳过覆盖备份? [Y/n] ${PLAIN}")
|
||||
read -p "${CHOICE_BACKUP}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
@@ -838,22 +881,22 @@ function install_docker_engine() {
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else
|
||||
echo ''
|
||||
cp -rvf $DockerConfig $DockerConfigBackup 2>&1
|
||||
echo -e "\n$COMPLETE 已备份原有 Docker 配置文件至 $DockerConfigBackup"
|
||||
fi
|
||||
sleep 2s
|
||||
else
|
||||
mkdir -p $DockerDir >/dev/null 2>&1
|
||||
touch $DockerConfig
|
||||
fi
|
||||
echo -e '{\n "registry-mirrors": ["https://SOURCE"]\n}' >$DockerConfig
|
||||
sed -i "s|SOURCE|${SOURCE_REGISTRY}|g" $DockerConfig
|
||||
systemctl daemon-reload
|
||||
if [[ $(systemctl is-active docker) == "active" ]]; then
|
||||
systemctl restart docker
|
||||
echo ''
|
||||
cp -rvf $DockerConfig $DockerConfigBackup 2>&1
|
||||
echo -e "\n$COMPLETE 已备份原有 Docker 配置文件至 $DockerConfigBackup"
|
||||
fi
|
||||
sleep 2s
|
||||
else
|
||||
mkdir -p $DockerDir >/dev/null 2>&1
|
||||
touch $DockerConfig
|
||||
fi
|
||||
echo -e '{\n "registry-mirrors": ["https://SOURCE"]\n}' >$DockerConfig
|
||||
sed -i "s|SOURCE|${SOURCE_REGISTRY}|g" $DockerConfig
|
||||
systemctl daemon-reload
|
||||
if [[ $(systemctl is-active docker) == "active" ]]; then
|
||||
systemctl restart docker
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -862,7 +905,7 @@ function install_docker_engine() {
|
||||
"${SYSTEM_DEBIAN}")
|
||||
dpkg -l | grep docker-ce-cli -q
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
rpm -qa | grep docker-ce-cli -q
|
||||
;;
|
||||
esac
|
||||
@@ -870,38 +913,68 @@ function install_docker_engine() {
|
||||
export_version_list
|
||||
DOCKER_INSTALLED_VERSION="$(docker -v | grep -Eo "[0-9][0-9]\.[0-9]{1,2}\.[0-9]{1,2}")"
|
||||
DOCKER_VERSION_LATEST="$(cat $DockerVersionFile | head -n 1)"
|
||||
if [[ "${DOCKER_INSTALLED_VERSION}" == "${DOCKER_VERSION_LATEST}" ]]; then
|
||||
if [[ "${INSTALL_LATESTED_DOCKER}" == "true" ]]; then
|
||||
echo -e "\n$COMPLETE 检测到已安装 Docker Engine 最新版本,跳过安装"
|
||||
rm -rf $DockerVersionFile
|
||||
change_docker_registry_mirror
|
||||
systemctl enable --now docker >/dev/null 2>&1
|
||||
check_version
|
||||
run_end
|
||||
exit
|
||||
if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then
|
||||
if [[ "${DOCKER_INSTALLED_VERSION}" == "${DOCKER_VERSION_LATEST}" ]]; then
|
||||
if [[ "${INSTALL_LATESTED_DOCKER}" == "true" ]]; then
|
||||
echo -e "\n$COMPLETE 检测到已安装 Docker Engine 最新版本,跳过安装"
|
||||
rm -rf $DockerVersionFile
|
||||
change_docker_registry_mirror
|
||||
systemctl enable --now docker >/dev/null 2>&1
|
||||
check_version
|
||||
run_end
|
||||
exit
|
||||
else
|
||||
echo ''
|
||||
interactive_select_boolean "${BOLD}检测到已安装 Docker Engine 最新版本,是否继续安装其它版本?${PLAIN}"
|
||||
fi
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 检测到已安装 Docker Engine 最新版本,是否继续安装其它版本? [Y/n] ${PLAIN}")
|
||||
echo ''
|
||||
if [[ "${INSTALL_LATESTED_DOCKER}" == "true" ]]; then
|
||||
interactive_select_boolean "${BOLD}检测到已安装 Docker Engine 旧版本,是否覆盖安装为最新版本?${PLAIN}"
|
||||
else
|
||||
interactive_select_boolean "${BOLD}检测到已安装 Docker Engine 旧版本,是否继续安装其它版本?${PLAIN}"
|
||||
fi
|
||||
fi
|
||||
if [[ "${_SELECT_RESULT}" == "true" ]]; then
|
||||
uninstall_original_version
|
||||
install_main
|
||||
[ $? -ne 0 ] && output_error "安装 Docker Engine 失败"
|
||||
fi
|
||||
else
|
||||
if [[ "${INSTALL_LATESTED_DOCKER}" == "true" ]]; then
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 检测到已安装 Docker Engine 旧版本,是否覆盖安装为最新版本? [Y/n] ${PLAIN}")
|
||||
if [[ "${DOCKER_INSTALLED_VERSION}" == "${DOCKER_VERSION_LATEST}" ]]; then
|
||||
if [[ "${INSTALL_LATESTED_DOCKER}" == "true" ]]; then
|
||||
echo -e "\n$COMPLETE 检测到已安装 Docker Engine 最新版本,跳过安装"
|
||||
rm -rf $DockerVersionFile
|
||||
change_docker_registry_mirror
|
||||
systemctl enable --now docker >/dev/null 2>&1
|
||||
check_version
|
||||
run_end
|
||||
exit
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 检测到已安装 Docker Engine 最新版本,是否继续安装其它版本? [Y/n] ${PLAIN}")
|
||||
fi
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 检测到已安装 Docker Engine 旧版本,是否继续安装其它版本? [Y/n] ${PLAIN}")
|
||||
if [[ "${INSTALL_LATESTED_DOCKER}" == "true" ]]; then
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 检测到已安装 Docker Engine 旧版本,是否覆盖安装为最新版本? [Y/n] ${PLAIN}")
|
||||
else
|
||||
local CHOICE=$(echo -e "\n${BOLD}└─ 检测到已安装 Docker Engine 旧版本,是否继续安装其它版本? [Y/n] ${PLAIN}")
|
||||
fi
|
||||
fi
|
||||
read -p "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case $INPUT in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
uninstall_original_version
|
||||
install_main
|
||||
[ $? -ne 0 ] && output_error "安装 Docker Engine 失败"
|
||||
;;
|
||||
[Nn] | [Nn][Oo]) ;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不覆盖安装!\n"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
read -p "${CHOICE}" INPUT
|
||||
[[ -z "${INPUT}" ]] && INPUT=Y
|
||||
case $INPUT in
|
||||
[Yy] | [Yy][Ee][Ss])
|
||||
uninstall_original_version
|
||||
install_main
|
||||
[ $? -ne 0 ] && output_error "安装 Docker Engine 失败"
|
||||
;;
|
||||
[Nn] | [Nn][Oo]) ;;
|
||||
*)
|
||||
echo -e "\n$WARN 输入错误,默认不覆盖安装!\n"
|
||||
;;
|
||||
esac
|
||||
|
||||
rm -rf $DockerVersionFile
|
||||
else
|
||||
uninstall_original_version
|
||||
@@ -927,7 +1000,7 @@ function check_version() {
|
||||
echo -e "\n检查源文件:cat $Dir_DebianExtendSource/docker.list"
|
||||
echo -e '请尝试手动执行安装命令:apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n'
|
||||
;;
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_ANOLISOS}")
|
||||
"${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}")
|
||||
local package_manager="$(get_package_manager)"
|
||||
echo -e "\n检查源文件:cat $Dir_YumRepos/docker.repo"
|
||||
echo -e "请尝试手动执行安装命令:$package_manager install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n"
|
||||
@@ -951,5 +1024,170 @@ function check_version() {
|
||||
fi
|
||||
}
|
||||
|
||||
function interactive_select_mirror() {
|
||||
_SELECT_RESULT=""
|
||||
local options=("$@")
|
||||
local message="${options[${#options[@]} - 1]}"
|
||||
unset options[${#options[@]}-1]
|
||||
local selected=0
|
||||
local start=0
|
||||
local page_size=$(($(tput lines) - 3)) # 减去1行用于显示提示信息
|
||||
function clear_menu() {
|
||||
tput rc
|
||||
for ((i = 0; i < ${#options[@]} + 1; i++)); do
|
||||
echo -e "\r\033[K"
|
||||
done
|
||||
tput rc
|
||||
}
|
||||
function cleanup() {
|
||||
clear_menu
|
||||
tput rc
|
||||
tput cnorm
|
||||
tput rmcup
|
||||
exit
|
||||
}
|
||||
function draw_menu() {
|
||||
tput clear
|
||||
tput cup 0 0
|
||||
echo -e "${message}"
|
||||
local end=$((start + page_size - 1))
|
||||
if [ $end -ge ${#options[@]} ]; then
|
||||
end=${#options[@]}-1
|
||||
fi
|
||||
for ((i = start; i <= end; i++)); do
|
||||
if [ "$i" -eq "$selected" ]; then
|
||||
echo -e "\e[34;4m➤ ${options[$i]%@*}\e[0m"
|
||||
else
|
||||
echo -e " ${options[$i]%@*}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
function read_key() {
|
||||
IFS= read -rsn1 key
|
||||
if [[ $key == $'\x1b' ]]; then
|
||||
IFS= read -rsn2 key
|
||||
key="$key"
|
||||
fi
|
||||
echo "$key"
|
||||
}
|
||||
tput smcup # 保存当前屏幕并切换到新屏幕
|
||||
tput sc # 保存光标位置
|
||||
tput civis # 隐藏光标
|
||||
trap "cleanup" INT TERM # 捕捉脚本结束时恢复光标
|
||||
draw_menu # 初始化菜单位置
|
||||
# 处理选择
|
||||
while true; do
|
||||
key=$(read_key)
|
||||
case "$key" in
|
||||
"[A")
|
||||
# 上箭头
|
||||
if [ "$selected" -gt 0 ]; then
|
||||
selected=$((selected - 1))
|
||||
if [ "$selected" -lt "$start" ]; then
|
||||
start=$((start - 1))
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
"[B")
|
||||
# 下箭头
|
||||
if [ "$selected" -lt $((${#options[@]} - 1)) ]; then
|
||||
selected=$((selected + 1))
|
||||
if [ "$selected" -ge $((start + page_size)) ]; then
|
||||
start=$((start + 1))
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
"")
|
||||
# Enter 键
|
||||
tput rmcup
|
||||
break
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
draw_menu
|
||||
done
|
||||
# clear_menu # 清除菜单
|
||||
tput cnorm # 恢复光标
|
||||
tput rmcup # 恢复之前的屏幕
|
||||
# tput rc # 恢复光标位置
|
||||
# 处理结果
|
||||
_SELECT_RESULT="${options[$selected]}"
|
||||
}
|
||||
|
||||
function interactive_select_boolean() {
|
||||
_SELECT_RESULT=""
|
||||
local selected=0
|
||||
local message="$1"
|
||||
function clear_menu() {
|
||||
tput rc
|
||||
for ((i = 0; i < 2 + 2; i++)); do
|
||||
echo -e "\r\033[K"
|
||||
done
|
||||
tput rc
|
||||
}
|
||||
function cleanup() {
|
||||
clear_menu
|
||||
tput rc
|
||||
tput cnorm
|
||||
tput rmcup
|
||||
exit
|
||||
}
|
||||
function draw_menu() {
|
||||
tput rc
|
||||
echo -e "╭─ ${message}"
|
||||
echo -e "│"
|
||||
if [ "$selected" -eq 0 ]; then
|
||||
echo -e "╰─ \033[32m●\033[0m 是\033[2m / ○ 否\033[0m"
|
||||
else
|
||||
echo -e "╰─ \033[2m○ 是 / \033[0m\033[32m●\033[0m 否"
|
||||
fi
|
||||
}
|
||||
function read_key() {
|
||||
IFS= read -rsn1 key
|
||||
if [[ $key == $'\x1b' ]]; then
|
||||
IFS= read -rsn2 key
|
||||
key="$key"
|
||||
fi
|
||||
echo "$key"
|
||||
}
|
||||
tput sc # 保存光标位置
|
||||
tput civis # 隐藏光标
|
||||
trap "cleanup" INT TERM # 捕捉脚本结束时恢复光标
|
||||
draw_menu # 初始化菜单位置
|
||||
# 处理选择
|
||||
while true; do
|
||||
key=$(read_key)
|
||||
case "$key" in
|
||||
"[D")
|
||||
# 左箭头
|
||||
if [ "$selected" -gt 0 ]; then
|
||||
selected=$((selected - 1))
|
||||
fi
|
||||
;;
|
||||
"[C")
|
||||
# 右箭头
|
||||
if [ "$selected" -lt 1 ]; then
|
||||
selected=$((selected + 1))
|
||||
fi
|
||||
;;
|
||||
"")
|
||||
# Enter 键
|
||||
break
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
draw_menu
|
||||
done
|
||||
# clear_menu # 清除菜单
|
||||
tput cnorm # 恢复光标
|
||||
# tput rc # 恢复光标位置
|
||||
# 处理结果
|
||||
if [ "$selected" -eq 0 ]; then
|
||||
_SELECT_RESULT="true"
|
||||
else
|
||||
_SELECT_RESULT="false"
|
||||
fi
|
||||
}
|
||||
|
||||
handle_command_options "$@"
|
||||
main
|
||||
|
||||
@@ -70,14 +70,14 @@
|
||||
<td><a href="https://almalinux.org/zh-hans" target="_blank"><img src="./docs/assets/images/icon/almalinux.svg" width="16" height="16" style="vertical-align: -0.25em"></a> AlmaLinux</td>
|
||||
<td align="center">8 ~ 9</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.opencloudos.org" target="_blank"><img src="./docs/assets/images/icon/opencloudos.png" width="16" height="16" style="vertical-align: -0.25em"></a> OpenCloudOS(鸥栖)</td>
|
||||
<td align="center">8.6 ~ 9 / Stream 23</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.openeuler.org/zh" target="_blank"><img src="./docs/assets/images/icon/openeuler.ico" width="16" height="16" style="vertical-align: -0.2em"></a> openEuler(开源欧拉)</td>
|
||||
<td align="center">21 ~ 24</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.opencloudos.org" target="_blank"><img src="./docs/assets/images/icon/opencloudos.png" width="16" height="16" style="vertical-align: -0.25em"></a> OpenCloudOS(鸥栖)</td>
|
||||
<td align="center">8.6 ~ 9 / Stream 23</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.openkylin.top" target="_blank"><img src="./docs/assets/images/icon/openkylin.ico" width="16" height="16" style="vertical-align: -0.25em"></a> openKylin(开放麒麟)</td>
|
||||
<td align="center">all</td>
|
||||
|
||||
@@ -88,8 +88,8 @@ hide:
|
||||
| <a href="https://www.centos.org" target="_blank"><img src="/assets/images/icon/centos.svg" width="16" height="16" style="vertical-align: -0.1em"></a> CentOS | _7 ~ 8 / Stream 8 ~ 9_ |
|
||||
| <a href="https://rockylinux.org" target="_blank"><img src="/assets/images/icon/rocky-linux.svg" width="16" height="16" style="vertical-align: -0.25em"></a> Rocky Linux | _8 ~ 9_ |
|
||||
| <a href="https://almalinux.org/zh-hans" target="_blank"><img src="/assets/images/icon/almalinux.svg" width="16" height="16" style="vertical-align: -0.15em"></a> AlmaLinux | _8 ~ 9_ |
|
||||
| <a href="https://www.opencloudos.org" target="_blank"><img src="/assets/images/icon/opencloudos.png" width="16" height="16" style="vertical-align: -0.25em"></a> OpenCloudOS(鸥栖) | _8.6 ~ 9 / Stream 23_ |
|
||||
| <a href="https://www.openeuler.org/zh" target="_blank"><img src="/assets/images/icon/openeuler.ico" width="16" height="16" style="vertical-align: -0.2em"></a> openEuler(开源欧拉) | _21 ~ 24_ |
|
||||
| <a href="https://www.opencloudos.org" target="_blank"><img src="/assets/images/icon/opencloudos.png" width="16" height="16" style="vertical-align: -0.25em"></a> OpenCloudOS(鸥栖) | _8.6 ~ 9 / Stream 23_ |
|
||||
| <a href="https://www.openkylin.top" target="_blank"><img src="/assets/images/icon/openkylin.ico" width="16" height="16" style="vertical-align: -0.25em"></a> openKylin(开放麒麟) | _all_ |
|
||||
| <a href="https://openanolis.cn" target="_blank"><img src="/assets/images/icon/anolis.png" width="16" height="16" style="vertical-align: -0.1em"></a> Anolis OS(龙蜥) | _8 / 23_ |
|
||||
| <a href="https://www.opensuse.org" target="_blank"><img src="/assets/images/icon/opensuse.svg" width="16" height="16"></a> openSUSE | _Leep 15 / Tumbleweed_ |
|
||||
|
||||
@@ -18,7 +18,7 @@ hide:
|
||||
| [网易](https://mirrors.163.com "mirrors.163.com") | :unsupport: | :supported: | :unsupport: | :supported: | :supported: | :unsupport: | :unsupport: | :supported: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :supported: | :supported: | :unsupport: | :supported: |
|
||||
| [火山引擎](https://developer.volcengine.com/mirror "mirrors.volces.com") | :unsupport: | :unsupport: | :supported: | :supported: | :incompatible: | :supported: | :supported: | :supported: | :unsupport: | :supported: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: |
|
||||
| [清华大学](https://mirrors.tuna.tsinghua.edu.cn "mirrors.tuna.tsinghua.edu.cn") | :supported: | :supported: | :supported: | :supported: | :unsupport: | :unsupport: | :supported: | :supported: | :unsupport: | :supported: | :supported: | :supported: | :supported: | :supported: | :unsupport: | :unsupport: |
|
||||
| [北京大学](https://mirrors.pku.edu.cn/Mirrors "mirrors.pku.edu.cn") | :supported: | :supported: | :unsupport: | :unsupport: | :supported: | :unsupport: | :supported: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: |
|
||||
| [北京大学](https://mirrors.pku.edu.cn/Mirrors "mirrors.pku.edu.cn") | :supported: | :supported: | :unsupport: | :unsupport: | :supported: | :supported: | :supported: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: | :unsupport: |
|
||||
| [浙江大学](https://mirrors.zju.edu.cn "mirrors.zju.edu.cn") | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :unsupport: | :supported: | :unsupport: | :unsupport: | :supported: | :supported: | :supported: | :unsupport: |
|
||||
| [南京大学](https://mirrors.nju.edu.cn "mirrors.nju.edu.cn") | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: |
|
||||
| [兰州大学](https://mirror.lzu.edu.cn "mirror.lzu.edu.cn") | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :supported: | :unsupport: | :supported: | :unsupport: | :unsupport: | :supported: | :supported: | :unsupport: | :supported: |
|
||||
|
||||
@@ -35,11 +35,11 @@ hide:
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://zorin.com/os" target="_blank"><img src="/assets/images/icon/zorin-os.png" width="16" height="16" style="vertical-align: -0.3em"></a> Zorin OS</td>
|
||||
<td><a href="https://www.opencloudos.org" target="_blank"><img src="/assets/images/icon/opencloudos.png" width="16" height="16" style="vertical-align: -0.25em"></a> OpenCloudOS(鸥栖)</td>
|
||||
<td><a href="https://www.openeuler.org/zh" target="_blank"><img src="/assets/images/icon/openeuler.ico" width="16" height="16" style="vertical-align: -0.2em"></a> openEuler(开源欧拉)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.armbian.com" target="_blank"><img src="/assets/images/icon/armbian.png" width="16" height="16" style="vertical-align: -0.2em"></a> Armbian</td>
|
||||
<td><a href="https://www.openeuler.org/zh" target="_blank"><img src="/assets/images/icon/openeuler.ico" width="16" height="16" style="vertical-align: -0.2em"></a> openEuler(开源欧拉)</td>
|
||||
<td><a href="https://www.opencloudos.org" target="_blank"><img src="/assets/images/icon/opencloudos.png" width="16" height="16" style="vertical-align: -0.25em"></a> OpenCloudOS(鸥栖)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.proxmox.com" target="_blank"><img src="/assets/images/icon/proxmox.svg" width="16" height="16" style="vertical-align: -0.2em"></a> Proxmox</td>
|
||||
|
||||
@@ -344,8 +344,8 @@ hide:
|
||||
| <a href="https://www.centos.org" target="_blank"><img src="/assets/images/icon/centos.svg" width="16" height="16" style="vertical-align: -0.1em"></a> CentOS | centos / centos-stream / centos-altarch / centos-vault |
|
||||
| <a href="https://rockylinux.org" target="_blank"><img src="/assets/images/icon/rocky-linux.svg" width="16" height="16" style="vertical-align: -0.25em"></a> Rocky Linux | rocky |
|
||||
| <a href="https://almalinux.org/zh-hans" target="_blank"><img src="/assets/images/icon/almalinux.svg" width="16" height="16" style="vertical-align: -0.15em"></a> AlmaLinux | almalinux / almalinux-vault |
|
||||
| <a href="https://www.opencloudos.org" target="_blank"><img src="/assets/images/icon/opencloudos.png" width="16" height="16" style="vertical-align: -0.25em"></a> OpenCloudOS(鸥栖) | opencloudos |
|
||||
| <a href="https://www.openeuler.org/zh" target="_blank"><img src="/assets/images/icon/openeuler.ico" width="16" height="16" style="vertical-align: -0.2em"></a> openEuler(开源欧拉) | openeuler |
|
||||
| <a href="https://www.opencloudos.org" target="_blank"><img src="/assets/images/icon/opencloudos.png" width="16" height="16" style="vertical-align: -0.25em"></a> OpenCloudOS(鸥栖) | opencloudos |
|
||||
| <a href="https://www.openkylin.top" target="_blank"><img src="/assets/images/icon/openkylin.ico" width="16" height="16" style="vertical-align: -0.25em"></a> openKylin(开放麒麟) | openkylin |
|
||||
| <a href="https://openanolis.cn" target="_blank"><img src="/assets/images/icon/anolis.png" width="16" height="16" style="vertical-align: -0.1em"></a> Anolis OS(龙蜥) | anolis |
|
||||
| <a href="https://www.opensuse.org" target="_blank"><img src="/assets/images/icon/opensuse.svg" width="16" height="16"></a> openSUSE | opensuse |
|
||||
|
||||
Reference in New Issue
Block a user