commit 192078dc3b6d9b0016f7a2f1e3cd600d2761aa5d Author: root Date: Tue Feb 17 17:28:37 2026 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7503322 --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +# Node/React +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +build/ +dist/ +coverage/ +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Go +*.exe +*.exe~ +*.test +*.out +*.dll +*.so +*.dylib +vendor/ + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +env/ +venv/ +ENV/ +*.egg-info/ +dist/ +build/ + +# 数据文件 +data/data.json +*.db +*.sqlite + +# 日志文件 +*.log +logs/ + +# 操作系统 +.DS_Store +Thumbs.db +desktop.ini + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ +.project +.classpath +.settings/ + +# 其他 +*.bak +*.tmp +*.temp diff --git a/change-mirror/ChangeMirrors.sh b/change-mirror/ChangeMirrors.sh new file mode 100644 index 0000000..25e0439 --- /dev/null +++ b/change-mirror/ChangeMirrors.sh @@ -0,0 +1,8614 @@ +#!/bin/bash +## Author: SuperManito +## Modified: 2025-12-11 +## License: MIT +## GitHub: https://github.com/SuperManito/LinuxMirrors +## Website: https://linuxmirrors.cn + +## 定制方法 +# 只需要在头部(此处)定义全局变量即可,具体详见官网文档,简单写几个例子 +# SOURCE="www.example.com" # 指定软件源地址 +# BRANCH="branch" # 指定软件源仓库 +# WEB_PROTOCOL="https" # 指定 Web 协议 + +## 软件源列表 +# 中国大陆默认 +mirror_list_default=( + "mirrors.aliyun.com" + "mirrors.tencent.com" + "mirrors.huaweicloud.com" + "mirrors.cmecloud.cn" + "mirrors.ctyun.cn" + "mirrors.163.com" + "mirrors.volces.com" + "mirrors.tuna.tsinghua.edu.cn" + "mirrors.pku.edu.cn" + "mirrors.zju.edu.cn" + "mirrors.nju.edu.cn" + "mirror.lzu.edu.cn" + "mirror.sjtu.edu.cn" + "mirrors.cqupt.edu.cn" + "mirrors.ustc.edu.cn" + "mirror.iscas.ac.cn" + "__OFFICIAL_SOURCE_TAG__" +) +# 中国大陆教育网 +mirror_list_edu=( + "mirrors.pku.edu.cn" + "mirror.bjtu.edu.cn" + "mirrors.bfsu.edu.cn" + "mirrors.bupt.edu.cn" + "mirrors.cqu.edu.cn" + "mirrors.cqupt.edu.cn" + "mirrors.neusoft.edu.cn" + "mirrors.uestc.cn" + "mirrors.scau.edu.cn" + "mirrors.hust.edu.cn" + "mirrors.jlu.edu.cn" + "mirrors.jcut.edu.cn" + "mirrors.jxust.edu.cn" + "mirror.lzu.edu.cn" + "mirrors.nju.edu.cn" + "mirrors.njtech.edu.cn" + "mirrors.njupt.edu.cn" + "mirrors.sustech.edu.cn" + "mirror.nyist.edu.cn" + "mirrors.qlu.edu.cn" + "mirrors.tuna.tsinghua.edu.cn" + "mirrors.sdu.edu.cn" + "mirrors.shanghaitech.edu.cn" + "mirror.sjtu.edu.cn" + "mirrors.sjtug.sjtu.edu.cn" + "mirrors.wsyu.edu.cn" + "mirrors.xjtu.edu.cn" + "mirrors.nwafu.edu.cn" + "mirrors.zju.edu.cn" + "mirrors.ustc.edu.cn" + "__OFFICIAL_SOURCE_TAG__" +) +# 境外以及海外地区 +mirror_list_abroad=( + "mirrors.xtom.hk" + "mirror.01link.hk" + "download.nus.edu.sg/mirror" + "mirror.sg.gs" + "mirrors.xtom.sg" + "free.nchc.org.tw" + "mirror.ossplanet.net" + "linux.cs.nctu.edu.tw" + "ftp.tku.edu.tw" + "mirror.twds.com.tw" + "mirror.anigil.com" + "ftp.udx.icscoe.jp/Linux" + "ftp.jaist.ac.jp/pub/Linux" + "linux2.yz.yamagata-u.ac.jp/pub/Linux" + "mirrors.xtom.jp" + "mirrors.gbnetwork.com" + "mirror.kku.ac.th" + "mirror.vorboss.net" + "mirror.quickhost.uk" + "mirror.dogado.de" + "mirrors.xtom.de" + "ftp.halifax.rwth-aachen.de" + "ftp.agdsn.de" + "mirror.in2p3.fr/pub/linux" + "mirrors.ircam.fr/pub" + "eclats.crans.org" + "ftp.crihan.fr" + "mirrors.xtom.nl" + "mirror.datapacket.com" + "eu.edge.kernel.org" + "mirrors.xtom.ee" + "mirror.netsite.dk" + "mirrors.dotsrc.org" + "mirror.accum.se" + "ftp.lysator.liu.se" + "mirror.yandex.ru" + "mirror.linux-ia64.org" + "mirror.truenetwork.ru" + "ftp.belnet.be/mirror" + "ftp.cc.uoc.gr/mirrors/linux" + "ftp.fi.muni.cz/pub/linux" + "ftp.sh.cvut.cz" + "mirror.karneval.cz/pub/linux" + "mirrors.nic.cz" + "mirror.ethz.ch" + "mirrors.kernel.org" + "mirrors.mit.edu" + "mirror.math.princeton.edu/pub" + "ftp-chi.osuosl.org/pub" + "mirror.fcix.net" + "mirrors.xtom.com" + "mirror.steadfast.net" + "mirror.it.ubc.ca" + "mirror.xenyth.net" + "mirrors.switch.ca" + "mirror.pop-sc.rnp.br/mirror" + "mirror.uepg.br" + "mirror.ufscar.br" + "mirrors.eze.sysarmy.com" + "gsl-syd.mm.fcix.net" + "mirror.aarnet.edu.au/pub" + "mirror.datamossa.io" + "mirror.amaze.com.au" + "mirrors.xtom.au" + "mirror.overthewire.com.au" + "mirror.fsmg.org.nz" + "mirror.liquidtelecom.com" + "mirror.dimensiondata.com" + "__OFFICIAL_SOURCE_TAG__" +) + +## 配置需要区分公网地址和内网地址的软件源(不分地域) +# 需要同时在两个数组变量中分别定义软件源地址,并且保证排列顺序一致 +# 软件源公网地址列表 +mirror_list_extranet=( + "mirrors.aliyun.com" + "mirrors.tencent.com" + "mirrors.huaweicloud.com" + "mirrors.ctyun.cn" + "mirrors.volces.com" +) +# 软件源内网地址列表 +mirror_list_intranet=( + "mirrors.cloud.aliyuncs.com" + "mirrors.tencentyun.com" + "mirrors.myhuaweicloud.com" + "internal.mirrors.ctyun.cn" + "mirrors.ivolces.com" +) + +## 赞助商广告 +SPONSOR_ADS=( + "1Panel · Linux 面板|极简运维 ➜ \033[3mhttps://1panel.cn\033[0m" + "多途云 · 智能化防护,每一次连接皆在安全之下 ➜ \033[3mhttps://www.duotuyun.com\033[0m" + "毫秒镜像 · 专为中国开发者提供Docker镜像加速下载服务 ➜ \033[3mhttps://1ms.run\033[0m" + "林枫云 · 专注独立IP高频VPS|R9/i9系列定制 ➜ \033[3mhttps://www.dkdun.cn\033[0m" + "不死鸟CDN · 香港日本高防CDN,免实名/免备案,轻松阻断DDOS/CC攻击 ➜ \033[3mhttps://www.bsncdn.org\033[0m" + "青叶云 · 香港1T高防|自助防火墙,无视CC|大带宽回国优化线路 ➜ \033[3mhttps://www.qingyeyun.com\033[0m" + "莱卡云 · 专业云计算服务器提供商 ➜ \033[3m https://www.lcayun.com\033[0m" + "云悠YUNYOO · 全球高性价比云服务器|低至15.99元起 ➜ \033[3mhttps://yunyoo.cc\033[0m" + "HKGserver · 全球家宽|双ISP|住宅原生云服务器54元/月起 ➜ \033[3mhttps://www.hkgserver.com\033[0m" + "速拓云 · 国内高防云28元/月|香港云100M优化线路9元/月 ➜ \033[3mhttps://www.sutuoyun.com\033[0m" + "语鹿云盾 · 专业CDN加速、防御,亚太百兆三网优化CDN低至9元起 ➜ \033[3mhttps://www.lucdn.cn\033[0m" + "不二云 · 国内外建站快响应服务器的不二之选 ➜ \033[3mhttps://cb2.cn\033[0m" + "CN2network · 超低价优质机器免实名自动开通 ➜ \033[3mhttps://idc.cn2network.com\033[0m" + "破碎工坊云 · 专注高性能国内外云服务器 ➜ \033[3mhttps://www.crash.work\033[0m" + "润信云 · 国内挂机宝海外云服务器低至9.9元/月 ➜ \033[3mhttps://www.runxinyun.com\033[0m" + "浪浪云 · BGP网络让每一次连接都纵享丝滑,明码标价、无套路续费 ➜ \033[3mhttps://langlangy.cn\033[0m" +) + +############################################################################## + +## 定义系统判定变量 +SYSTEM_DEBIAN="Debian" +SYSTEM_UBUNTU="Ubuntu" +SYSTEM_KALI="Kali" +SYSTEM_DEEPIN="Deepin" +SYSTEM_LINUX_MINT="Linuxmint" +SYSTEM_ZORIN="Zorin" +SYSTEM_RASPBERRY_PI_OS="Raspberry Pi OS" +SYSTEM_REDHAT="RedHat" +SYSTEM_RHEL="Red Hat Enterprise Linux" +SYSTEM_CENTOS="CentOS" +SYSTEM_CENTOS_STREAM="CentOS Stream" +SYSTEM_ROCKY="Rocky" +SYSTEM_ALMALINUX="AlmaLinux" +SYSTEM_FEDORA="Fedora" +SYSTEM_ORACLE="Oracle Linux" +SYSTEM_OPENCLOUDOS="OpenCloudOS" +SYSTEM_OPENCLOUDOS_STREAM="OpenCloudOS Stream" +SYSTEM_TENCENTOS="TencentOS" +SYSTEM_OPENEULER="openEuler" +SYSTEM_ANOLISOS="Anolis" +SYSTEM_KYLIN_DESKTOP="Kylin Desktop" +SYSTEM_KYLIN_SERVER="Kylin Server" +SYSTEM_OPENKYLIN="openKylin" +SYSTEM_OPENSUSE="openSUSE" +SYSTEM_ARCH="Arch" +SYSTEM_MANJARO="Manjaro" +SYSTEM_ALPINE="Alpine" +SYSTEM_GENTOO="Gentoo" +SYSTEM_NIXOS="NixOS" + +## 定义系统版本文件 +File_LinuxRelease=/etc/os-release +File_RedHatRelease=/etc/redhat-release +File_DebianVersion=/etc/debian_version +File_ArmbianRelease=/etc/armbian-release +File_RaspberryPiOSRelease=/etc/rpi-issue +File_openEulerRelease=/etc/openEuler-release +File_HuaweiCloudEulerOSRelease=/etc/hce-release +File_OpenCloudOSRelease=/etc/opencloudos-release +File_TencentOSServerRelease=/etc/tlinux-release +File_AnolisOSRelease=/etc/anolis-release +File_AlibabaCloudLinuxRelease=/etc/alinux-release +File_OracleLinuxRelease=/etc/oracle-release +File_ArchLinuxRelease=/etc/arch-release +File_ManjaroRelease=/etc/manjaro-release +File_AlpineRelease=/etc/alpine-release +File_GentooRelease=/etc/gentoo-release +File_KylinRelease=/etc/kylin-release +File_kylinVersion=/etc/kylin-version/kylin-system-version.conf +File_ProxmoxVersion=/etc/pve/.version + +## 定义软件源相关文件或目录 +Dir_AptAdditionalSources=/etc/apt/sources.list.d +Dir_AptAdditionalSourcesBackup=$Dir_AptAdditionalSources.bak +Dir_YumRepos=/etc/yum.repos.d +Dir_YumReposBackup=$Dir_YumRepos.bak +Dir_ZYppRepos=/etc/zypp/repos.d +Dir_ZYppReposBackup=$Dir_ZYppRepos.bak +Dir_GentooReposConf=/etc/portage/repos.conf +Dir_NixConfig=/etc/nix +File_AptSourceList=/etc/apt/sources.list +File_AptSourceListBackup=$File_AptSourceList.bak +File_DebianSources=$Dir_AptAdditionalSources/debian.sources +File_DebianSourcesBackup=$File_DebianSources.bak +File_UbuntuSources=$Dir_AptAdditionalSources/ubuntu.sources +File_UbuntuSourcesBackup=$File_UbuntuSources.bak +File_ArmbianSourceList=$Dir_AptAdditionalSources/armbian.list +File_ArmbianSourceListBackup=$File_ArmbianSourceList.bak +File_ProxmoxSourceList=$Dir_AptAdditionalSources/pve-no-subscription.list +File_ProxmoxSourceListBackup=$File_ProxmoxSourceList.bak +File_ProxmoxAPLInfo=/usr/share/perl5/PVE/APLInfo.pm +File_LinuxMintSourceList=$Dir_AptAdditionalSources/official-package-repositories.list +File_LinuxMintSourceListBackup=$File_LinuxMintSourceList.bak +File_RaspberryPiSourceList=$Dir_AptAdditionalSources/raspi.list +File_RaspberryPiSourceListBackup=$File_RaspberryPiSourceList.bak +File_PacmanMirrorList=/etc/pacman.d/mirrorlist +File_PacmanMirrorListBackup=$File_PacmanMirrorList.bak +File_AlpineRepositories=/etc/apk/repositories +File_AlpineRepositoriesBackup=$File_AlpineRepositories.bak +File_GentooMakeConf=/etc/portage/make.conf +File_GentooMakeConfBackup=$File_GentooMakeConf.bak +File_GentooReposConf=/etc/portage/repos.conf/gentoo.conf +File_GentooReposConfBackup=$File_GentooReposConf.bak +File_NixConf=/etc/nix/nix.conf +File_NixConfBackup=$File_NixConf.bak + +## 定义颜色和样式变量 +RED='\033[31m' +GREEN='\033[32m' +YELLOW='\033[33m' +BLUE='\033[34m' +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 WARN ${PLAIN}" +ERROR="\033[1;31m✘${PLAIN}" +FAIL="\033[1;31m✘${PLAIN}" +TIP="\033[1;44m TIP ${PLAIN}" +WORKING="\033[1;36m◉${PLAIN}" + +function main() { + permission_judgment + collect_system_info + check_command_options + run_start + choose_mirrors + choose_protocol + choose_install_epel_packages + backup_original_mirrors + remove_original_mirrors + change_mirrors_main + upgrade_software + run_end +} + +function handle_command_options() { + while [ $# -gt 0 ]; do + case "$1" in + ## 海外模式 + --abroad) + USE_ABROAD_SOURCE="true" + ;; + ## 中国大陆教育网模式 + --edu) + USE_EDU_SOURCE="true" + ;; + ## 指定软件源地址 + --source) + if [ "$2" ]; then + echo "$2" | grep -Eq "\(|\)|\[|\]|\{|\}" + if [ $? -eq 0 ]; then + command_error "$2" "$(msg "error.cmd.options.validAddress")" + else + SOURCE="$(echo "$2" | sed -e 's,^http[s]\?://,,g' -e 's,/$,,')" + shift + fi + else + command_error "$1" "$(msg "error.cmd.options.sourceAddress")" + fi + ;; + --source-epel) + if [ "$2" ]; then + echo "$2" | grep -Eq "\(|\)|\[|\]|\{|\}" + if [ $? -eq 0 ]; then + command_error "$2" "$(msg "error.cmd.options.validAddress")" + else + SOURCE_EPEL="$(echo "$2" | sed -e 's,^http[s]\?://,,g' -e 's,/$,,')" + shift + fi + else + command_error "$1" "$(msg "error.cmd.options.sourceAddress")" + fi + ;; + --source-security) + if [ "$2" ]; then + echo "$2" | grep -Eq "\(|\)|\[|\]|\{|\}" + if [ $? -eq 0 ]; then + command_error "$2" "$(msg "error.cmd.options.validAddress")" + else + SOURCE_SECURITY="$(echo "$2" | sed -e 's,^http[s]\?://,,g' -e 's,/$,,')" + shift + fi + else + command_error "$1" "$(msg "error.cmd.options.sourceAddress")" + fi + ;; + --source-vault) + if [ "$2" ]; then + echo "$2" | grep -Eq "\(|\)|\[|\]|\{|\}" + if [ $? -eq 0 ]; then + command_error "$2" "$(msg "error.cmd.options.validAddress")" + else + SOURCE_VAULT="$(echo "$2" | sed -e 's,^http[s]\?://,,g' -e 's,/$,,')" + shift + fi + else + command_error "$1" "$(msg "error.cmd.options.sourceAddress")" + fi + ;; + --source-portage) + if [ "$2" ]; then + echo "$2" | grep -Eq "\(|\)|\[|\]|\{|\}" + if [ $? -eq 0 ]; then + command_error "$2" "$(msg "error.cmd.options.validAddress")" + else + SOURCE_PORTAGE="$(echo "$2" | sed -e 's,^http[s]\?://,,g' -e 's,/$,,')" + shift + fi + else + command_error "$1" "$(msg "error.cmd.options.sourceAddress")" + fi + ;; + --source-base-system) + if [ "$2" ]; then + echo "$2" | grep -Eq "\(|\)|\[|\]|\{|\}" + if [ $? -eq 0 ]; then + command_error "$2" "$(msg "error.cmd.options.validAddress")" + else + SOURCE_BASE_SYSTEM="$(echo "$2" | sed -e 's,^http[s]\?://,,g' -e 's,/$,,')" + shift + fi + else + command_error "$1" "$(msg "error.cmd.options.sourceAddress")" + fi + ;; + ## 指定软件源仓库 + --branch) + if [ "$2" ]; then + SOURCE_BRANCH="$2" + shift + else + command_error "$1" "$(msg "error.cmd.options.sourceRepository")" + fi + ;; + --branch-epel) + if [ "$2" ]; then + SOURCE_EPEL_BRANCH="$2" + shift + else + command_error "$1" "$(msg "error.cmd.options.sourceRepository")" + fi + ;; + --branch-security) + if [ "$2" ]; then + SOURCE_SECURITY_BRANCH="$2" + shift + else + command_error "$1" "$(msg "error.cmd.options.sourceRepository")" + fi + ;; + --branch-vault) + if [ "$2" ]; then + SOURCE_VAULT_BRANCH="$2" + shift + else + command_error "$1" "$(msg "error.cmd.options.sourceRepository")" + fi + ;; + --branch-portage) + if [ "$2" ]; then + SOURCE_PORTAGE_BRANCH="$2" + shift + else + command_error "$1" "$(msg "error.cmd.options.sourceRepository")" + fi + ;; + --branch-base-system) + if [ "$2" ]; then + SOURCE_BASE_SYSTEM_BRANCH="$2" + shift + else + command_error "$1" "$(msg "error.cmd.options.sourceRepository")" + fi + ;; + ## 指定 Debian 系操作系统的版本代号 + --codename) + if [ "$2" ]; then + DEBIAN_CODENAME="$2" + shift + else + command_error "$1" "$(msg "error.cmd.options.codename")" + fi + ;; + ## 使用官方源 + --use-official-source) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + USE_OFFICIAL_SOURCE="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.boolean")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.boolean")" + fi + ;; + ## EPEL 使用 官方源 + --use-official-source-epel) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + USE_OFFICIAL_SOURCE_EPEL="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.boolean")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.boolean")" + fi + ;; + ## 使用内网地址 + --intranet | --use-intranet-source) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + USE_INTRANET_SOURCE="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.boolean")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.boolean")" + fi + ;; + ## Web 协议(HTTP/HTTPS) + --protocol | --web-protocol) + if [ "$2" ]; then + case "$2" in + http | https | HTTP | HTTPS) + WEB_PROTOCOL="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.protocol")" + ;; + esac + else + ocommand_error "$1" "$(msg "error.cmd.options.needProtocol")" + fi + ;; + ## 安装 EPEL 附加软件包 + --install-epel) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + INSTALL_EPEL="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.boolean")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.boolean")" + fi + ;; + --only-epel) + ONLY_EPEL="true" + INSTALL_EPEL="true" + ;; + ## 备份原有软件源 + --backup) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + BACKUP="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.boolean")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.boolean")" + fi + ;; + ## 忽略覆盖备份提示 + --ignore-backup-tips) + IGNORE_BACKUP_TIPS="true" + ;; + ## 更新软件包 + --upgrade-software | --updata-software) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + UPGRADE_SOFTWARE="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.boolean")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.boolean")" + fi + ;; + ## 在更新软件包后清理下载缓存 + --clean-cache) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + CLEAN_CACHE="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.boolean")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.boolean")" + fi + ;; + ## Locale + --lang) + if [ "$2" ]; then + local lang_norm="${2//_/-}" + lang_norm="${lang_norm,,}" + case "$lang_norm" in + zh | zh-cn | zh-hans | zh-hans-*) + init_msg_pack "zh-hans" + shift + ;; + zh-hant | zh-hant-* | zh-tw | zh-hk) + init_msg_pack "zh-hant" + shift + ;; + en | en-us | en-*) + init_msg_pack "en" + shift + ;; + auto) + choose_display_language + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.validLangKey")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.langKey")" + fi + ;; + --zh | --zh-[Cc][Nn]) + init_msg_pack "zh-hans" + ;; + --en | --en-[Uu][Ss]) + init_msg_pack "en" + ;; + --zh-[Hh]an[st]) + init_msg_pack "$1" + ;; + ## 清除屏幕上的所有内容 + --clean-screen) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + CLEAN_SCREEN="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.boolean")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.boolean")" + fi + ;; + ## 打印源文件修改前后差异 + --print-diff) + PRINT_DIFF="true" + ;; + ## 纯净模式 + --pure-mode) + PURE_MODE="true" + ;; + ## 命令帮助 + --help) + echo -e "\n$(msg "commands.help" "https://github.com/SuperManito/LinuxMirrors/issues")\n" + exit + ;; + *) + command_error "$1" + ;; + esac + shift + done + ## 设置部分功能的默认值 + ONLY_EPEL="${ONLY_EPEL:-"false"}" + BACKUP="${BACKUP:-"true"}" + USE_OFFICIAL_SOURCE="${USE_OFFICIAL_SOURCE:-"false"}" + IGNORE_BACKUP_TIPS="${IGNORE_BACKUP_TIPS:-"false"}" + PRINT_DIFF="${PRINT_DIFF:-"false"}" + PURE_MODE="${PURE_MODE:-"false"}" +} + +function run_start() { + if [ -z "${CLEAN_SCREEN}" ]; then + [ -z "${SOURCE}" ] && clear + elif [ "${CLEAN_SCREEN}" == "true" ]; then + clear + fi + if [[ "${PURE_MODE}" == "true" ]]; then + return + fi + local system_name="${SYSTEM_PRETTY_NAME:-"${SYSTEM_NAME} ${SYSTEM_VERSION_ID}"}" + local arch="${DEVICE_ARCH}" + local date_time="$(date "+%Y-%m-%d %H:%M")" + local time_zone="$(timedatectl status 2>/dev/null | grep "Time zone" | awk -F ':' '{print$2}' | awk -F ' ' '{print$1}')" + echo -e "+-----------------------------------+" + echo -e "| \033[0;1;35;95m⡇\033[0m \033[0;1;33;93m⠄\033[0m \033[0;1;32;92m⣀⡀\033[0m \033[0;1;36;96m⡀\033[0;1;34;94m⢀\033[0m \033[0;1;35;95m⡀⢀\033[0m \033[0;1;31;91m⡷\033[0;1;33;93m⢾\033[0m \033[0;1;32;92m⠄\033[0m \033[0;1;36;96m⡀⣀\033[0m \033[0;1;34;94m⡀\033[0;1;35;95m⣀\033[0m \033[0;1;31;91m⢀⡀\033[0m \033[0;1;33;93m⡀\033[0;1;32;92m⣀\033[0m \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[0m \033[0;1;36;96m⠇⠸\033[0m \033[0;1;34;94m⠣\033[0;1;35;95m⠼\033[0m \033[0;1;31;91m⠜⠣\033[0m \033[0;1;33;93m⠇\033[0;1;32;92m⠸\033[0m \033[0;1;36;96m⠇\033[0m \033[0;1;34;94m⠏\033[0m \033[0;1;35;95m⠏\033[0m \033[0;1;33;93m⠣⠜\033[0m \033[0;1;32;92m⠏\033[0m \033[0;1;34;94m⠭⠕\033[0m |" + echo -e "+-----------------------------------+" + echo -e "$(msg "start.welcome")" + echo -e '' + echo -e "$(msg "start.runtimeEnv") ${BLUE}${system_name} ${arch}${PLAIN}" + echo -e "$(msg "start.dateTime") ${BLUE}${date_time} ${time_zone}${PLAIN}" + sleep 1 >/dev/null 2>&1 +} + +function run_end() { + if [[ "${PURE_MODE}" == "true" ]]; then + echo '' + return + fi + echo -e "\n✨ $(msg "end.moreInfo") 👉 \033[3mhttps://linuxmirrors.cn\033[0m" + if [[ "${#SPONSOR_ADS[@]}" -gt 0 ]]; then + echo -e "\n\033[2m$(msg "end.sponsorAds")\033[0m" + for ad in "${SPONSOR_ADS[@]}"; do + sleep 0.1 + echo -e " \033[2m${ad}\033[0m" + done + fi + echo -e "\n\033[3;1mPowered by \033[34mLinuxMirrors\033[0m\n" +} + +function output_error() { + [ "$1" ] && echo -e "\n$ERROR $1\n" + exit 1 +} + +function command_error() { + local tmp_text="$(msg "error.cmd.options.needConfirm")" + if [[ "${2}" ]]; then + tmp_text="$(msg "error.cmd.options.needSpecify" "${2}")" + fi + output_error "$(msg "error.cmd.options.invalid" "${BLUE}$1${PLAIN}" "${tmp_text}")" +} + +function unsupport_system_error() { + output_error "$(msg "error.unsupportSystem" "${1}")" +} + +function input_error() { + echo -e "\n$WARN $(msg "error.input" "${1}")" +} + +function command_exists() { + command -v "$@" &>/dev/null +} + +function permission_judgment() { + if [ $UID -ne 0 ]; then + local change_cmd="su root" + if command_exists sudo; then + change_cmd="sudo -i" + fi + output_error "$(msg "error.needRoot" "${BLUE}${change_cmd}${PLAIN}")" + fi +} + +function get_os_release_value() { + grep -E "^${1}=" $File_LinuxRelease | cut -d= -f2- | sed "s/[\'\"]//g" +} + +function collect_system_info() { + if [ ! -s "${File_LinuxRelease}" ]; then + unsupport_system_error "$(msg "error.unknownSystem")" + fi + ## 定义系统名称 + SYSTEM_NAME="$(get_os_release_value NAME)" + SYSTEM_PRETTY_NAME="$(get_os_release_value PRETTY_NAME)" + ## 定义系统版本号 + SYSTEM_VERSION_ID="$(get_os_release_value VERSION_ID)" + SYSTEM_VERSION_ID_MAJOR="${SYSTEM_VERSION_ID%%.*}" + SYSTEM_VERSION_ID_MINOR="${SYSTEM_VERSION_ID#*.}" + ## 定义系统ID + SYSTEM_ID="$(get_os_release_value ID)" + ## 判定当前系统派系 + if [ -s "${File_DebianVersion}" ]; then + 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 + SYSTEM_FACTIONS="${SYSTEM_OPENCLOUDOS}" # 自 9.0 版本起不再基于红帽 + elif [ -s "${File_AnolisOSRelease}" ]; then + SYSTEM_FACTIONS="${SYSTEM_ANOLISOS}" # 自 8.8 版本起不再基于红帽 + elif [ -s "${File_kylinVersion}" ] && [[ "${SYSTEM_ID}" == *"openkylin"* ]]; then + SYSTEM_FACTIONS="${SYSTEM_OPENKYLIN}" + elif [ -f "${File_ArchLinuxRelease}" ]; then + SYSTEM_FACTIONS="${SYSTEM_ARCH}" + elif [ -f "${File_AlpineRelease}" ]; then + SYSTEM_FACTIONS="${SYSTEM_ALPINE}" + elif [ -f "${File_GentooRelease}" ]; then + SYSTEM_FACTIONS="${SYSTEM_GENTOO}" + elif [[ "${SYSTEM_NAME}" == *"openSUSE"* ]]; then + SYSTEM_FACTIONS="${SYSTEM_OPENSUSE}" + elif [[ "${SYSTEM_NAME}" == *"NixOS"* ]]; then + SYSTEM_FACTIONS="${SYSTEM_NIXOS}" + else + unsupport_system_error "$(msg "error.unknownSystem")" + fi + ## 判定系统类型、版本、版本号 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + if command_exists lsb_release; then + SYSTEM_JUDGMENT="$(lsb_release -is)" + SYSTEM_VERSION_CODENAME="${DEBIAN_CODENAME:-"$(lsb_release -cs)"}" + else + ## https://codeberg.org/gioele/lsb-release-minimal + SYSTEM_JUDGMENT="${SYSTEM_ID^}" + if [ "${SYSTEM_NAME}" ]; then + if [[ "${SYSTEM_ID,,}" == "${SYSTEM_NAME,,}" ]]; then + SYSTEM_JUDGMENT="${SYSTEM_NAME}" + fi + fi + SYSTEM_VERSION_CODENAME="${DEBIAN_CODENAME:-"$(get_os_release_value VERSION_CODENAME)"}" + fi + ## Raspberry Pi OS 判定 + if [[ "${SYSTEM_FACTIONS}" == "${SYSTEM_DEBIAN}" ]] && [ -s "${File_RaspberryPiOSRelease}" ]; then + SYSTEM_JUDGMENT="${SYSTEM_RASPBERRY_PI_OS}" + SYSTEM_PRETTY_NAME="${SYSTEM_RASPBERRY_PI_OS}" + fi + ## 针对特定系统的判定 + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_DEBIAN}" ]]; then + ## 尚未正式发布的版本 + if [[ -z "${SYSTEM_VERSION_ID}" && "${SYSTEM_VERSION_CODENAME}" == "trixie" ]]; then + SYSTEM_VERSION_ID="13" + SYSTEM_VERSION_ID_MAJOR="${SYSTEM_VERSION_ID%%.*}" + SYSTEM_VERSION_ID_MINOR="${SYSTEM_VERSION_ID#*.}" + fi + ## 是否使用 DEB822 格式 + if [[ "${SYSTEM_VERSION_ID_MAJOR}" && "${SYSTEM_VERSION_ID_MAJOR}" -ge 13 ]]; then + USE_DEB822_FORMAT="true" + fi + fi + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_UBUNTU}" ]]; then + ## 是否使用 DEB822 格式 + if [[ "${SYSTEM_VERSION_ID_MAJOR}" && "${SYSTEM_VERSION_ID_MAJOR}" -ge 24 ]]; then + USE_DEB822_FORMAT="true" + fi + fi + ;; + "${SYSTEM_REDHAT}") + SYSTEM_JUDGMENT="$(awk '{printf $1}' $File_RedHatRelease)" + ## 针对特定系统的判定 + # Red Hat Enterprise Linux + grep -q "${SYSTEM_RHEL}" $File_RedHatRelease && SYSTEM_JUDGMENT="${SYSTEM_RHEL}" + # CentOS Stream + grep -q "${SYSTEM_CENTOS_STREAM}" $File_RedHatRelease && SYSTEM_JUDGMENT="${SYSTEM_CENTOS_STREAM}" + # Oracle Linux + [ -s "${File_OracleLinuxRelease}" ] && SYSTEM_JUDGMENT="${SYSTEM_ORACLE}" + ;; + "${SYSTEM_ARCH}") + if [ -f "${File_ManjaroRelease}" ]; then + SYSTEM_JUDGMENT="${SYSTEM_MANJARO}" + else + SYSTEM_JUDGMENT="${SYSTEM_FACTIONS}" + fi + ;; + *) + SYSTEM_JUDGMENT="${SYSTEM_FACTIONS}" + ;; + esac + ## 判断系统及版本是否适配 + local is_supported="true" + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_DEBIAN}") + if [[ ! "${SYSTEM_VERSION_ID_MAJOR}" =~ ^(1[0-3]|[8-9])$ ]]; then + is_supported="false" + fi + if [[ "${SYSTEM_VERSION_CODENAME}" == "sid" ]]; then + if [[ "${PURE_MODE}" != "true" ]]; then + echo -e "\n${WARN} $(msg "warn.unstableDebian" "${BLUE}unstable(sid)${PLAIN}")\n" + fi + fi + ;; + "${SYSTEM_UBUNTU}") + if [[ ! "${SYSTEM_VERSION_ID_MAJOR}" =~ ^(1[4-9]|2[0-5])$ ]]; then + is_supported="false" + fi + ;; + "${SYSTEM_LINUX_MINT}") + if [[ "${SYSTEM_NAME}" == *"LMDE"* ]]; then + if [[ "${SYSTEM_VERSION_ID_MAJOR}" != [6-7] ]]; then + is_supported="false" + fi + else + if [[ ! "${SYSTEM_VERSION_ID_MAJOR}" =~ ^(19|2[0-2])$ ]]; then + is_supported="false" + fi + fi + ;; + "${SYSTEM_RHEL}") + if [[ ! "${SYSTEM_VERSION_ID_MAJOR}" =~ ^([7-9]|10)$ ]]; then + is_supported="false" + fi + ;; + "${SYSTEM_CENTOS}") + if [[ "${SYSTEM_VERSION_ID_MAJOR}" != [7-8] ]]; then + is_supported="false" + fi + ;; + "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ROCKY}" | "${SYSTEM_ALMALINUX}" | "${SYSTEM_ORACLE}") + if [[ ! "${SYSTEM_VERSION_ID_MAJOR}" =~ ^([8-9]|10)$ ]]; then + is_supported="false" + fi + ;; + "${SYSTEM_FEDORA}") + if [[ "${SYSTEM_VERSION_ID}" != [3-4][0-9] ]]; then + is_supported="false" + fi + ;; + "${SYSTEM_OPENEULER}") + if [[ "${SYSTEM_VERSION_ID_MAJOR}" != 2[0-5] ]]; then + is_supported="false" + fi + ;; + "${SYSTEM_OPENCLOUDOS}") + if [[ ! "${SYSTEM_VERSION_ID_MAJOR}" =~ ^([8-9]|23)$ ]] || [[ "${SYSTEM_VERSION_ID_MAJOR}" == 8 && "${SYSTEM_VERSION_ID_MINOR}" -lt 6 ]]; then + is_supported="false" + fi + ;; + "${SYSTEM_ANOLISOS}") + if [[ ! "${SYSTEM_VERSION_ID_MAJOR}" =~ ^(8|23)$ ]]; then + is_supported="false" + fi + ;; + "${SYSTEM_OPENSUSE}") + case "${SYSTEM_ID}" in + "opensuse-leap") + if [[ "${SYSTEM_VERSION_ID_MAJOR}" != 1[5-6] ]]; then + is_supported="false" + fi + ;; + "opensuse-tumbleweed") ;; + *) + is_supported="false" + ;; + esac + ;; + # 理论全部支持或不作判断 + "${SYSTEM_KALI}" | "${SYSTEM_DEEPIN}" | "${SYSTEM_ZORIN}" | "${SYSTEM_RASPBERRY_PI_OS}" | "${SYSTEM_OPENKYLIN}") ;; + "${SYSTEM_ARCH}" | "${SYSTEM_MANJARO}" | "${SYSTEM_ALPINE}" | "${SYSTEM_GENTOO}" | "${SYSTEM_NIXOS}") ;; + *) + unsupport_system_error "$(msg "error.unknownVersion")" + ;; + esac + if [[ "${is_supported}" == "false" ]]; then + unsupport_system_error "$(msg "error.unsupportVersion")" + fi + ## 判定系统处理器架构 + DEVICE_ARCH_RAW="$(uname -m)" + case "${DEVICE_ARCH_RAW}" in + x86_64) + DEVICE_ARCH="x86_64" + ;; + aarch64) + DEVICE_ARCH="ARM64" + ;; + armv8l) + DEVICE_ARCH="ARMv8_32" + ;; + armv7l) + DEVICE_ARCH="ARMv7" + ;; + armv6l) + DEVICE_ARCH="ARMv6" + ;; + armv5tel) + DEVICE_ARCH="ARMv5" + ;; + i686) + DEVICE_ARCH="x86_32" + ;; + *) + DEVICE_ARCH="${DEVICE_ARCH_RAW}" + ;; + esac + ## 定义软件源仓库名称 + if [[ -z "${SOURCE_BRANCH}" ]]; then + ## 默认为系统名称小写,替换空格 + SOURCE_BRANCH="${SYSTEM_JUDGMENT,,}" + SOURCE_BRANCH="${SOURCE_BRANCH// /-}" + ## 处理特殊的仓库名称 + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_DEBIAN}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 8 | 9 | 10 | 11) + SOURCE_BRANCH="debian-archive/debian" + ;; + *) + SOURCE_BRANCH="debian" + ;; + esac + ;; + "${SYSTEM_UBUNTU}" | "${SYSTEM_ZORIN}") + if [[ "${DEVICE_ARCH_RAW}" == "x86_64" || "${DEVICE_ARCH_RAW}" == *i?86* ]]; then + SOURCE_BRANCH="ubuntu" + else + SOURCE_BRANCH="ubuntu-ports" + fi + ;; + "${SYSTEM_RASPBERRY_PI_OS}") + SOURCE_BRANCH="raspberrypi" + ;; + "${SYSTEM_RHEL}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 7 | 8) + if [[ "${DEVICE_ARCH_RAW}" == "x86_64" ]]; then + SOURCE_BRANCH="centos-vault" + else + SOURCE_BRANCH="centos-altarch" + fi + ;; + *) + SOURCE_BRANCH="centos-stream" # 使用 CentOS Stream 仓库 + ;; + esac + ;; + "${SYSTEM_CENTOS}") + if [[ "${DEVICE_ARCH_RAW}" == "x86_64" ]]; then + SOURCE_BRANCH="centos-vault" + else + SOURCE_BRANCH="centos-altarch" + fi + ;; + "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ORACLE}") + # 自 CentOS Stream 9 开始使用 centos-stream 仓库,旧版本使用 centos 仓库 + case "${SYSTEM_VERSION_ID_MAJOR}" in + 8) + if [[ "${DEVICE_ARCH_RAW}" == "x86_64" ]]; then + SOURCE_BRANCH="centos-vault" + else + SOURCE_BRANCH="centos-altarch" + fi + ;; + *) + SOURCE_BRANCH="centos-stream" + ;; + esac + ;; + "${SYSTEM_FEDORA}") + if [[ "${SYSTEM_VERSION_ID}" -lt 39 ]]; then + SOURCE_BRANCH="fedora-archive" + fi + ;; + "${SYSTEM_ARCH}") + if [[ "${DEVICE_ARCH_RAW}" == "x86_64" || "${DEVICE_ARCH_RAW}" == *i?86* ]]; then + SOURCE_BRANCH="archlinux" + else + SOURCE_BRANCH="archlinuxarm" + fi + ;; + "${SYSTEM_OPENCLOUDOS}") + # OpenCloudOS Stream + grep -q "${SYSTEM_OPENCLOUDOS_STREAM}" $File_OpenCloudOSRelease + if [ $? -eq 0 ]; then + SOURCE_BRANCH="${SYSTEM_OPENCLOUDOS_STREAM,,}" + SOURCE_BRANCH="${SOURCE_BRANCH// /-}" + fi + ;; + "${SYSTEM_NIXOS}") + SOURCE_BRANCH="nix-channels" + ;; + esac + fi + ## 定义软件源更新文字 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_ALPINE}" | "${SYSTEM_OPENKYLIN}") + SYNC_MIRROR_TEXT="$(msg "source.sync.text1")" + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}") + SYNC_MIRROR_TEXT="$(msg "source.sync.text2")" + ;; + "${SYSTEM_OPENSUSE}") + SYNC_MIRROR_TEXT="$(msg "source.sync.text3")" + ;; + "${SYSTEM_ARCH}" | "${SYSTEM_GENTOO}") + SYNC_MIRROR_TEXT="$(msg "source.sync.text4")" + ;; + "${SYSTEM_NIXOS}") + SYNC_MIRROR_TEXT="$(msg "source.sync.text5")" + ;; + esac + ## 判断是否可以使用高级交互式选择器 + CAN_USE_ADVANCED_INTERACTIVE_SELECTION="false" + if command_exists tput; then + CAN_USE_ADVANCED_INTERACTIVE_SELECTION="true" + fi +} + +## 命令选项兼容性判断 +function check_command_options() { + if [[ "${USE_ABROAD_SOURCE}" == "true" && "${USE_EDU_SOURCE}" == "true" ]]; then + output_error "$(msg "error.cmd.options.unsupportTwoSourceMode")" + fi + if [[ "${DEBIAN_CODENAME}" ]]; then + if [[ "${SYSTEM_FACTIONS}" != "${SYSTEM_DEBIAN}" && "${SYSTEM_FACTIONS}" != "${SYSTEM_OPENKYLIN}" ]]; then + output_error "$(msg "error.cmd.options.unsupportCodename")" + fi + fi + if [[ "${ONLY_EPEL}" == "true" ]]; then + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_REDHAT}") + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_FEDORA}" ]]; then + output_error "$(msg "error.cmd.options.unsupportEPEL")" + fi + ;; + *) + output_error "$(msg "error.cmd.options.unsupportEPEL")" + ;; + esac + fi +} + +## 选择显示语言 +function choose_display_language() { + local result + if command_exists tput; then + local -a lang_key_labels=() + local language_text + for ((i = 0; i < ${#MESSAGE_LANG_KEYS[@]}; i++)); do + language_text="${MESSAGE_LANG_DISPLAY[${MESSAGE_LANG_KEYS[$i]}]}" + if [[ "${language_text}" ]]; then + lang_key_labels+=("${language_text}") + else + lang_key_labels+=("") + fi + done + interactive_select_list "MESSAGE_LANG_KEYS" "\n ${BOLD}Please select the display language:${PLAIN}\n" "lang_key_labels" + result="${_SELECT_RESULT%%@@*}" + else + echo '' + for ((i = 0; i < ${#MESSAGE_LANG_KEYS[@]}; i++)); do + echo -e " $((i + 1)). ${MESSAGE_LANG_DISPLAY[${MESSAGE_LANG_KEYS[$i]}]}" + done + local CHOICE="$(echo -e "\n${BOLD}└─ Please select and enter the display language [ 1-${#MESSAGE_LANG_KEYS[@]} ]:${PLAIN}")" + while true; do + read -rp "${CHOICE}" INPUT + case "${INPUT}" in + [1-9] | [1-9][0-9]) + local tmp_result="${MESSAGE_LANG_KEYS[$((INPUT - 1))]}" + if [[ -z "${tmp_result}" ]]; then + echo -e "\n$WARN $(msg "warn.needValidNumberIndex")" + else + result="${tmp_result}" + break + fi + ;; + *) + echo -e "\n$WARN $(msg "warn.needInputNumberIndex")" + ;; + esac + done + fi + init_msg_pack "${result}" +} + +## 选择软件源 +function choose_mirrors() { + ## 打印软件源列表 + function print_mirrors_list() { + local tmp_name tmp_index i j + function StringLength() { + local text=$1 + echo "${#text}" + } + local -a list_arr=() + local list_arr_sum="$(eval echo \${#$1[@]})" + for ((i = 0; i < $list_arr_sum; i++)); do + list_arr[$i]="$(eval echo \${$1[i]})" + done + local name_width=${2:-"30"} + local -a list_labels=() + if [[ "${3}" ]]; then + eval "list_labels=(\"\${${3}[@]}\")" + fi + if command_exists printf; then + local tmp_uchar_1 tmp_uchar_2 tmp_uchar_3 tmp_uchar_4 tmp_default_length tmp_length tmp_unicode_length tmp_spaces_nums tmp_max_length + for ((i = 0; i < ${#list_arr[@]}; i++)); do + if [[ "${list_labels[$i]}" ]]; then + tmp_name="${list_labels[$i]}" + else + tmp_name="${list_arr[i]}" + fi + tmp_index=$((i + 1)) + tmp_default_length="${name_width}" + tmp_uchar_1=$(echo "${tmp_name}" | grep -c "“") + tmp_uchar_2=$(echo "${tmp_name}" | grep -c "”") + tmp_uchar_3=$(echo "${tmp_name}" | grep -c "‘") + tmp_uchar_4=$(echo "${tmp_name}" | grep -c "’") + [[ "${tmp_uchar_1}" -gt 0 ]] && ((tmp_default_length += tmp_uchar_1)) + [[ "${tmp_uchar_2}" -gt 0 ]] && ((tmp_default_length += tmp_uchar_2)) + [[ "${tmp_uchar_3}" -gt 0 ]] && ((tmp_default_length += tmp_uchar_3)) + [[ "${tmp_uchar_4}" -gt 0 ]] && ((tmp_default_length += tmp_uchar_4)) + tmp_length=$(StringLength "${tmp_name}") + tmp_unicode_length=$(StringLength "$(echo "${tmp_name}" | sed "s|[0-9a-zA-Z -~]||g; s| ||g")") + tmp_max_length=$((tmp_default_length + tmp_unicode_length)) + tmp_spaces_nums=$((((tmp_default_length - tmp_unicode_length - tmp_length)) / 2)) + if [[ $tmp_spaces_nums -gt 0 ]]; then + tmp_name="${tmp_name}$(printf '%*s' ${tmp_spaces_nums} '')" + fi + printf "❖ %-${tmp_max_length}s %4s\n" "${tmp_name}" "${tmp_index})" + done + else + for ((i = 0; i < ${#list_arr[@]}; i++)); do + if [[ "${list_labels[$i]}" ]]; then + tmp_name="${list_labels[$i]}" + else + tmp_name="${list_arr[i]}" + fi + tmp_index=$((i + 1)) + echo -e " ❖ $tmp_index. ${tmp_name}" + done + fi + } + + ## 选择使用软件源内网地址 + function choose_use_intranet_address() { + local intranet_source + for ((i = 0; i < ${#mirror_list_extranet[@]}; i++)); do + if [[ "${SOURCE}" == "${mirror_list_extranet[i]}" ]]; then + intranet_source="${mirror_list_intranet[i]}" + break + else + continue + fi + done + if [[ -z "${USE_INTRANET_SOURCE}" ]]; then + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}$(msg "interaction.source.type.select")${PLAIN}" "$(msg "interaction.source.type.public")" "$(msg "interaction.source.type.intranet")" + if [[ "${_SELECT_RESULT}" == "false" ]]; then + SOURCE="${intranet_source}" + ONLY_HTTP="true" # 强制使用 HTTP 协议 + [[ "${PURE_MODE}" != "true" ]] && echo -e "\n$WARN $(msg "warn.usedIntranetSource")" + fi + else + local CHOICE="$(echo -e "\n${BOLD}└─ $(msg "interaction.source.type.usePublicAddress")? [Y/n] ${PLAIN}")" + read -rp "${CHOICE}" INPUT + [[ -z "${INPUT}" ]] && INPUT=Y + case "${INPUT}" in + [Yy] | [Yy][Ee][Ss]) ;; + [Nn] | [Nn][Oo]) + SOURCE="${intranet_source}" + ONLY_HTTP="true" # 强制使用 HTTP 协议 + [[ "${PURE_MODE}" != "true" ]] && echo -e "\n$WARN $(msg "warn.usedIntranetSource")" + ;; + *) + input_error "$(msg "error.defaultBehavior.noUseIntranetSource")" + ;; + esac + fi + elif [[ "${USE_INTRANET_SOURCE}" == "true" ]]; then + SOURCE="${intranet_source}" + fi + } + + if [[ -z "${SOURCE}" ]]; then + ## 使用官方源 + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + return + fi + + local mirror_list_name mirror_list_label_msg_prefix mirror_list_print_length + if [[ "${USE_ABROAD_SOURCE}" = "true" ]]; then + mirror_list_name="mirror_list_abroad" + mirror_list_label_msg_prefix="mirrors.abroad" + mirror_list_print_length=56 + elif [[ "${USE_EDU_SOURCE}" = "true" ]]; then + mirror_list_name="mirror_list_edu" + mirror_list_label_msg_prefix="mirrors.edu" + mirror_list_print_length=32 + else + mirror_list_name="mirror_list_default" + mirror_list_label_msg_prefix="mirrors.default" + mirror_list_print_length=32 + fi + local -a mirror_list_labels=() + local mirror_list_length=$(eval "echo \${#${mirror_list_name}[@]}") + local label_msg_index label_msg_content + for ((i = 0; i < ${mirror_list_length}; i++)); do + label_msg_index="${mirror_list_label_msg_prefix}.${i}" + label_msg_content="$(msg "${label_msg_index}")" + if [[ "${label_msg_content}" == "${label_msg_index}" ]]; then + mirror_list_labels+=("") + else + mirror_list_labels+=("${label_msg_content}") + fi + done + + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + interactive_select_list "${mirror_list_name}" "\n ${BOLD}$(msg "interaction.source.select")${PLAIN}\n" "mirror_list_labels" + SOURCE="${_SELECT_RESULT%%@@*}" + echo -e "\n${GREEN}➜${PLAIN} ${BOLD}${_SELECT_RESULT#*@@}${PLAIN}" | sed "s| · |-|g" + else + echo '' + print_mirrors_list "${mirror_list_name}" "${mirror_list_print_length}" "mirror_list_labels" + local CHOICE="$(echo -e "\n${BOLD}└─ $(msg "interaction.source.selectAndInput") [ 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_result="$(eval echo \${${mirror_list_name}[$((INPUT - 1))]})" + if [[ -z "${tmp_result}" ]]; then + echo -e "\n$WARN $(msg "warn.needValidNumberIndex")" + else + SOURCE="$(echo "${tmp_result}" | awk -F '@' '{print$2}')" + break + fi + ;; + *) + echo -e "\n$WARN $(msg "warn.needInputNumberIndex")" + ;; + esac + done + fi + + ## 使用官方源 + if [[ "${SOURCE}" == "__OFFICIAL_SOURCE_TAG__" ]]; then + USE_OFFICIAL_SOURCE="true" + SOURCE="" + return + fi + fi + + ## 选择软件源内网地址 + if [[ "${mirror_list_extranet[*]}" =~ (^|[^[:alpha:]])"${SOURCE}"([^[:alpha:]]|$) ]]; then + choose_use_intranet_address + fi +} + +## 选择同步或更新软件源所使用的 Web 协议( HTTP/HTTPS) +function choose_protocol() { + if [[ -z "${WEB_PROTOCOL}" ]]; then + if [[ "${ONLY_HTTP}" == "true" ]]; then + WEB_PROTOCOL="http" + else + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}$(msg "interaction.protocol.select")${PLAIN}" "HTTP" "HTTPS" + if [[ "${_SELECT_RESULT}" == "true" ]]; then + WEB_PROTOCOL="http" + else + WEB_PROTOCOL="https" + fi + else + local CHOICE="$(echo -e "\n${BOLD}└─ $(msg "interaction.protocol.useHttp")? [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" + ;; + *) + input_error "$(msg "error.defaultBehavior.https")" + WEB_PROTOCOL="https" + ;; + esac + fi + fi + fi + WEB_PROTOCOL="${WEB_PROTOCOL,,}" +} + +# 选择安装/换源 EPEL 附加软件包(适用于部分红帽系统) +function choose_install_epel_packages() { + function check_install_status() { + ## 判断是否已安装 EPEL 软件包 + rpm -qa | grep epel-release -q + VERIFICATION_EPEL=$? + } + + ## 判断是否支持且需要处理 EPEL 附加软件包 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_REDHAT}") + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_FEDORA}" ]] || [[ "${INSTALL_EPEL}" == "false" ]]; then + INSTALL_EPEL="false" + return + else + check_install_status + fi + ;; + *) + INSTALL_EPEL="false" + return + ;; + esac + ## 选择是否安装 EPEL 附加软件包 + if [[ -z "${INSTALL_EPEL}" ]]; then + local ask_text + if [ $VERIFICATION_EPEL -eq 0 ]; then + ask_text="$(msg "interaction.epel.skipReplace")" + else + ask_text="$(msg "interaction.epel.install")" + fi + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}${ask_text}?${PLAIN}" + if [[ "${_SELECT_RESULT}" == "true" ]]; then + INSTALL_EPEL="true" + else + INSTALL_EPEL="false" + fi + else + local CHOICE="$(echo -e "\n${BOLD}└─ ${ask_text}? [Y/n] ${PLAIN}")" + read -rp "${CHOICE}" INPUT + [[ -z "${INPUT}" ]] && INPUT=Y + case "${INPUT}" in + [Yy] | [Yy][Ee][Ss]) + INSTALL_EPEL="true" + ;; + [Nn] | [Nn][Oo]) + INSTALL_EPEL="false" + ;; + *) + input_error "$(msg "error.defaultBehavior.noReplace")" + INSTALL_EPEL="false" + ;; + esac + fi + fi +} + +## 备份原有软件源(文件/目录) +function backup_original_mirrors() { + function backup_file() { + local target_file=$1 + local backup_file=$2 + local type="$3" + ## 判断是否存在源文件 + [ -f "${target_file}" ] || touch "${target_file}" + if [ ! -s "${target_file}" ]; then + return + fi + ## 判断是否存在已备份的源文件 + if [ -s "${backup_file}" ]; then + if [[ "${IGNORE_BACKUP_TIPS}" != "false" ]]; then + return + fi + local ask_text="$(msg "interaction.backup.skipOverwrite.sourceFile" "${type}")?" + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}${ask_text}${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}└─ ${ask_text} [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" + ;; + *) + input_error "$(msg "error.defaultBehavior.noOverwrite")" + ;; + esac + fi + else + echo '' + cp -rvf "${target_file}" "${backup_file}" 2>&1 + BACKED_UP="true" + echo -e "\n$COMPLETE $(msg "info.backuped.sourceFile" "${type}")" + sleep 1s + fi + } + function backup_dir() { + local target_dir=$1 + local backup_dir=$2 + [ -d "${target_dir}" ] || mkdir -p "${target_dir}" + [ -d "${backup_dir}" ] || mkdir -p "${backup_dir}" + ## 判断是否存在 repo 源文件 + ls "${target_dir}" | grep '\.repo$' -q + if [ $? -ne 0 ]; then + return + fi + ## 判断是否存在已备份的 repo 源文件 + ls "${backup_dir}" | grep '\.repo$' -q + if [ $? -eq 0 ]; then + if [[ "${IGNORE_BACKUP_TIPS}" != "false" ]]; then + return + fi + local ask_text="$(msg "interaction.backup.skipOverwrite.sourceFile" "repo")?" + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}${ask_text}${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}└─ ${ask_text} [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" + ;; + *) + input_error "$(msg "error.defaultBehavior.noOverwrite")" + ;; + esac + fi + else + echo '' + cp -rvf $target_dir/* "${backup_dir}" 2>&1 + BACKED_UP="true" + echo -e "\n$COMPLETE $(msg "info.backuped.sourceFile" "repo")" + sleep 1s + fi + } + + BACKED_UP="false" # 是否已备份 + if [[ "${BACKUP}" == "true" ]]; then + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + # /etc/apt/sources.list + if [[ "${SYSTEM_JUDGMENT}" != "${SYSTEM_LINUX_MINT}" && -s "${File_AptSourceList}" ]]; then + backup_file $File_AptSourceList $File_AptSourceListBackup "sources.list" + fi + # Debian DEB822 格式源文件 + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_DEBIAN}" ]] && [ -f "${File_DebianSources}" ]; then + backup_file $File_DebianSources $File_DebianSourcesBackup "debian.sources" + USE_DEB822_FORMAT="true" + fi + # Ubuntu DEB822 格式源文件 + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_UBUNTU}" ]] && [ -f "${File_UbuntuSources}" ]; then + backup_file $File_UbuntuSources $File_UbuntuSourcesBackup "ubuntu.sources" + USE_DEB822_FORMAT="true" + fi + # Armbian + if [ -f "${File_ArmbianRelease}" ]; then + backup_file $File_ArmbianSourceList $File_ArmbianSourceListBackup "armbian.list" + fi + # Proxmox VE + if [ -f "${File_ProxmoxVersion}" ]; then + backup_file $File_ProxmoxSourceList $File_ProxmoxSourceListBackup "pve-no-subscription.list" + fi + # Linux Mint + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_LINUX_MINT}" ]]; then + backup_file $File_LinuxMintSourceList $File_LinuxMintSourceListBackup "official-package-repositories.list" + fi + # Raspberry Pi OS + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_RASPBERRY_PI_OS}" ]]; then + backup_file $File_RaspberryPiSourceList $File_RaspberryPiSourceListBackup "raspi.list" + fi + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}") + # /etc/yum.repos.d + backup_dir $Dir_YumRepos $Dir_YumReposBackup + ;; + "${SYSTEM_OPENSUSE}") + # /etc/zypp/repos.d + backup_dir $Dir_ZYppRepos $Dir_ZYppReposBackup + ;; + "${SYSTEM_ARCH}") + # /etc/pacman.d/mirrorlist + backup_file $File_PacmanMirrorList $File_PacmanMirrorListBackup "mirrorlist" + ;; + "${SYSTEM_ALPINE}") + # /etc/apk/repositories + backup_file $File_AlpineRepositories $File_AlpineRepositoriesBackup "repositories" + ;; + "${SYSTEM_GENTOO}") + # /etc/portage/make.conf + backup_file $File_GentooMakeConf $File_GentooMakeConfBackup "make.conf" + # /etc/portage/repos.conf/gentoo.conf + [ -d "${Dir_GentooReposConf}" ] || mkdir -p "${Dir_GentooReposConf}" + backup_file $File_GentooReposConf $File_GentooReposConfBackup "gentoo.conf" + ;; + "${SYSTEM_NIXOS}") + [ ! -d "${Dir_NixConfig}" ] && mkdir -p "${Dir_NixConfig}" + # /etc/nix/nix.conf + backup_file $File_NixConf $File_NixConfBackup "nix.conf" + ;; + esac + fi +} + +## 移除原有软件源 +function remove_original_mirrors() { + function clear_file() { + [ -f "$1" ] && sed -i '1,$d' "$1" + } + + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + # /etc/apt/sources.list.d + [ -d "${Dir_AptAdditionalSources}" ] || mkdir -p $Dir_AptAdditionalSources + # Debian DEB822 格式源文件 + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_DEBIAN}" ]] && [ -f "${File_DebianSources}" ]; then + clear_file $File_DebianSources + USE_DEB822_FORMAT="true" + fi + # Ubuntu DEB822 格式源文件 + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_UBUNTU}" ]] && [ -f "${File_UbuntuSources}" ]; then + clear_file $File_UbuntuSources + USE_DEB822_FORMAT="true" + fi + # /etc/apt/sources.list + if [[ "${USE_DEB822_FORMAT}" != "true" ]] && [[ "${SYSTEM_JUDGMENT}" != "${SYSTEM_LINUX_MINT}" ]]; then + [ -s "${File_AptSourceList}" ] && clear_file $File_AptSourceList + fi + ## 解决软件源冲突 + if [[ "${USE_DEB822_FORMAT}" == "true" ]] && [ -s "${File_AptSourceList}" ]; then + if [[ "${SOURCE_BRANCH}" ]]; then + sed -e "/^deb\(-src\)\? http.*\/${SOURCE_BRANCH}/d" \ + -e "/^#[[:space:]]*deb\(-src\)\? http.*\/${SOURCE_BRANCH}/d" \ + -e "/^#.*\(默认禁用源码镜像以提高更新速度\|安全更新软件源\|预发布软件源\).*/d" \ + -i \ + $File_AptSourceList + fi + fi + # Armbian + [ -f "${File_ArmbianRelease}" ] && clear_file $File_ArmbianSourceList + # Proxmox VE + [ -f "${File_ProxmoxVersion}" ] && clear_file $File_ProxmoxSourceList + # Linux Mint + [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_LINUX_MINT}" ]] && clear_file $File_LinuxMintSourceList + # Raspberry Pi OS + [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_RASPBERRY_PI_OS}" ]] && clear_file $File_RaspberryPiSourceList + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}") + if [ ! -d "${Dir_YumRepos}" ]; then + mkdir -p "${Dir_YumRepos}" + return + fi + local -a repo_patterns=() + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_FEDORA}" ]]; then + repo_patterns=( + "fedora.repo" + "fedora-updates.repo" + "fedora-updates-testing.repo" + "fedora-modular.repo" + "fedora-updates-modular.repo" + "fedora-updates-testing-modular.repo" + ) + else + if [[ "${ONLY_EPEL}" != "false" ]]; then + return + fi + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_RHEL}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 7 | 8) + repo_patterns=("CentOS-*") + ;; + *) + repo_patterns=( + "centos-stream.repo" + "centos-stream-addons.repo" + ) + ;; + esac + ;; + "${SYSTEM_CENTOS}") + repo_patterns=("CentOS-*") + ;; + "${SYSTEM_CENTOS_STREAM}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 9 | 10) + repo_patterns=( + "centos-stream.repo" + "centos-stream-addons.repo" + ) + ;; + 8) + repo_patterns=("CentOS-Stream-*") + ;; + esac + ;; + "${SYSTEM_ROCKY}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 9) + repo_patterns=( + "rocky.repo" + "rocky-addons.repo" + "rocky-devel.repo" + "rocky-extras.repo" + ) + ;; + 8) + repo_patterns=("Rocky-*") + ;; + esac + ;; + "${SYSTEM_ALMALINUX}") + repo_patterns=("almalinux*") + ;; + "${SYSTEM_ORACLE}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 9 | 10) + repo_patterns=( + "*ol${SYSTEM_VERSION_ID_MAJOR}.repo" + "centos-stream.repo" + "centos-stream-addons.repo" + ) + ;; + 8) + repo_patterns=( + "*ol${SYSTEM_VERSION_ID_MAJOR}.repo" + "CentOS-Stream-*" + ) + ;; + esac + ;; + "${SYSTEM_OPENCLOUDOS}") + repo_patterns=("OpenCloudOS*") + ;; + "${SYSTEM_ANOLISOS}") + repo_patterns=("AnolisOS*") + ;; + "${SYSTEM_OPENEULER}") + repo_patterns=("openEuler.repo") + ;; + esac + fi + for pattern in "${repo_patterns[@]}"; do + if [[ -n "$pattern" ]]; then + eval "rm -rf $Dir_YumRepos/$pattern" + fi + done + ;; + "${SYSTEM_OPENSUSE}") + if [ ! -d "${Dir_ZYppRepos}" ]; then + mkdir -p "${Dir_ZYppRepos}" + return + fi + rm -rf $Dir_ZYppRepos/repo-* + rm -rf $Dir_ZYppRepos/openSUSE:repo-* + rm -rf $Dir_ZYppRepos/download.opensuse.org-* + ;; + "${SYSTEM_ARCH}") + clear_file $File_PacmanMirrorList + ;; + "${SYSTEM_ALPINE}") + clear_file $File_AlpineRepositories + ;; + "${SYSTEM_GENTOO}") + clear_file $File_GentooReposConf + ;; + esac +} + +## 换源 +function change_mirrors_main() { + ## 打印软件源内容修改前后差异 + function print_diff() { + ## 单一文件 + function diff_file() { + local diff_file=$1 + local origin_file=$2 + if [ -s "${diff_file}" ] && [ -s "${origin_file}" ]; then + if [[ "$(cat "${diff_file}")" != "$(cat "${origin_file}")" ]]; then + echo -e "\n${BLUE}${diff_file}${PLAIN} -> ${BLUE}${origin_file}${PLAIN}" + diff "${diff_file}" "${origin_file}" -d --color=always -I -B -E + fi + fi + } + ## 目录文件 + function diff_dir() { + local diff_dir=$1 + local origin_dir=$2 + for item in $(ls $diff_dir | xargs); do + diff_file "${diff_dir}/${item}" "${origin_dir}/${item}" + done + } + + if command_exists diff && [[ "${BACKED_UP}" == "true" ]]; then + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + if [[ "${USE_DEB822_FORMAT}" == "true" ]]; then + # DEB822 格式源文件 + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_DEBIAN}" ]]; then + diff_file $File_DebianSourcesBackup $File_DebianSources + fi + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_UBUNTU}" ]]; then + diff_file $File_UbuntuSourcesBackup $File_UbuntuSources + fi + else + if [[ "${SYSTEM_JUDGMENT}" != "${SYSTEM_LINUX_MINT}" ]]; then + diff_file $File_AptSourceListBackup $File_AptSourceList + fi + fi + # Armbian + if [ -f "${File_ArmbianRelease}" ]; then + diff_file $File_ArmbianSourceListBackup $File_ArmbianSourceList + fi + # Proxmox VE + if [ -f "${File_ProxmoxVersion}" ]; then + diff_file $File_ProxmoxSourceListBackup $File_ProxmoxSourceList + fi + # Linux Mint + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_LINUX_MINT}" ]]; then + diff_file $File_LinuxMintSourceListBackup $File_LinuxMintSourceList + fi + # Raspberry Pi OS + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_RASPBERRY_PI_OS}" ]]; then + diff_file $File_RaspberryPiSourceListBackup $File_RaspberryPiSourceList + fi + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}") + diff_dir $Dir_YumReposBackup $Dir_YumRepos + ;; + "${SYSTEM_OPENSUSE}") + diff_dir $Dir_ZYppReposBackup $Dir_ZYppRepos + ;; + "${SYSTEM_ARCH}") + diff_file $File_PacmanMirrorListBackup $File_PacmanMirrorList + ;; + "${SYSTEM_ALPINE}") + diff_file $File_AlpineRepositoriesBackup $File_AlpineRepositories + ;; + "${SYSTEM_GENTOO}") + diff_file $File_GentooMakeConfBackup $File_GentooMakeConf + diff_file $File_GentooReposConfBackup $File_GentooReposConf + ;; + "${SYSTEM_NIXOS}") + diff_file $File_NixConfBackup $File_NixConf + ;; + esac + fi + } + + ## 调用换源函数 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}") + change_mirrors_Debian + ;; + "${SYSTEM_REDHAT}") + change_mirrors_RedHat + ;; + "${SYSTEM_OPENEULER}") + change_mirrors_openEuler + ;; + "${SYSTEM_OPENCLOUDOS}") + change_mirrors_OpenCloudOS + ;; + "${SYSTEM_OPENKYLIN}") + change_mirrors_openKylin + ;; + "${SYSTEM_ANOLISOS}") + change_mirrors_AnolisOS + ;; + "${SYSTEM_OPENSUSE}") + change_mirrors_openSUSE + ;; + "${SYSTEM_ARCH}") + change_mirrors_ArchLinux + ;; + "${SYSTEM_ALPINE}") + change_mirrors_Alpine + ;; + "${SYSTEM_GENTOO}") + change_mirrors_Gentoo + ;; + "${SYSTEM_NIXOS}") + change_mirrors_NixOS + ;; + esac + ## 比较差异 + if [[ "${PRINT_DIFF}" == "true" ]]; then + print_diff + fi + ## 更新软件源 + local -a commands=() + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + commands+=("apt-get update") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}") + local package_manager="$(get_package_manager)" + commands+=("${package_manager} makecache") + ;; + "${SYSTEM_OPENSUSE}") + commands+=("zypper ref") + ;; + "${SYSTEM_ARCH}") + commands+=("pacman -Sy") + ;; + "${SYSTEM_ALPINE}") + commands+=("apk update -f") + ;; + "${SYSTEM_GENTOO}") + commands+=("emerge --sync --quiet") + ;; + "${SYSTEM_NIXOS}") + commands+=("nix-store --verify") + commands+=("nix-channel --update") + ;; + esac + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + echo '' + animate_exec "${exec_cmd}" "${SYNC_MIRROR_TEXT}" + if [ $? -ne 0 ]; then + echo '' + exit 1 + fi + else + echo -e "\n$WORKING ${SYNC_MIRROR_TEXT}...\n" + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + if [ $? -eq 0 ]; then + echo -e "\n$SUCCESS $(msg "source.changeResult.success")" + else + echo -e "\n$FAIL $(msg "source.changeResult.fail" "${SYNC_MIRROR_TEXT}")" + echo -e "\n$TIP $(msg "source.changeResult.tipTitle" "${SYNC_MIRROR_TEXT}")" + echo -e "\n1. $(msg "source.changeResult.tip1")" + echo -e "2. $(msg "source.changeResult.tip2" "${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}")" + echo -e " $(msg "source.changeResult.tip2.1")" + echo -e " $(msg "source.changeResult.tip2.2")" + echo -e " $(msg "source.changeResult.tip2.3")" + echo -e "3. $(msg "source.changeResult.tip3")\n" + exit 1 + fi + fi +} + +## 升级软件包 +function upgrade_software() { + ## 跳过特殊的系统 + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_RHEL}" | "${SYSTEM_ORACLE}") + return + ;; + esac + local ask_text="" + ## 交互确认 + if [[ -z "${UPGRADE_SOFTWARE}" ]]; then + UPGRADE_SOFTWARE="false" + ask_text="$(msg "interaction.upgrade.skip")?" + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}${ask_text}${PLAIN}" + if [[ "${_SELECT_RESULT}" == "false" ]]; then + UPGRADE_SOFTWARE="true" + fi + else + local CHOICE="$(echo -e "\n${BOLD}└─ ${ask_text} [Y/n] ${PLAIN}")" + read -rp "${CHOICE}" INPUT + [[ -z "${INPUT}" ]] && INPUT=Y + case "${INPUT}" in + [Yy] | [Yy][Ee][Ss]) ;; + [Nn] | [Nn][Oo]) + UPGRADE_SOFTWARE="true" + ;; + *) + input_error "$(msg "error.defaultBehavior.noUpdate")" + ;; + esac + fi + fi + if [[ "${UPGRADE_SOFTWARE}" == "false" ]]; then + return + fi + if [[ -z "${CLEAN_CACHE}" ]]; then + CLEAN_CACHE="false" + ask_text="$(msg "interaction.cache.autoClean")?" + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}${ask_text}${PLAIN}" + if [[ "${_SELECT_RESULT}" == "true" ]]; then + CLEAN_CACHE="true" + fi + else + local CHOICE="$(echo -e "\n${BOLD}└─ ${ask_text} [Y/n] ${PLAIN}")" + read -rp "${CHOICE}" INPUT + [[ -z "${INPUT}" ]] && INPUT=Y + case "${INPUT}" in + [Yy] | [Yy][Ee][Ss]) + CLEAN_CACHE="true" + ;; + [Nn] | [Nn][Oo]) ;; + *) + input_error "$(msg "error.defaultBehavior.noClean")" + ;; + esac + fi + fi + local -a commands=() + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + commands+=("apt-get upgrade -y") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}") + local package_manager="$(get_package_manager)" + commands+=("${package_manager} upgrade -y") + ;; + "${SYSTEM_OPENSUSE}") + commands+=("zypper update -y") + ;; + "${SYSTEM_ARCH}") + commands+=("pacman -Syu --noconfirm") + ;; + "${SYSTEM_ALPINE}") + commands+=("apk upgrade --no-cache") + ;; + "${SYSTEM_GENTOO}") + commands+=("emerge --update --deep --with-bdeps=y --ask=n @world") + ;; + "${SYSTEM_NIXOS}") + commands+=("nixos-rebuild switch") + ;; + esac + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + echo '' + animate_exec "${exec_cmd}" "$(msg "work.upgradeSoftware")" + else + echo '' + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + fi + if [[ "${CLEAN_CACHE}" == "false" ]]; then + return + fi + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + apt-get autoremove -y >/dev/null 2>&1 + apt-get clean >/dev/null 2>&1 + ;; + "${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 + ;; + "${SYSTEM_OPENSUSE}") + rm -rf /var/cache/zypp/* >/dev/null 2>&1 + ;; + "${SYSTEM_ARCH}") + pacman -Scc --noconfirm >/dev/null 2>&1 + ;; + "${SYSTEM_ALPINE}") + rm -rf /var/cache/apk/* >/dev/null 2>&1 + ;; + "${SYSTEM_GENTOO}") + eclean-dist --deep >/dev/null 2>&1 + eclean-packages --deep >/dev/null 2>&1 + ;; + "${SYSTEM_NIXOS}") + nix-collect-garbage -d >/dev/null 2>&1 + ;; + esac +} + +############################################################################## + +## 更换基于 Debian 系 Linux 发行版的软件源 +function change_mirrors_Debian() { + local apt_source_file=$File_AptSourceList + local apt_source_content="" + function write_apt_source() { + if [[ -n "${apt_source_content}" ]]; then + echo "${apt_source_content}" >>$apt_source_file + fi + apt_source_content="" # 重置内容 + } + + ## 注释的提示语句 + local deb_src_disabled_tips="## $(msg "source.comment.disabledSourceCode")" + local security_source_tips="## $(msg "source.comment.securitySource")" + local proposed_source_tips="## $(msg "source.comment.proposedSource")" + + ## one-line 格式模板 + function _template_deb() { + echo "${1} ${WEB_PROTOCOL}://${2}/ ${3} ${4}" + } + function gen_deb() { + echo "$(_template_deb "deb" "${1}" "${2}" "${3}") +$(_template_deb "deb-src" "${1}" "${2}" "${3}" | sed -e "s|^|# |g")" + } + function gen_deb_unsrc() { + echo "$(_template_deb "deb" "${1}" "${2}" "${3}")" + } + function gen_deb_disabled() { + echo "$(gen_deb "${1}" "${2}" "${3}" | sed -e "s|^|# |g")" + } + function gen_deb_unsrc_disabled() { + echo "$(gen_deb_unsrc "${1}" "${2}" "${3}" | sed -e "s|^|# |g")" + } + function gen_deb_security() { + echo "${security_source_tips} +$(gen_deb "${1}" "${2}-security" "${3}")" + } + + ## DEB822 格式模板 + function _template_deb822() { + echo "Types: ${1} +URIs: ${WEB_PROTOCOL}://${2}/ +Suites: ${3} +Components: ${4} +Signed-By: /usr/share/keyrings/${SYSTEM_JUDGMENT,,}-archive-keyring.gpg" + } + function gen_deb822() { + echo "$(_template_deb822 "deb" "${1}" "${2}" "${3}") + +$(_template_deb822 "deb-src" "${1}" "${2}" "${3}" | sed -e "s|^|# |g")" + } + function gen_deb822_disabled() { + echo "$(_template_deb822 "deb" "${1}" "${2}" "${3}" | sed -e "s|^|# |g") + +$(_template_deb822 "deb-src" "${1}" "${2}" "${3}" | sed -e "s|^|# |g")" + } + function gen_deb822_security() { + echo "${security_source_tips} +$(gen_deb822 "${1}" "${2}-security" "${3}")" + } + + ## 获取 Debian 软件源相关信息 + function _template_get_debian_info() { + local data1="${1}" + local data2="${2}" + local mode="${3:-main}" + local codename="${4}" + local result="${data2}" + case "${mode}" in + "security") + local -a majors=(8 9 10) + local -a codenames=("jessie" "stretch" "buster") + ;; + *) + local -a majors=(8 9 10 11) + local -a codenames=("jessie" "stretch" "buster" "bullseye") + ;; + esac + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_DEBIAN}" ]]; then + for version in "${majors[@]}"; do + if [[ "${SYSTEM_VERSION_ID_MAJOR}" == "${version}" ]]; then + result="${data1}" + break + fi + done + else + for name in "${codenames[@]}"; do + if [[ "${codename}" == "${name}" ]]; then + result="${data1}" + break + fi + done + fi + echo "${result}" + } + function get_debian_official_source() { + # 注:使用官方源时仓库分支固定为 debian,应同此方法一起使用 + _template_get_debian_info "archive.debian.org" "deb.debian.org" "main" "${1}" + } + function get_debian_source_branch() { + _template_get_debian_info "debian-archive/debian" "debian" "main" "${1}" + } + function get_debian_repo_components() { + _template_get_debian_info "main contrib non-free" "main contrib non-free non-free-firmware" "main" "${1}" + } + function get_debian_official_source_security_host() { + # 注:使用官方源时仓库分支固定为 debian-security,应同此方法一起使用 + _template_get_debian_info "archive.debian.org" "security.debian.org" "security" "${1}" + } + function get_debian_source_security_branch() { + _template_get_debian_info "debian-archive/debian-security" "debian-security" "security" "${1}" + } + + ## Debian 软件源模板 + # debian-backports: https://ftp.debian.org/debian/dists + # debian-security: https://security.debian.org/debian-security/dists + function _template_gen_debian_source() { + local mode="${4:-main}" + local type="${5:-deb}" + local result="" + + case "${mode}" in + "security") + case "${2}" in + "forky" | "trixie" | "bookworm" | "bullseye" | "oldoldstable" | "oldstable" | "stable" | "testing") + if [[ "${type}" == "deb822" ]]; then + result="$(gen_deb822_security "${1}" "${2}" "${3}")" + else + result="$(gen_deb_security "${1}" "${2}" "${3}")" + fi + ;; + "jessie" | "stretch" | "buster") + if [[ "${type}" == "deb822" ]]; then + result="${security_source_tips} +$(gen_deb822 "${1}" "${2}" "${3}")" + else + result="${security_source_tips} +$(gen_deb "${1}" "${2}" "${3}")" + fi + ;; + *) + result="" + ;; + esac + ;; + + *) + case "${2}" in + "forky" | "trixie" | "bookworm" | "stable" | "oldstable" | "testing") + if [[ "${type}" == "deb822" ]]; then + result="${deb_src_disabled_tips} +$(gen_deb822 "${1}" "${2} ${2}-updates ${2}-backports" "${3}")" + else + result="$(gen_deb "${1}" "${2}" "${3}") +$(gen_deb "${1}" "${2}-updates" "${3}") +$(gen_deb "${1}" "${2}-backports" "${3}")" + fi + ;; + *) + if [[ "${type}" == "deb822" ]]; then + result="${deb_src_disabled_tips} +$(gen_deb822 "${1}" "${2} ${2}-updates" "${3}")" + else + result="$(gen_deb "${1}" "${2}" "${3}") +$(gen_deb "${1}" "${2}-updates" "${3}")" + fi + ;; + esac + ;; + esac + echo "${result}" + } + function gen_debian_deb() { + _template_gen_debian_source "${1}" "${2}" "${3}" "main" "deb" + } + function gen_debian_deb_security() { + _template_gen_debian_source "${1}" "${2}" "${3}" "security" "deb" + } + function gen_debian_deb822() { + _template_gen_debian_source "${1}" "${2}" "${3}" "main" "deb822" + } + function gen_debian_deb822_security() { + _template_gen_debian_source "${1}" "${2}" "${3}" "security" "deb822" + } + + ## Ubuntu 软件源模板 + function gen_ubuntu_deb() { + echo "$(gen_deb "${1}" "${2}" "${3}") +$(gen_deb "${1}" "${2}-updates" "${3}") +$(gen_deb "${1}" "${2}-backports" "${3}") +${proposed_source_tips} +$(gen_deb_disabled "${1}" "${2}-proposed" "${3}")" + } + function gen_ubuntu_deb822() { + echo "${deb_src_disabled_tips} +$(gen_deb822 "${1}" "${2} ${2}-updates ${2}-backports" "${3}") + +${proposed_source_tips} +$(gen_deb822_disabled "${1}" "${2}-proposed" "${3}")" + } + + ## 使用官方源 + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_UBUNTU}" | "${SYSTEM_ZORIN}") + if [[ "${DEVICE_ARCH_RAW}" == "x86_64" || "${DEVICE_ARCH_RAW}" == *i?86* ]]; then + SOURCE="archive.ubuntu.com" + else + SOURCE="ports.ubuntu.com" + fi + ;; + "${SYSTEM_KALI}") + SOURCE="http.kali.org" + ;; + "${SYSTEM_DEEPIN}") + SOURCE="community-packages.deepin.com" + ;; + esac + fi + + # 注:SOURCE_ SOURCE__BRANCH 系列变量默认为空值,仅在自定义(使用相关命令选项)时提供,需注意逻辑顺序 + local repo_components="" # 软件源仓库区域 + local source_address="${SOURCE}/${SOURCE_BRANCH}" # 软件源地址 + + local source_security_host="${SOURCE}" + local source_security_branch="${SOURCE_BRANCH}" + local source_security_address="" + + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_DEBIAN}") + repo_components="$(get_debian_repo_components "${SYSTEM_VERSION_CODENAME}")" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="$(get_debian_official_source "${SYSTEM_VERSION_CODENAME}")" + SOURCE_BRANCH="debian" + source_address="${SOURCE}/${SOURCE_BRANCH}" + fi + # 安全更新源 + source_security_branch="$(get_debian_source_security_branch "${SYSTEM_VERSION_CODENAME}")" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + source_security_host="$(get_debian_official_source_security_host "${SYSTEM_VERSION_CODENAME}")" + source_security_branch="debian-security" + fi + source_security_address="${SOURCE_SECURITY:-${source_security_host}}/${SOURCE_SECURITY_BRANCH:-${source_security_branch}}" + ## DEB822 / one-line + if [[ "${USE_DEB822_FORMAT}" == "true" ]]; then + apt_source_file="${File_DebianSources}" + if [[ "${SYSTEM_VERSION_CODENAME}" != "sid" ]]; then + apt_source_content="$(gen_debian_deb822 "${source_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}") + +$(gen_debian_deb822_security "${source_security_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}")" + else + apt_source_content="$(gen_debian_deb822 "${source_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}")" + fi + else + apt_source_file="${File_AptSourceList}" + if [[ "${SYSTEM_VERSION_CODENAME}" != "sid" ]]; then + apt_source_content="${deb_src_disabled_tips} +$(gen_debian_deb "${source_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}") +$(gen_debian_deb_security "${source_security_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}")" + else + apt_source_content="${deb_src_disabled_tips} +$(gen_deb "${source_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}")" + fi + fi + write_apt_source + ;; + + "${SYSTEM_UBUNTU}" | "${SYSTEM_ZORIN}") + repo_components="main restricted universe multiverse" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + if [[ "${DEVICE_ARCH_RAW}" == "x86_64" || "${DEVICE_ARCH_RAW}" == *i?86* ]]; then + SOURCE="archive.ubuntu.com" + SOURCE_BRANCH="ubuntu" + source_address="${SOURCE}/${SOURCE_BRANCH}" + else + SOURCE="ports.ubuntu.com" + SOURCE_BRANCH="" # 官方源默认无分支(注:有 ubuntu-ports 重定向) + source_address="${SOURCE}" + fi + fi + # 安全更新源 + source_security_address="${SOURCE_SECURITY:-${source_security_host}}/${SOURCE_SECURITY_BRANCH:-${source_security_branch}}" + ## DEB822 / one-line + if [[ "${USE_DEB822_FORMAT}" == "true" ]]; then + apt_source_file="${File_UbuntuSources}" + apt_source_content="$(gen_ubuntu_deb822 "${source_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}") + +$(gen_deb822_security "${source_security_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}")" + else + apt_source_file="${File_AptSourceList}" + apt_source_content="${deb_src_disabled_tips} +$(gen_ubuntu_deb "${source_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}") +$(gen_deb_security "${source_security_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}")" + fi + write_apt_source + ;; + + "${SYSTEM_KALI}") + repo_components="main contrib non-free non-free-firmware" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="http.kali.org" + SOURCE_BRANCH="" # 官方源无分支 + source_address="${SOURCE}" + fi + apt_source_content="${deb_src_disabled_tips} +$(gen_deb "${source_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}")" + write_apt_source + ;; + + "${SYSTEM_DEEPIN}") + if [[ "${SYSTEM_VERSION_ID_MAJOR}" == "25" ]]; then + repo_components="main commercial community" + else + repo_components="main contrib non-free" + fi + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="community-packages.deepin.com" + SOURCE_BRANCH="deepin" + source_address="${SOURCE}/${SOURCE_BRANCH}" + fi + apt_source_content="${deb_src_disabled_tips} +$(gen_deb "${source_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}")" + write_apt_source + ;; + + "${SYSTEM_LINUX_MINT}") + # 专用源 + repo_components="main upstream import backport" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="packages.linuxmint.com" + SOURCE_BRANCH="" # 官方源无分支 + source_address="${SOURCE}" + fi + apt_source_file="${File_LinuxMintSourceList}" + apt_source_content="${deb_src_disabled_tips} +$(gen_deb_unsrc "${source_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}") +" # 注:此处空行用于隔开两种软件源内容 + write_apt_source + + # 底层系统软件源 + local base_system_branch base_system_codename + if [[ "${SYSTEM_NAME}" == *"LMDE"* ]]; then + ## Debian 版(LMDE) + base_system_codename="$(get_os_release_value DEBIAN_CODENAME)" + [[ -z "${base_system_codename}" ]] && base_system_codename="bookworm" + base_system_branch="$(get_debian_source_branch "${base_system_codename}")" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="$(get_debian_official_source "${base_system_codename}")" + base_system_branch="debian" + fi + repo_components="$(get_debian_repo_components "${base_system_codename}")" + source_address="${SOURCE_BASE_SYSTEM:-${SOURCE}}/${SOURCE_BASE_SYSTEM_BRANCH:-${base_system_branch}}" + # 安全更新源 + source_security_branch="$(get_debian_source_security_branch "${base_system_codename}")" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + source_security_host="$(get_debian_official_source_security_host "${base_system_codename}")" + source_security_branch="debian-security" + fi + source_security_address="${SOURCE_SECURITY:-${SOURCE_BASE_SYSTEM:-${source_security_host}}}/${SOURCE_SECURITY_BRANCH:-${source_security_branch}}" + # 写入源文件 + apt_source_file="${File_LinuxMintSourceList}" + apt_source_content="$(gen_debian_deb "${source_address}" "${base_system_codename}" "${repo_components}") +$(gen_debian_deb_security "${source_security_address}" "${base_system_codename}" "${repo_components}")" + write_apt_source + else + ## Ubuntu 版 + base_system_codename="$(get_os_release_value UBUNTU_CODENAME)" + [[ -z "${base_system_codename}" ]] && base_system_codename="noble" + if [[ "${DEVICE_ARCH_RAW}" == "x86_64" || "${DEVICE_ARCH_RAW}" == *i?86* ]]; then + base_system_branch="ubuntu" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="archive.ubuntu.com" + fi + else + base_system_branch="ubuntu-ports" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="ports.ubuntu.com" + fi + fi + repo_components="main restricted universe multiverse" + source_address="${SOURCE_BASE_SYSTEM:-${SOURCE}}/${SOURCE_BASE_SYSTEM_BRANCH:-${base_system_branch}}" + # 安全更新源 + source_security_address="${SOURCE_SECURITY:-${SOURCE_BASE_SYSTEM:-${source_security_host}}}/${SOURCE_BASE_SYSTEM_BRANCH:-${base_system_branch}}" + # 写入源文件 + apt_source_file="${File_LinuxMintSourceList}" + apt_source_content="$(gen_ubuntu_deb "${source_address}" "${base_system_codename}" "${repo_components}") +$(gen_deb_security "${source_security_address}" "${base_system_codename}" "${repo_components}")" + write_apt_source + fi + ;; + + "${SYSTEM_RASPBERRY_PI_OS}") + # 专用源 + repo_components="main" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="archive.raspberrypi.org" + SOURCE_BRANCH="debian" + source_address="${SOURCE}/${SOURCE_BRANCH}" + fi + apt_source_file="${File_RaspberryPiSourceList}" + apt_source_content="${deb_src_disabled_tips} +$(gen_deb "${source_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}")" + write_apt_source + + # 底层系统软件源(注:64位系统为 Debian 官方仓库,32位为 Raspbian 仓库) + local base_system_branch base_system_codename + case "${DEVICE_ARCH_RAW}" in + x86_64 | aarch64) + ## Debian 版 + base_system_codename="${SYSTEM_VERSION_CODENAME}" + base_system_branch="$(get_debian_source_branch "${base_system_codename}")" + repo_components="$(get_debian_repo_components "${base_system_codename}")" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="$(get_debian_official_source "${base_system_codename}")" + base_system_branch="debian" + fi + source_address="${SOURCE_BASE_SYSTEM:-${SOURCE}}/${SOURCE_BASE_SYSTEM_BRANCH:-${base_system_branch}}" + # 安全更新源 + source_security_branch="$(get_debian_source_security_branch "${base_system_codename}")" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + source_security_host="$(get_debian_official_source_security_host "${base_system_codename}")" + source_security_branch="debian-security" + fi + source_security_address="${SOURCE_SECURITY:-${SOURCE_BASE_SYSTEM:-${source_security_host}}}/${SOURCE_SECURITY_BRANCH:-${source_security_branch}}" + # 写入源文件 + apt_source_file="${File_AptSourceList}" + apt_source_content="${deb_src_disabled_tips} +$(gen_debian_deb "${source_address}" "${base_system_codename}" "${repo_components}") +$(gen_debian_deb_security "${source_security_address}" "${base_system_codename}" "${repo_components}")" + write_apt_source + ;; + *) + ## Raspbian 版 + base_system_branch="raspbian" + base_system_codename="${SYSTEM_VERSION_CODENAME}" + repo_components="main contrib non-free rpi" + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="raspbian.raspberrypi.org" + source_address="${SOURCE_BASE_SYSTEM:-${SOURCE}}/${SOURCE_BASE_SYSTEM_BRANCH:-${base_system_branch}}" + else + source_address="${SOURCE_BASE_SYSTEM:-${SOURCE}}/${SOURCE_BASE_SYSTEM_BRANCH:-${base_system_branch}}/raspbian" + fi + # 写入源文件 + apt_source_file="${File_AptSourceList}" + apt_source_content="${deb_src_disabled_tips} +$(gen_deb "${source_address}" "${base_system_codename}" "${repo_components}")" + # multiarch 源 + if [[ "${DEVICE_ARCH_RAW}" == "armv7l" && "${USE_OFFICIAL_SOURCE}" != "true" ]]; then + source_address="${SOURCE_BASE_SYSTEM:-${SOURCE}}/${SOURCE_BASE_SYSTEM_BRANCH:-${base_system_branch}}" + apt_source_content="${apt_source_content} +## multiarch +# deb [arch=arm64] ${WEB_PROTOCOL}://${source_address}/multiarch/ ${base_system_codename} ${repo_components}" + fi + write_apt_source + ;; + esac + ;; + esac + + ## 处理其它衍生操作系统的专用源 + # Armbian + if [ -f "${File_ArmbianRelease}" ]; then + apt_source_file="${File_ArmbianSourceList}" + apt_source_content="deb [signed-by=/usr/share/keyrings/armbian.gpg] ${WEB_PROTOCOL}://${SOURCE}/armbian ${SYSTEM_VERSION_CODENAME} main ${SYSTEM_VERSION_CODENAME}-utils ${SYSTEM_VERSION_CODENAME}-desktop" + write_apt_source + fi + # Proxmox VE + if [ -f "${File_ProxmoxVersion}" ]; then + source_address="${SOURCE}/proxmox/debian" + apt_source_file="${File_ProxmoxSourceList}" + apt_source_content="$(gen_deb_unsrc "${source_address}/pve" "${SYSTEM_VERSION_CODENAME}" "pve-no-subscription") +$(gen_deb_unsrc_disabled "${source_address}/pbs" "${SYSTEM_VERSION_CODENAME}" "pbs-no-subscription") +$(gen_deb_unsrc_disabled "${source_address}/pbs-client" "${SYSTEM_VERSION_CODENAME}" "pbs-client-no-subscription") +$(gen_deb_unsrc_disabled "${source_address}/pmg" "${SYSTEM_VERSION_CODENAME}" "pmg-no-subscription")" + write_apt_source + if [ -s "${File_ProxmoxAPLInfo}" ]; then + sed -e "s|url => [\"']https\?://[^/]*/images[\"']|url => \"${WEB_PROTOCOL}://${SOURCE}/images\"|g" \ + -i \ + $File_ProxmoxAPLInfo + fi + fi +} + +## 更换基于 RedHat 系 Linux 发行版的软件源 +function change_mirrors_RedHat() { + ## 仅 EPEL 模式 + if [[ "${ONLY_EPEL}" == "true" ]]; then + change_mirrors_or_install_EPEL # EPEL 附加软件包 + return + fi + ## 生成 repo 源文件 + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_RHEL}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 7 | 8) + gen_repo_files_CentOS "${SYSTEM_VERSION_ID_MAJOR}" + ;; + *) + gen_repo_files_CentOSStream "${SYSTEM_VERSION_ID_MAJOR}" + ;; + esac + ;; + "${SYSTEM_CENTOS}") + gen_repo_files_CentOS "${SYSTEM_VERSION_ID_MAJOR}" + ;; + "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ORACLE}") + gen_repo_files_CentOSStream "${SYSTEM_VERSION_ID_MAJOR}" + ;; + "${SYSTEM_ROCKY}") + gen_repo_files_RockyLinux "${SYSTEM_VERSION_ID_MAJOR}" + ;; + "${SYSTEM_ALMALINUX}") + gen_repo_files_AlmaLinux "${SYSTEM_VERSION_ID_MAJOR}" + ;; + "${SYSTEM_FEDORA}") + gen_repo_files_Fedora "${SYSTEM_VERSION_ID}" + ;; + "${SYSTEM_OPENCLOUDOS}") + gen_repo_files_OpenCloudOS "${SYSTEM_VERSION_ID}" + ;; + "${SYSTEM_ANOLISOS}") + gen_repo_files_AnolisOS "${SYSTEM_VERSION_ID}" + ;; + esac + ## 使用官方源 + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_CENTOS}" ]]; then + SOURCE="vault.centos.org" + SOURCE_BRANCH="centos" + else + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ORACLE}") + if [[ "${SYSTEM_VERSION_ID_MAJOR}" == 8 ]]; then + SOURCE="vault.centos.org" + SOURCE_BRANCH="centos" + else + change_mirrors_or_install_EPEL # EPEL 附加软件包 + return + fi + ;; + *) + change_mirrors_or_install_EPEL # EPEL 附加软件包 + return + ;; + esac + fi + fi + + ## 修改源 + cd $Dir_YumRepos + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_RHEL}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 7 | 8) + sed -e "s|^#baseurl=http|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|^mirrorlist=|#mirrorlist=|g" \ + -i \ + CentOS-* + case "${SYSTEM_VERSION_ID_MAJOR}" in + 8) + sed -e "s|mirror.centos.org/\$contentdir|mirror.centos.org/${SOURCE_BRANCH}|g" \ + -e "s|\$releasever|8.5.2111|g" \ + -i \ + CentOS-* + sed -e "s|vault.centos.org/\$contentdir|vault.centos.org/${SOURCE_VAULT_BRANCH:-"centos-vault"}|g" \ + -i \ + CentOS-Linux-Sources.repo + ;; + 7) + sed -e "s|mirror.centos.org/centos|mirror.centos.org/${SOURCE_BRANCH}|g" \ + -e "s|\$releasever|7.9.2009|g" \ + -i \ + CentOS-* + sed -e "s|vault.centos.org/centos|vault.centos.org/${SOURCE_VAULT_BRANCH:-"centos-vault"}|g" \ + -i \ + CentOS-Sources.repo + ;; + esac + sed -e "s|mirror.centos.org|${SOURCE}|g" \ + -e "s|vault.centos.org|${SOURCE_VAULT:-${SOURCE}}|g" \ + -i \ + CentOS-* + ;; + *) + sed -e "s|^#baseurl=https|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|^metalink=|#metalink=|g" \ + -e "s|mirror.stream.centos.org|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + centos.repo \ + centos-addons.repo + # 禁用 GPG 签名检查 + sed -e "s|gpgcheck=1|gpgcheck=0|g" \ + -i \ + centos.repo \ + centos-addons.repo + ;; + esac + ;; + "${SYSTEM_CENTOS}") + sed -e "s|^#baseurl=http|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|^mirrorlist=|#mirrorlist=|g" \ + -i \ + CentOS-* + if [[ "${DEVICE_ARCH_RAW}" == "x86_64" ]]; then + SOURCE_BRANCH="centos-vault" + else + SOURCE_BRANCH="centos-altarch" + fi + case "${SYSTEM_VERSION_ID_MAJOR}" in + 8) + # 最终版本为 8.5.2011(2022-02) + sed -e "s|mirror.centos.org/\$contentdir|mirror.centos.org/${SOURCE_BRANCH}|g" \ + -e "s|\$releasever|8.5.2111|g" \ + -i \ + CentOS-* + sed -e "s|vault.centos.org/\$contentdir|vault.centos.org/${SOURCE_VAULT_BRANCH:-"centos-vault"}|g" \ + -i \ + CentOS-Linux-Sources.repo + ;; + 7) + # 最终版本为 7.9.2009(2024-07) + sed -e "s|mirror.centos.org/centos|mirror.centos.org/${SOURCE_BRANCH}|g" \ + -e "s|\$releasever|7.9.2009|g" \ + -i \ + CentOS-* + sed -e "s|vault.centos.org/centos|vault.centos.org/${SOURCE_VAULT_BRANCH:-"centos-vault"}|g" \ + -i \ + CentOS-Sources.repo + ;; + esac + sed -e "s|mirror.centos.org|${SOURCE}|g" \ + -e "s|vault.centos.org|${SOURCE_VAULT:-${SOURCE}}|g" \ + -i \ + CentOS-* + ;; + "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ORACLE}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 9 | 10) + sed -e "s|^#baseurl=https|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|^metalink=|#metalink=|g" \ + -e "s|mirror.stream.centos.org|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + centos.repo \ + centos-addons.repo + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_ORACLE}" ]]; then + # 禁用 GPG 签名检查 + sed -e "s|gpgcheck=1|gpgcheck=0|g" \ + -i \ + centos.repo \ + centos-addons.repo + fi + ;; + 8) + sed -e "s|^#baseurl=http|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|^mirrorlist=|#mirrorlist=|g" \ + -e "s|mirror.centos.org/\$contentdir|${SOURCE}/${SOURCE_BRANCH}|g" \ + -e "s|vault.centos.org/\$contentdir|${SOURCE_VAULT:-${SOURCE}}/${SOURCE_VAULT_BRANCH:-"centos-vault"}|g" \ + -i \ + CentOS-Stream-* + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_ORACLE}" ]]; then + # 禁用 GPG 签名检查 + sed -e "s|gpgcheck=1|gpgcheck=0|g" \ + -i \ + CentOS-Stream-* + fi + ;; + esac + ;; + "${SYSTEM_ROCKY}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 9 | 10) + sed -e "s|^#baseurl=http|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|^mirrorlist=|#mirrorlist=|g" \ + -e "s|dl.rockylinux.org/\$contentdir|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + rocky.repo \ + rocky-addons.repo \ + rocky-devel.repo \ + rocky-extras.repo + ;; + 8) + sed -e "s|^#baseurl=http|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|^mirrorlist=|#mirrorlist=|g" \ + -e "s|dl.rockylinux.org/\$contentdir|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + Rocky-* + ;; + esac + ;; + "${SYSTEM_ALMALINUX}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 10) + sed -e "s|^# baseurl=https|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|^mirrorlist=|#mirrorlist=|g" \ + -e "s|vault.almalinux.org|${SOURCE_VAULT:-${SOURCE}}/${SOURCE_VAULT_BRANCH:-"almalinux-vault"}|g" \ + -e "s|repo.almalinux.org/almalinux|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + almalinux-appstream.repo \ + almalinux-baseos.repo \ + almalinux-crb.repo \ + almalinux-extras.repo \ + almalinux-highavailability.repo \ + almalinux-nfv.repo \ + almalinux-rt.repo \ + almalinux-saphana.repo \ + almalinux-sap.repo + ;; + 9) + sed -e "s|^# baseurl=https|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|^mirrorlist=|#mirrorlist=|g" \ + -e "s|repo.almalinux.org/vault|${SOURCE_VAULT:-${SOURCE}}/${SOURCE_VAULT_BRANCH:-"almalinux-vault"}|g" \ + -e "s|repo.almalinux.org/almalinux|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + almalinux-appstream.repo \ + almalinux-baseos.repo \ + almalinux-crb.repo \ + almalinux-extras.repo \ + almalinux-highavailability.repo \ + almalinux-nfv.repo \ + almalinux-plus.repo \ + almalinux-resilientstorage.repo \ + almalinux-rt.repo \ + almalinux-sap.repo \ + almalinux-saphana.repo + ;; + 8) + sed -e "s|^mirrorlist=|#mirrorlist=|g" \ + -e "s|^# baseurl=https|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|repo.almalinux.org/vault|${SOURCE_VAULT:-${SOURCE}}/${SOURCE_VAULT_BRANCH:-"almalinux-vault"}|g" \ + -e "s|repo.almalinux.org/almalinux|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + almalinux-ha.repo \ + almalinux-nfv.repo \ + almalinux-plus.repo \ + almalinux-powertools.repo \ + almalinux-resilientstorage.repo \ + almalinux-rt.repo \ + almalinux-sap.repo \ + almalinux-saphana.repo \ + almalinux.repo + ;; + esac + ;; + "${SYSTEM_FEDORA}") + # 自 Fedora 39 起不再使用 modular 仓库 + local fedora_repo_files="fedora.repo fedora-updates.repo fedora-updates-testing.repo" + if [[ "${SYSTEM_VERSION_ID}" -lt 39 ]]; then + fedora_repo_files="${fedora_repo_files} fedora-modular.repo fedora-updates-modular.repo fedora-updates-testing-modular.repo" + fi + sed -e "s|^metalink=|#metalink=|g" \ + -e "s|^#baseurl=http|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|download.example/pub/fedora/linux|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + $fedora_repo_files + ;; + "${SYSTEM_OPENCLOUDOS}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 8) + sed -e "s|^baseurl=https|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|mirrors.opencloudos.tech/opencloudos|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + OpenCloudOS-Debuginfo.repo \ + OpenCloudOS.repo \ + OpenCloudOS-Sources.repo + ;; + esac + ;; + "${SYSTEM_ANOLISOS}") + # Anolis OS 仓库配置特殊,baseurl 同时使用 http 和 https 协议,gpgkey 同时使用软件源仓库远程路径和本地路径 + case "${SYSTEM_VERSION_ID_MAJOR}" in + 8) + sed -e "s|http\(s\)\?://mirrors.openanolis.cn/anolis|${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + AnolisOS-* + ;; + esac + ;; + esac + + ## 重置使用官方源时定义的变量 + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_CENTOS}" ]]; then + SOURCE="" + SOURCE_BRANCH="" + else + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ORACLE}") + if [[ "${SYSTEM_VERSION_ID_MAJOR}" == 8 ]]; then + SOURCE="" + SOURCE_BRANCH="" + fi + ;; + esac + fi + fi + + change_mirrors_or_install_EPEL # EPEL 附加软件包 +} + +## 更换 openEuler 软件源 +function change_mirrors_openEuler() { + ## 生成 repo 源文件 + gen_repo_files_openEuler + ## 使用官方源 + [[ "${USE_OFFICIAL_SOURCE}" == "true" ]] && return + + ## 修改源 + cd $Dir_YumRepos + sed -e "s|^baseurl=http|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|repo.openeuler.org|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + openEuler.repo +} + +## 更换 OpenCloudOS 软件源 +function change_mirrors_OpenCloudOS() { + ## 生成 repo 源文件 + gen_repo_files_OpenCloudOS "${SYSTEM_VERSION_ID}" + ## 使用官方源 + [[ "${USE_OFFICIAL_SOURCE}" == "true" ]] && return + + ## 修改源 + cd $Dir_YumRepos + if [[ "${SYSTEM_VERSION_ID}" == 23 ]]; then + sed -e "s|^baseurl=https|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|mirrors.opencloudos.tech/opencloudos-stream|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + OpenCloudOS-Stream.repo + else + sed -e "s|^baseurl=https|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|mirrors.opencloudos.tech/opencloudos|${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + OpenCloudOS.repo + fi +} + +## 更换 openKylin 软件源 +function change_mirrors_openKylin() { + local deb_src_disabled_tips="## $(msg "source.comment.disabledSourceCode")" + + function gen_deb() { + echo "deb ${WEB_PROTOCOL}://${1}/ ${2} ${3} +# deb-src ${WEB_PROTOCOL}://${1}/ ${2} ${3} +deb ${WEB_PROTOCOL}://${1}/ ${2}-security ${3} +# deb-src ${WEB_PROTOCOL}://${1}/ ${2}-security ${3} +deb ${WEB_PROTOCOL}://${1}/ ${2}-updates ${3} +# deb-src ${WEB_PROTOCOL}://${1}/ ${2}-updates ${3}" + } + + ## 使用官方源 + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="archive.build.openkylin.top" + fi + local repo_components="main cross pty" # 仓库区域 + local source_address="${SOURCE}/${SOURCE_BRANCH}" + echo "${deb_src_disabled_tips} +$(gen_deb "${source_address}" "${SYSTEM_VERSION_CODENAME}" "${repo_components}")" >>$File_AptSourceList +} + +## 更换 Anolis OS 软件源 +function change_mirrors_AnolisOS() { + ## 生成 repo 源文件 + gen_repo_files_AnolisOS "${SYSTEM_VERSION_ID}" + ## 使用官方源 + [[ "${USE_OFFICIAL_SOURCE}" == "true" ]] && return + + ## 修改源 + cd $Dir_YumRepos + # Anolis OS 仓库配置特殊,baseurl 同时使用 http 和 https 协议,gpgkey 同时使用软件源仓库远程路径和本地路径 + case "${SYSTEM_VERSION_ID_MAJOR}" in + 23) + sed -e "s|http\(s\)\?://mirrors.openanolis.cn/anolis|${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + AnolisOS-Debuginfo.repo \ + AnolisOS.repo \ + AnolisOS-Source.repo + ;; + 8) + sed -e "s|http\(s\)\?://mirrors.openanolis.cn/anolis|${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}|g" \ + -i \ + AnolisOS-* + ;; + esac +} + +## 更换 openSUSE 软件源 +function change_mirrors_openSUSE() { + ## 禁用 RIS + zypper remove -y openSUSE-repos-* >/dev/null 2>&1 + ## 生成 repo 源文件 + case "${SYSTEM_ID}" in + "opensuse-leap") + gen_repo_files_openSUSE "leap" "${SYSTEM_VERSION_ID}" + ;; + "opensuse-tumbleweed") + gen_repo_files_openSUSE "tumbleweed" + ;; + esac + ## 使用官方源 + [[ "${USE_OFFICIAL_SOURCE}" == "true" ]] && return + + ## 修改源 + cd $Dir_ZYppRepos + local -a opensuse_repo_files=() + case "${SYSTEM_ID}" in + opensuse-leap) + case "${SYSTEM_VERSION_ID_MAJOR}" in + 16) + opensuse_repo_files=( + "openSUSE:repo-non-oss-debug.repo" + "openSUSE:repo-non-oss.repo" + "openSUSE:repo-oss-debug.repo" + "openSUSE:repo-oss.repo" + "openSUSE:repo-oss-source.repo" + ) + ;; + 15) + case "${SYSTEM_VERSION_ID_MINOR}" in + [0-2]) + opensuse_repo_files=( + "repo-debug-non-oss.repo" + "repo-debug.repo" + "repo-debug-update-non-oss.repo" + "repo-debug-update.repo" + "repo-non-oss.repo" + "repo-oss.repo" + "repo-source-non-oss.repo" + "repo-source.repo" + "repo-update-non-oss.repo" + "repo-update.repo" + ) + ;; + *) + opensuse_repo_files=( + "repo-backports-debug-update.repo" + "repo-backports-update.repo" + "repo-debug-non-oss.repo" + "repo-debug.repo" + "repo-debug-update-non-oss.repo" + "repo-debug-update.repo" + "repo-non-oss.repo" + "repo-openh264.repo" + "repo-oss.repo" + "repo-sle-debug-update.repo" + "repo-sle-update.repo" + "repo-source.repo" + "repo-update-non-oss.repo" + "repo-update.repo" + ) + ;; + esac + ;; + esac + ;; + opensuse-tumbleweed) + opensuse_repo_files=( + "repo-debug.repo" + "repo-non-oss.repo" + "repo-openh264.repo" + "repo-oss.repo" + "repo-source.repo" + "repo-update.repo" + ) + ;; + esac + sed -e "s#\(baseurl\|gpgkey\)=http://\(cdn\|download\)\.opensuse\.org/\(distribution\|update\|tumbleweed\|factory\|slowroll\|history\)/#\1=${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}/\3/#g" \ + -i \ + "${opensuse_repo_files[@]}" +} + +## 更换 Arch Linux 系 Linux 发行版的软件源 +function change_mirrors_ArchLinux() { + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_ARCH}") + ## 修改源 + case "${SOURCE_BRANCH}" in + "archlinuxarm") + [[ "${USE_OFFICIAL_SOURCE}" == "true" ]] && SOURCE="mirror.archlinuxarm.org" ## 使用官方源 + echo "Server = ${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}/\$arch/\$repo" >>$File_PacmanMirrorList + ;; + *) + [[ "${USE_OFFICIAL_SOURCE}" == "true" ]] && SOURCE="mirror.pkgbuild.com" ## 使用官方源 + echo "Server = ${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}/\$repo/os/\$arch" >>$File_PacmanMirrorList + ;; + esac + ;; + "${SYSTEM_MANJARO}") + ## 使用官方源 + [[ "${USE_OFFICIAL_SOURCE}" == "true" ]] && SOURCE="mirrors2.manjaro.org" + ## 修改源 + echo "Server = ${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}/stable/\$repo/\$arch" >>$File_PacmanMirrorList + ;; + esac + # if [[ "${USE_ARCHLINUXCN_SOURCE}" == "true" ]]; then + # # /etc/pacman.conf + # [[ "${USE_OFFICIAL_SOURCE}" == "true" ]] && SOURCE="repo.archlinuxcn.org" ## 使用官方源 + # echo -e "[archlinuxcn]\nServer = ${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}/\$arch" >>/etc/pacman.conf + # fi +} + +## 更换 Alpine Linux 软件源 +function change_mirrors_Alpine() { + ## 使用官方源 + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + SOURCE="dl-cdn.alpinelinux.org" + fi + local version_name + echo "${SYSTEM_PRETTY_NAME}" | grep " edge" -q + if [ $? -eq 0 ]; then + version_name="edge" + else + version_name="v${SYSTEM_VERSION_ID%.*}" + fi + ## 修改源 + echo "${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}/${version_name}/main +${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}/${version_name}/community" >>$File_AlpineRepositories +} + +## 更换 Gentoo 软件源 +function change_mirrors_Gentoo() { + ## 使用官方源 + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + grep -Eq "^GENTOO_MIRRORS=" $File_GentooMakeConf + if [ $? -eq 0 ]; then + sed -e "/^GENTOO_MIRRORS=/d" \ + -i \ + $File_GentooMakeConf + fi + [ -f "${File_GentooReposConf}" ] && rm -rf $File_GentooReposConf + return + fi + ## 修改源 + grep -Eq "^GENTOO_MIRRORS=" $File_GentooMakeConf + if [ $? -eq 0 ]; then + sed -e "s|^GENTOO_MIRRORS=.*|GENTOO_MIRRORS=\"${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}\"|g" \ + -i \ + $File_GentooMakeConf + else + echo -e "\nGENTOO_MIRRORS=\"${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}\"" >>$File_GentooMakeConf + fi + echo "[DEFAULT] +main-repo = gentoo + +[gentoo] +location = /usr/portage +sync-type = rsync +sync-uri = rsync://${SOURCE_PORTAGE:-${SOURCE}}/${SOURCE_PORTAGE_BRANCH:-"gentoo-portage"} +auto-sync = yes" >$File_GentooReposConf +} + +## 更换 NixOS 软件源 +function change_mirrors_NixOS() { + local binary_cache_source channel_source + if [[ "${USE_OFFICIAL_SOURCE}" == "true" ]]; then + binary_cache_source="https://cache.nixos.org/" + channel_source="https://nixos.org/channels" + else + binary_cache_source="${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}/store https://cache.nixos.org/" + channel_source="${WEB_PROTOCOL}://${SOURCE}/${SOURCE_BRANCH}" + fi + # binary cache + sed -e "s|^substituters.*|substituters = ${binary_cache_source}|g" \ + -i \ + $File_NixConf + # channel + nix-channel --add "${channel_source}/nixos-${SYSTEM_VERSION_ID}" nixos + nix-channel --update >/dev/null 2>&1 +} + +## EPEL (Extra Packages for Enterprise Linux) 附加软件包 - 安装或更换软件源 +function change_mirrors_or_install_EPEL() { + if [[ "${INSTALL_EPEL}" != "true" ]]; then + return + fi + ## 确定安装版本(不支持安装的系统直接跳出此方法) + local epel_version + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_REDHAT}") + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_FEDORA}" ]]; then + return + else + epel_version="${SYSTEM_VERSION_ID_MAJOR}" + fi + ;; + *) + return + ;; + esac + ## EPEL 7 + if [[ "${epel_version}" == "7" ]]; then + [ -z "${SOURCE_EPEL_BRANCH}" ] && SOURCE_EPEL_BRANCH="epel-archive" + [[ "${PURE_MODE}" != "true" ]] && echo -e "\n$WARN $(msg "warn.EPEL7")" + [[ "${PURE_MODE}" != "true" ]] && echo -e "\n$TIP $(msg "tip.EPEL7")\n\n${GREEN}➜${PLAIN} ${WEB_PROTOCOL}://${SOURCE_EPEL:-${SOURCE}}/${SOURCE_EPEL_BRANCH:-"epel"}" + fi + ## 安装 EPEL 软件包 + if [ $VERIFICATION_EPEL -ne 0 ]; then + echo -e "\n${WORKING} $(msg "work.installEPELPackage")\n" + local package_manager="$(get_package_manager)" + local package_path="epel/epel-release-latest-${epel_version}" + case "${epel_version}" in + 7) + package_path="epel-archive/7/${DEVICE_ARCH_RAW}/Packages/e/epel-release-7-14" + ;; + 9) + ## CentOS Stream 9 特殊,有两个不同的发行包 epel-release epel-next-release + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ORACLE}" | "${SYSTEM_RHEL}") + package_path="epel/epel{,-next}-release-latest-9" + ;; + esac + ;; + esac + eval $package_manager install -y https://mirrors.cloud.tencent.com/${package_path}.noarch.rpm + rm -rf $Dir_YumRepos/epel* + fi + ## 删除原有 repo 源文件 + if [ -d "${Dir_YumRepos}" ]; then + ls $Dir_YumRepos | grep epel -q + [ $? -eq 0 ] && rm -rf $Dir_YumRepos/epel* + fi + if [ -d "${Dir_YumReposBackup}" ]; then + ls $Dir_YumReposBackup | grep epel -q + [ $? -eq 0 ] && rm -rf $Dir_YumReposBackup/epel* + fi + ## 生成 repo 源文件 + gen_repo_files_EPEL "${SYSTEM_VERSION_ID_MAJOR}" + if [[ "${epel_version}" == 9 ]]; then + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ORACLE}" | "${SYSTEM_RHEL}") + gen_repo_files_EPEL_NEXT "${SYSTEM_VERSION_ID_MAJOR}" + ;; + esac + fi + ## 使用官方源 + if [[ "${USE_OFFICIAL_SOURCE}" == "true" || "${USE_OFFICIAL_SOURCE_EPEL}" == "true" ]]; then + case "${epel_version}" in + 7) + SOURCE_EPEL="dl.fedoraproject.org/pub/archive" + ;; + *) + SOURCE_EPEL="dl.fedoraproject.org/pub" + ;; + esac + fi + ## 修改源 + sed -e "s|^#baseurl=http\(s\)\?|baseurl=${WEB_PROTOCOL}|g" \ + -e "s|^metalink=|#metalink=|g" \ + -e "s|download.example/pub/epel|${SOURCE_EPEL:-${SOURCE}}/${SOURCE_EPEL_BRANCH:-"epel"}|g" \ + -i \ + $Dir_YumRepos/epel* + ## 启用所需的仓库(EPEL 需要结合 PowerTools / CRB 使用) + case "${epel_version}" in + 9 | 10) + dnf config-manager --set-enabled crb >/dev/null 2>&1 + ;; + 8) + dnf config-manager --set-enabled powertools >/dev/null 2>&1 + ;; + esac +} + +## 选择系统包管理器 +function get_package_manager() { + local command="yum" + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_RHEL}" | "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ROCKY}" | "${SYSTEM_ALMALINUX}" | "${SYSTEM_ORACLE}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 9 | 10) + command="dnf" + ;; + esac + ;; + "${SYSTEM_FEDORA}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}") + command="dnf" + ;; + esac + echo "${command}" +} + +function interactive_select_list() { + _SELECT_RESULT="" + eval "local -a __values=(\"\${${1}[@]}\")" + local -a __labels=() + local message="${2}" + local selected=0 + local start=0 + local page_size=$(($(tput lines 2>/dev/null) - 3)) + if [[ "${3}" ]]; then + eval "__labels=(\"\${${3}[@]}\")" + fi + function clear_menu() { + tput rc 2>/dev/null + for ((i = 0; i < ${#__values[@]} + 1; i++)); do + echo -e "\r\033[K" + done + tput rc 2>/dev/null + } + function cleanup() { + clear_menu + tput rc 2>/dev/null + tput cnorm 2>/dev/null + tput rmcup 2>/dev/null + echo -e "\n\033[1;44m $(msg "interaction.common.tip") \033[0m \033[31m$(msg "interaction.common.operationCanceled")\033[0m\n" + exit 130 + } + function draw_menu() { + tput clear 2>/dev/null + tput cup 0 0 2>/dev/null + echo -e "${message}" + local end=$((start + page_size - 1)) + local label + if [ $end -ge ${#__values[@]} ]; then + end=${#__values[@]}-1 + fi + for ((i = start; i <= end; i++)); do + if [[ "${__labels[$i]}" ]]; then + label="${__labels[$i]}" + else + label="${__values[$i]}" + fi + if [ "$i" -eq "${selected}" ]; then + echo -e "\e[34;4m➤ ${label}\e[0m" + else + echo -e " ${label}" + fi + done + } + function read_key() { + IFS= read -rsn1 key + if [[ $key == $'\x1b' ]]; then + IFS= read -rsn2 key + key="$key" + fi + echo "$key" + } + tput smcup 2>/dev/null + tput sc 2>/dev/null + tput civis 2>/dev/null + trap "cleanup" INT TERM + draw_menu + while true; do + key=$(read_key) + case "$key" in + "[A" | "w" | "W") + if [ "${selected}" -gt 0 ]; then + selected=$((selected - 1)) + if [ "${selected}" -lt "$start" ]; then + start=$((start - 1)) + fi + fi + ;; + "[B" | "s" | "S") + if [ "${selected}" -lt $((${#__values[@]} - 1)) ]; then + selected=$((selected + 1)) + if [ "${selected}" -ge $((start + page_size)) ]; then + start=$((start + 1)) + fi + fi + ;; + "") + tput rmcup + break + ;; + *) ;; + esac + draw_menu + done + tput cnorm 2>/dev/null + tput rmcup 2>/dev/null + _SELECT_RESULT="${__values[${selected}]}" + if [ "${__labels[${selected}]}" ]; then + _SELECT_RESULT="${_SELECT_RESULT}@@${__labels[${selected}]}" + fi +} + +function interactive_select_boolean() { + _SELECT_RESULT="" + local selected=0 + local message="$1" + local positive_title="${2:-"$(msg "interaction.common.yes")"}" + local negative_title="${3:-"$(msg "interaction.common.no")"}" + local menu_height=3 + local original_line + function store_position() { + original_line=$(tput lines 2>/dev/null) + } + function clear_menu() { + for ((i = 0; i < $menu_height; i++)); do + tput cuu1 2>/dev/null + tput el 2>/dev/null + done + } + function cleanup() { + clear_menu + tput cnorm 2>/dev/null + echo -e "\n\033[1;44m $(msg "interaction.common.tip") \033[0m \033[31m$(msg "interaction.common.operationCanceled")\033[0m\n" + exit 130 + } + function draw_menu() { + echo -e "╭─ ${message}" + echo -e "│" + if [ "${selected}" -eq 0 ]; then + echo -e "╰─ \033[34m●\033[0m ${positive_title}\033[2m / ○ ${negative_title}\033[0m" + else + echo -e "╰─ \033[2m○ ${positive_title} / \033[0m\033[34m●\033[0m ${negative_title}" + fi + } + function read_key() { + IFS= read -rsn1 key + if [[ $key == $'\x1b' ]]; then + IFS= read -rsn2 key + key="$key" + fi + echo "$key" + } + tput civis 2>/dev/null + store_position + trap "cleanup" INT TERM + draw_menu + while true; do + key=$(read_key) + case "$key" in + "[D" | "a" | "A") + if [ "${selected}" -gt 0 ]; then + selected=$((selected - 1)) + clear_menu + draw_menu + fi + ;; + "[C" | "d" | "D") + if [ "${selected}" -lt 1 ]; then + selected=$((selected + 1)) + clear_menu + draw_menu + fi + ;; + "") + clear_menu + break + ;; + *) ;; + esac + done + echo -e "╭─ ${message}" + echo -e "│" + if [ "${selected}" -eq 0 ]; then + echo -e "╰─ \033[32m●\033[0m \033[1m${positive_title}\033[0m\033[2m / ○ ${negative_title}\033[0m" + _SELECT_RESULT="true" + else + echo -e "╰─ \033[2m○ ${positive_title} / \033[0m\033[32m●\033[0m \033[1m${negative_title}\033[0m" + _SELECT_RESULT="false" + fi + tput cnorm 2>/dev/null +} + +function animate_exec() { + local cmd="$1" + local title="$2" + local max_lines=${3:-5} + local spinner_style="${4:-dots}" + local refresh_rate="${5:-0.1}" + local scroll_mode="${6:-1}" + if [[ "${scroll_mode}" == "0" ]]; then + echo -e "◉ ${title} \n" + eval "${cmd}" + return $? + fi + local -A spinners=([dots]="⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏" [circle]="◐ ◓ ◑ ◒" [classic]="-\\ |/") + local -A recommended_rates=([dots]="0.08" [circle]="0.12" [classic]="0.12") + [[ -z "${spinners[$spinner_style]}" ]] && spinner_style="dots" + [[ "${refresh_rate}" == "0.1" ]] && refresh_rate="${recommended_rates[$spinner_style]}" + local term_width=$(tput cols 2>/dev/null || echo 80) + local display_width=$((term_width - 2)) + function simple_truncate() { + local line="$1" + local truncate_marker="..." + local max_length=$((display_width - 3)) + if [[ "${line}" =~ ^[[:ascii:]]*$ && ${#line} -le $display_width ]]; then + echo "${line}" + return + fi + local non_ascii_count=$(echo "${line}" | sed "s|[0-9a-zA-Z -~]||g; s| ||g" | wc -m) + local total_length=${#line} + local display_length=$((total_length + non_ascii_count)) + local quote_count=0 + [[ $(echo "${line}" | grep -c "“") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "“")")) + [[ $(echo "${line}" | grep -c "”") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "”")")) + [[ $(echo "${line}" | grep -c "‘") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "‘")")) + [[ $(echo "${line}" | grep -c "’") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "’")")) + display_length=$((display_length - quote_count)) + if [[ $display_length -le $display_width ]]; then + echo "$line" + return + fi + local result="" + local current_width=0 + local i=0 + while [ $i -lt ${#line} ]; do + local char="${line:$i:1}" + local char_width=1 + if ! [[ "$char" =~ [0-9a-zA-Z\.\=\:\_\(\)\'\"\-\/\!\·] ]]; then + if [[ "$char" != "“" && "$char" != "”" && "$char" != "‘" && "$char" != "’" ]]; then + char_width=2 + fi + fi + if [[ $((current_width + char_width)) -gt $max_length ]]; then + echo "${result}${truncate_marker}" + return + fi + result+="${char}" + current_width=$((current_width + char_width)) + ((i++)) + done + echo "${line}" + } + function cleanup() { + [ -f "${temp_file}" ] && rm -f "${temp_file}" + tput cnorm 2>/dev/null + echo -e "\n\033[1;44m $(msg "interaction.common.tip") \033[0m \033[31m$(msg "interaction.common.operationCanceled")\033[0m\n" + exit 130 + } + function make_temp_file() { + local -a temp_dirs=("." "/tmp") + local tmp_file="" + for dir in "${temp_dirs[@]}"; do + [[ ! -d "${dir}" || ! -w "${dir}" ]] && continue + tmp_file="${dir}/animate_exec_$$_$(date +%s)" + touch "${tmp_file}" 2>/dev/null || continue + if [[ -f "${tmp_file}" && -w "${tmp_file}" ]]; then + echo "${tmp_file}" + return + fi + done + echo "${tmp_file}" + } + function update_display() { + local current_size=$(wc -c <"${temp_file}" 2>/dev/null || echo 0) + if [[ $current_size -le $last_size ]]; then + return 1 + fi + local -a lines=() + mapfile -t -n "${max_lines}" lines < <(tail -n "$max_lines" "${temp_file}") + local -a processed_lines=() + for ((i = 0; i < ${#lines[@]}; i++)); do + processed_lines[i]=$(simple_truncate "${lines[i]}") + done + tput cud1 2>/dev/null + echo -ne "\r\033[K" + tput cud1 2>/dev/null + for ((i = 0; i < $max_lines; i++)); do + echo -ne "\r\033[K" + [[ $i -lt ${#processed_lines[@]} ]] && echo -ne "\033[2m${processed_lines[$i]}\033[0m" + [[ $i -lt $((max_lines - 1)) ]] && tput cud1 2>/dev/null + done + for ((i = 0; i < $max_lines + 1; i++)); do + tput cuu1 2>/dev/null + done + last_size=$current_size + return 0 + } + local spinner_frames=(${spinners[$spinner_style]}) + local temp_file="$(make_temp_file)" + trap "cleanup" INT TERM + tput civis 2>/dev/null + echo '' + echo '' + for ((i = 0; i < $max_lines; i++)); do + echo '' + done + eval "${cmd}" >"${temp_file}" 2>&1 & + local cmd_pid=$! + local last_size=0 + local spin_idx=0 + tput cuu $((max_lines + 2)) 2>/dev/null + sleep 0.05 + echo -ne "\r\033[K◉ ${title} [\033[1m\033[34m${spinner_frames[$spin_idx]}\033[0m]" + spin_idx=$(((spin_idx + 1) % ${#spinner_frames[@]})) + update_display + local update_count=0 + local adaptive_rate=$refresh_rate + while kill -0 $cmd_pid 2>/dev/null; do + echo -ne "\r\033[K◉ ${title} [\033[1m\033[34m${spinner_frames[$spin_idx]}\033[0m]" + spin_idx=$(((spin_idx + 1) % ${#spinner_frames[@]})) + if update_display; then + update_count=$((update_count + 1)) + if [[ $update_count -gt 5 ]]; then + adaptive_rate=$(awk "BEGIN {print $adaptive_rate * 1.5; exit}") + [[ $(awk "BEGIN {print ($adaptive_rate > 0.5); exit}") -eq 1 ]] && adaptive_rate=0.5 + update_count=0 + fi + else + update_count=0 + adaptive_rate=$refresh_rate + fi + sleep $adaptive_rate + done + wait $cmd_pid + local exit_status=$? + update_display + if [ $exit_status -eq 0 ]; then + echo -ne "\r\033[K◉ ${title} [\033[1m\033[32m✓\033[0m]\n" + else + echo -ne "\r\033[K◉ ${title} [\033[1m\033[31m✗\033[0m]\n" + fi + echo -ne "\r\033[K\n" + local actual_lines=$(wc -l <"${temp_file}" 2>/dev/null || echo 0) + [[ $actual_lines -gt $max_lines ]] && actual_lines=$max_lines + if [[ $actual_lines -gt 0 ]]; then + local -a final_lines=() + mapfile -t -n "$actual_lines" final_lines < <(tail -n "$actual_lines" "${temp_file}") + + for ((i = 0; i < actual_lines; i++)); do + local line=$(simple_truncate "${final_lines[$i]}") + echo -ne "\r\033[K\033[2m${line}\033[0m\n" + done + fi + tput cnorm 2>/dev/null + rm -f "${temp_file}" + return $exit_status +} + +############################################################################## + +## 生成 CentOS repo 源文件 +function gen_repo_files_CentOS() { + case "$1" in + 8) + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-AppStream.repo +[appstream] +name=CentOS Linux $releasever - AppStream +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=AppStream&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$releasever/AppStream/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-BaseOS.repo +[baseos] +name=CentOS Linux $releasever - BaseOS +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=BaseOS&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$releasever/BaseOS/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-ContinuousRelease.repo +[cr] +name=CentOS Linux $releasever - ContinuousRelease +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=cr&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$releasever/cr/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-Debuginfo.repo +[debuginfo] +name=CentOS Linux $releasever - Debuginfo +baseurl=http://debuginfo.centos.org/$releasever/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-Devel.repo +[devel] +name=CentOS Linux $releasever - Devel WARNING! FOR BUILDROOT USE ONLY! +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=Devel&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$releasever/Devel/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-Extras.repo +[extras] +name=CentOS Linux $releasever - Extras +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$releasever/extras/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-FastTrack.repo +[fasttrack] +name=CentOS Linux $releasever - FastTrack +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=fasttrack&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$releasever/fasttrack/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-HighAvailability.repo +[ha] +name=CentOS Linux $releasever - HighAvailability +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=HighAvailability&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$releasever/HighAvailability/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-Media.repo +[media-baseos] +name=CentOS Linux $releasever - Media - BaseOS +baseurl=file:///media/CentOS/BaseOS + file:///media/cdrom/BaseOS + file:///media/cdrecorder/BaseOS +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[media-appstream] +name=CentOS Linux $releasever - Media - AppStream +baseurl=file:///media/CentOS/AppStream + file:///media/cdrom/AppStream + file:///media/cdrecorder/AppStream +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-Plus.repo +[plus] +name=CentOS Linux $releasever - Plus +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$releasever/centosplus/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-PowerTools.repo +[powertools] +name=CentOS Linux $releasever - PowerTools +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=PowerTools&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$releasever/PowerTools/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Linux-Sources.repo +[baseos-source] +name=CentOS Linux $releasever - BaseOS - Source +baseurl=http://vault.centos.org/$contentdir/$releasever/BaseOS/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[appstream-source] +name=CentOS Linux $releasever - AppStream - Source +baseurl=http://vault.centos.org/$contentdir/$releasever/AppStream/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[extras-source] +name=CentOS Linux $releasever - Extras - Source +baseurl=http://vault.centos.org/$contentdir/$releasever/extras/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[plus-source] +name=CentOS Linux $releasever - Plus - Source +baseurl=http://vault.centos.org/$contentdir/$releasever/centosplus/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + ;; + 7) + cat <<'EOF' >$Dir_YumRepos/CentOS-Base.repo +[base] +name=CentOS-$releasever - Base +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +[updates] +name=CentOS-$releasever - Updates +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +[extras] +name=CentOS-$releasever - Extras +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +[centosplus] +name=CentOS-$releasever - Plus +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-CR.repo +[cr] +name=CentOS-$releasever - cr +baseurl=http://mirror.centos.org/centos/$releasever/cr/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 +enabled=0 +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Debuginfo.repo +[base-debuginfo] +name=CentOS-7 - Debuginfo +baseurl=http://debuginfo.centos.org/7/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-Debug-7 +enabled=0 +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-fasttrack.repo +[fasttrack] +name=CentOS-7 - fasttrack +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=fasttrack&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/fasttrack/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Media.repo +[c7-media] +name=CentOS-$releasever - Media +baseurl=file:///media/CentOS/ + file:///media/cdrom/ + file:///media/cdrecorder/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Sources.repo +[base-source] +name=CentOS-$releasever - Base Sources +baseurl=http://vault.centos.org/centos/$releasever/os/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +[updates-source] +name=CentOS-$releasever - Updates Sources +baseurl=http://vault.centos.org/centos/$releasever/updates/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +[extras-source] +name=CentOS-$releasever - Extras Sources +baseurl=http://vault.centos.org/centos/$releasever/extras/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +[centosplus-source] +name=CentOS-$releasever - Plus Sources +baseurl=http://vault.centos.org/centos/$releasever/centosplus/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 +EOF + ;; + esac +} + +## 生成 CentOS Stream repo 源文件 +function gen_repo_files_CentOSStream() { + case "$1" in + 10) + cat <<'EOF' >$Dir_YumRepos/centos.repo +[baseos] +name=CentOS Stream $releasever - BaseOS +#baseurl=https://mirror.stream.centos.org/$releasever-stream/BaseOS/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=1 + +[baseos-debuginfo] +name=CentOS Stream $releasever - BaseOS - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[baseos-source] +name=CentOS Stream $releasever - BaseOS - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[appstream] +name=CentOS Stream $releasever - AppStream +#baseurl=https://mirror.stream.centos.org/$releasever-stream/AppStream/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=1 + +[appstream-debuginfo] +name=CentOS Stream $releasever - AppStream - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[appstream-source] +name=CentOS Stream $releasever - AppStream - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[crb] +name=CentOS Stream $releasever - CRB +#baseurl=https://mirror.stream.centos.org/$releasever-stream/CRB/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-crb-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=0 + +[crb-debuginfo] +name=CentOS Stream $releasever - CRB - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-crb-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[crb-source] +name=CentOS Stream $releasever - CRB - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-crb-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 +EOF + cat <<'EOF' >$Dir_YumRepos/centos-addons.repo +[highavailability] +name=CentOS Stream $releasever - HighAvailability +#baseurl=https://mirror.stream.centos.org/$releasever-stream/HighAvailability/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-highavailability-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=0 + +[highavailability-debuginfo] +name=CentOS Stream $releasever - HighAvailability - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-highavailability-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[highavailability-source] +name=CentOS Stream $releasever - HighAvailability - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-highavailability-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[nfv] +name=CentOS Stream $releasever - NFV +#baseurl=https://mirror.stream.centos.org/$releasever-stream/NFV/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-nfv-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=0 + +[nfv-debuginfo] +name=CentOS Stream $releasever - NFV - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-nfv-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[nfv-source] +name=CentOS Stream $releasever - NFV - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-nfv-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[rt] +name=CentOS Stream $releasever - RT +#baseurl=https://mirror.stream.centos.org/$releasever-stream/RT/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-rt-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=0 + +[rt-debuginfo] +name=CentOS Stream $releasever - RT - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-rt-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[rt-source] +name=CentOS Stream $releasever - RT - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-rt-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[resilientstorage] +name=CentOS Stream $releasever - ResilientStorage +#baseurl=https://mirror.stream.centos.org/$releasever-stream/ResilientStorage/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-resilientstorage-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=0 + +[resilientstorage-debuginfo] +name=CentOS Stream $releasever - ResilientStorage - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-resilientstorage-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[resilientstorage-source] +name=CentOS Stream $releasever - ResilientStorage - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-resilientstorage-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[extras-common] +name=CentOS Stream $releasever - Extras packages +#baseurl=https://mirror.stream.centos.org/SIGs/$releasever-stream/extras/$basearch/extras-common/ +metalink=https://mirrors.centos.org/metalink?repo=centos-extras-sig-extras-common-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=1 + +[extras-common-source] +name=CentOS Stream $releasever - Extras packages - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-extras-sig-extras-common-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 +EOF + ;; + 9) + cat <<'EOF' >$Dir_YumRepos/centos.repo +[baseos] +name=CentOS Stream $releasever - BaseOS +#baseurl=https://mirror.stream.centos.org/$releasever-stream/BaseOS/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=1 + +[baseos-debug] +name=CentOS Stream $releasever - BaseOS - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[baseos-source] +name=CentOS Stream $releasever - BaseOS - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[appstream] +name=CentOS Stream $releasever - AppStream +#baseurl=https://mirror.stream.centos.org/$releasever-stream/AppStream/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=1 + +[appstream-debug] +name=CentOS Stream $releasever - AppStream - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[appstream-source] +name=CentOS Stream $releasever - AppStream - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[crb] +name=CentOS Stream $releasever - CRB +#baseurl=https://mirror.stream.centos.org/$releasever-stream/CRB/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-crb-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=0 + +[crb-debug] +name=CentOS Stream $releasever - CRB - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-crb-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[crb-source] +name=CentOS Stream $releasever - CRB - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-crb-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 +EOF + cat <<'EOF' >$Dir_YumRepos/centos-addons.repo +[highavailability] +name=CentOS Stream $releasever - HighAvailability +#baseurl=https://mirror.stream.centos.org/$releasever-stream/HighAvailability/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-highavailability-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=0 + +[highavailability-debug] +name=CentOS Stream $releasever - HighAvailability - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-highavailability-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[highavailability-source] +name=CentOS Stream $releasever - HighAvailability - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-highavailability-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[nfv] +name=CentOS Stream $releasever - NFV +#baseurl=https://mirror.stream.centos.org/$releasever-stream/NFV/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-nfv-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=0 + +[nfv-debug] +name=CentOS Stream $releasever - NFV - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-nfv-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[nfv-source] +name=CentOS Stream $releasever - NFV - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-nfv-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[rt] +name=CentOS Stream $releasever - RT +#baseurl=https://mirror.stream.centos.org/$releasever-stream/RT/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-rt-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=0 + +[rt-debug] +name=CentOS Stream $releasever - RT - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-rt-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[rt-source] +name=CentOS Stream $releasever - RT - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-rt-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[resilientstorage] +name=CentOS Stream $releasever - ResilientStorage +#baseurl=https://mirror.stream.centos.org/$releasever-stream/ResilientStorage/$basearch/os/ +metalink=https://mirrors.centos.org/metalink?repo=centos-resilientstorage-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=0 + +[resilientstorage-debug] +name=CentOS Stream $releasever - ResilientStorage - Debug +metalink=https://mirrors.centos.org/metalink?repo=centos-resilientstorage-debug-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[resilientstorage-source] +name=CentOS Stream $releasever - ResilientStorage - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-resilientstorage-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 + +[extras-common] +name=CentOS Stream $releasever - Extras packages +#baseurl=https://mirror.stream.centos.org/SIGs/$releasever-stream/extras/$basearch/extras-common/ +metalink=https://mirrors.centos.org/metalink?repo=centos-extras-sig-extras-common-$stream&arch=$basearch&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +countme=1 +enabled=1 + +[extras-common-source] +name=CentOS Stream $releasever - Extras packages - Source +metalink=https://mirrors.centos.org/metalink?repo=centos-extras-sig-extras-common-source-$stream&arch=source&protocol=https,http +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512 +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=6h +enabled=0 +EOF + ;; + 8) + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-AppStream.repo +[appstream] +name=CentOS Stream $releasever - AppStream +mirrorlist=http://mirrorlist.centos.org/?release=$stream&arch=$basearch&repo=AppStream&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$stream/AppStream/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-BaseOS.repo +[baseos] +name=CentOS Stream $releasever - BaseOS +mirrorlist=http://mirrorlist.centos.org/?release=$stream&arch=$basearch&repo=BaseOS&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$stream/BaseOS/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-Debuginfo.repo +[debuginfo] +name=CentOS Stream $releasever - Debuginfo +baseurl=http://debuginfo.centos.org/$stream/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-Extras-common.repo +[extras-common] +name=CentOS Stream $releasever - Extras common packages +mirrorlist=http://mirrorlist.centos.org/?release=$stream&arch=$basearch&repo=extras-extras-common +#baseurl=http://mirror.centos.org/$contentdir/$stream/extras/$basearch/extras-common/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-Extras.repo +[extras] +name=CentOS Stream $releasever - Extras +mirrorlist=http://mirrorlist.centos.org/?release=$stream&arch=$basearch&repo=extras&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$stream/extras/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-HighAvailability.repo +[ha] +name=CentOS Stream $releasever - HighAvailability +mirrorlist=http://mirrorlist.centos.org/?release=$stream&arch=$basearch&repo=HighAvailability&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$stream/HighAvailability/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-Media.repo +[media-baseos] +name=CentOS Stream $releasever - Media - BaseOS +baseurl=file:///media/CentOS/BaseOS + file:///media/cdrom/BaseOS + file:///media/cdrecorder/BaseOS +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[media-appstream] +name=CentOS Stream $releasever - Media - AppStream +baseurl=file:///media/CentOS/AppStream + file:///media/cdrom/AppStream + file:///media/cdrecorder/AppStream +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-NFV.repo +[nfv] +name=CentOS Stream $releasever - NFV +mirrorlist=http://mirrorlist.centos.org/?release=$stream&arch=$basearch&repo=NFV&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$stream/NFV/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-PowerTools.repo +[powertools] +name=CentOS Stream $releasever - PowerTools +mirrorlist=http://mirrorlist.centos.org/?release=$stream&arch=$basearch&repo=PowerTools&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$stream/PowerTools/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-RealTime.repo +[rt] +name=CentOS Stream $releasever - RealTime +mirrorlist=http://mirrorlist.centos.org/?release=$stream&arch=$basearch&repo=RT&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$stream/RT/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-ResilientStorage.repo +[resilientstorage] +name=CentOS Stream $releasever - ResilientStorage +mirrorlist=http://mirrorlist.centos.org/?release=$stream&arch=$basearch&repo=ResilientStorage&infra=$infra +#baseurl=http://mirror.centos.org/$contentdir/$stream/ResilientStorage/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + cat <<'EOF' >$Dir_YumRepos/CentOS-Stream-Sources.repo +[baseos-source] +name=CentOS Stream $releasever - BaseOS - Source +baseurl=http://vault.centos.org/$contentdir/$stream/BaseOS/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[appstream-source] +name=CentOS Stream $releasever - AppStream - Source +baseurl=http://vault.centos.org/$contentdir/$stream/AppStream/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[powertools-source] +name=CentOS Stream $releasever - PowerTools - Source +baseurl=http://vault.centos.org/$contentdir/$stream/PowerTools/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[extras-source] +name=CentOS Stream $releasever - Extras - Source +baseurl=http://vault.centos.org/$contentdir/$stream/extras/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[ha-source] +name=CentOS Stream $releasever - HighAvailability - Source +baseurl=http://vault.centos.org/$contentdir/$stream/HighAvailability/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[rt-source] +name=CentOS Stream $releasever - RT - Source +baseurl=http://vault.centos.org/$contentdir/$stream/RT/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[resilientstorage-source] +name=CentOS Stream $releasever - ResilientStorage - Source +baseurl=http://vault.centos.org/$contentdir/$stream/ResilientStorage/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[nfv-source] +name=CentOS Stream $releasever - NFV - Source +baseurl=http://vault.centos.org/$contentdir/$stream/NFV/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +EOF + ;; + esac +} + +## 生成 Rocky Linux repo 源文件 +function gen_repo_files_RockyLinux() { + case "$1" in + 10) + cat <<'EOF' >$Dir_YumRepos/rocky.repo +[baseos] +name=Rocky Linux $releasever - BaseOS +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/$basearch/os/ +gpgcheck=1 +enabled=1 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[baseos-debuginfo] +name=Rocky Linux $releasever - BaseOS - Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[baseos-source] +name=Rocky Linux $releasever - BaseOS - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=BaseOS-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[appstream] +name=Rocky Linux $releasever - AppStream +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=AppStream-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/AppStream/$basearch/os/ +gpgcheck=1 +enabled=1 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[appstream-debuginfo] +name=Rocky Linux $releasever - AppStream - Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=AppStream-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/AppStream/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[appstream-source] +name=Rocky Linux $releasever - AppStream - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=AppStream-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/AppStream/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[crb] +name=Rocky Linux $releasever - CRB +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=CRB-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/CRB/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[crb-debuginfo] +name=Rocky Linux $releasever - CRB - Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=CRB-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/CRB/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[crb-source] +name=Rocky Linux $releasever - CRB - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=CRB-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/CRB/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 +EOF + cat <<'EOF' >$Dir_YumRepos/rocky-addons.repo +[highavailability] +name=Rocky Linux $releasever - High Availability +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=HighAvailability-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/HighAvailability/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[highavailability-debuginfo] +name=Rocky Linux $releasever - High Availability - Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=HighAvailability-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/HighAvailability/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[highavailability-source] +name=Rocky Linux $releasever - High Availability - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=HighAvailability-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/HighAvailability/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[nfv] +name=Rocky Linux $releasever - NFV +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=NFV-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/NFV/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[nfv-debuginfo] +name=Rocky Linux $releasever - NFV Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=RT-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/NFV/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[nfv-source] +name=Rocky Linux $releasever - NFV Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=RT-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/NFV/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[rt] +name=Rocky Linux $releasever - Realtime +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=RT-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/RT/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[rt-debuginfo] +name=Rocky Linux $releasever - Realtime Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=RT-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/RT/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[rt-source] +name=Rocky Linux $releasever - Realtime Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=RT-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/RT/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[sap] +name=Rocky Linux $releasever - SAP +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAP-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAP/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[sap-debuginfo] +name=Rocky Linux $releasever - SAP Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAP-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAP/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[sap-source] +name=Rocky Linux $releasever - SAP Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAP-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAP/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[saphana] +name=Rocky Linux $releasever - SAPHANA +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAPHANA-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAPHANA/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[saphana-debuginfo] +name=Rocky Linux $releasever - SAPHANA Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAPHANA-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAPHANA/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[saphana-source] +name=Rocky Linux $releasever - SAPHANA Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAPHANA-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAPHANA/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 +EOF + cat <<'EOF' >$Dir_YumRepos/rocky-devel.repo +[devel] +name=Rocky Linux $releasever - Devel WARNING! FOR BUILDROOT ONLY DO NOT LEAVE ENABLED +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=devel-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/devel/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[devel-debuginfo] +name=Rocky Linux $releasever - Devel Debug WARNING! FOR BUILDROOT ONLY DO NOT LEAVE ENABLED +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=devel-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/devel/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[devel-source] +name=Rocky Linux $releasever - Devel Source WARNING! FOR BUILDROOT ONLY DO NOT LEAVE ENABLED +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=devel-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/devel/source/tree/ +gpgcheck=1 +enabled=0 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 +EOF + cat <<'EOF' >$Dir_YumRepos/rocky-extras.repo +[extras] +name=Rocky Linux $releasever - Extras +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=extras-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/extras/$basearch/os/ +gpgcheck=1 +enabled=1 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[extras-debuginfo] +name=Rocky Linux $releasever - Extras Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=extras-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/extras/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[extras-source] +name=Rocky Linux $releasever - Extras Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=extras-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/extras/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[plus] +name=Rocky Linux $releasever - Plus +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=plus-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/plus/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[plus-debuginfo] +name=Rocky Linux $releasever - Plus - Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=plus-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/plus/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 + +[plus-source] +name=Rocky Linux $releasever - Plus - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=plus-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/plus/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-10 +EOF + ;; + 9) + cat <<'EOF' >$Dir_YumRepos/rocky.repo +[baseos] +name=Rocky Linux $releasever - BaseOS +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/$basearch/os/ +gpgcheck=1 +enabled=1 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[baseos-debug] +name=Rocky Linux $releasever - BaseOS - Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[baseos-source] +name=Rocky Linux $releasever - BaseOS - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=BaseOS-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[appstream] +name=Rocky Linux $releasever - AppStream +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=AppStream-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/AppStream/$basearch/os/ +gpgcheck=1 +enabled=1 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[appstream-debug] +name=Rocky Linux $releasever - AppStream - Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=AppStream-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/AppStream/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[appstream-source] +name=Rocky Linux $releasever - AppStream - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=AppStream-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/AppStream/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[crb] +name=Rocky Linux $releasever - CRB +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=CRB-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/CRB/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[crb-debug] +name=Rocky Linux $releasever - CRB - Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=CRB-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/CRB/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[crb-source] +name=Rocky Linux $releasever - CRB - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=CRB-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/CRB/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 +EOF + cat <<'EOF' >$Dir_YumRepos/rocky-addons.repo +[highavailability] +name=Rocky Linux $releasever - High Availability +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=HighAvailability-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/HighAvailability/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[highavailability-debug] +name=Rocky Linux $releasever - High Availability - Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=HighAvailability-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/HighAvailability/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[highavailability-source] +name=Rocky Linux $releasever - High Availability - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=HighAvailability-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/HighAvailability/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[resilientstorage] +name=Rocky Linux $releasever - Resilient Storage +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=ResilientStorage-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/ResilientStorage/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[resilientstorage-debug] +name=Rocky Linux $releasever - Resilient Storage - Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=ResilientStorage-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/ResilientStorage/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[resilientstorage-source] +name=Rocky Linux $releasever - Resilient Storage - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=ResilientStorage-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/ResilientStorage/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[nfv] +name=Rocky Linux $releasever - NFV +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=NFV-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/NFV/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[nfv-debug] +name=Rocky Linux $releasever - NFV Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=RT-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/NFV/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[nfv-source] +name=Rocky Linux $releasever - NFV Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=RT-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/NFV/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[rt] +name=Rocky Linux $releasever - Realtime +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=RT-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/RT/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[rt-debug] +name=Rocky Linux $releasever - Realtime Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=RT-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/RT/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[rt-source] +name=Rocky Linux $releasever - Realtime Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=RT-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/RT/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[sap] +name=Rocky Linux $releasever - SAP +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAP-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAP/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[sap-debug] +name=Rocky Linux $releasever - SAP Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAP-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAP/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[sap-source] +name=Rocky Linux $releasever - SAP Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAP-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAP/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[saphana] +name=Rocky Linux $releasever - SAPHANA +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAPHANA-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAPHANA/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[saphana-debug] +name=Rocky Linux $releasever - SAPHANA Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAPHANA-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAPHANA/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[saphana-source] +name=Rocky Linux $releasever - SAPHANA Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=SAPHANA-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/SAPHANA/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 +EOF + cat <<'EOF' >$Dir_YumRepos/rocky-devel.repo +[devel] +name=Rocky Linux $releasever - Devel WARNING! FOR BUILDROOT ONLY DO NOT LEAVE ENABLED +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=devel-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/devel/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 +EOF + cat <<'EOF' >$Dir_YumRepos/rocky-extras.repo +[extras] +name=Rocky Linux $releasever - Extras +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=extras-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/extras/$basearch/os/ +gpgcheck=1 +enabled=1 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[extras-debug] +name=Rocky Linux $releasever - Extras Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=extras-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/extras/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[extras-source] +name=Rocky Linux $releasever - Extras Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=extras-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/extras/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[plus] +name=Rocky Linux $releasever - Plus +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=plus-$releasever$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/plus/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[plus-debug] +name=Rocky Linux $releasever - Plus - Debug +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=plus-$releasever-debug$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/plus/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 + +[plus-source] +name=Rocky Linux $releasever - Plus - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=plus-$releasever-source$rltype +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/plus/source/tree/ +gpgcheck=1 +enabled=0 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 +EOF + ;; + 8) + cat <<'EOF' >$Dir_YumRepos/Rocky-AppStream.repo +[appstream] +name=Rocky Linux $releasever - AppStream +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=AppStream-$releasever +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/AppStream/$basearch/os/ +gpgcheck=1 +enabled=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-BaseOS.repo +[baseos] +name=Rocky Linux $releasever - BaseOS +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/$basearch/os/ +gpgcheck=1 +enabled=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-Debuginfo.repo +[baseos-debug] +name=Rocky Linux $releasever - BaseOS - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever-debug +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial + +[appstream-debug] +name=Rocky Linux $releasever - AppStream - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=AppStream-$releasever-debug +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/AppStream/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial + +[ha-debug] +name=Rocky Linux $releasever - High Availability - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=HighAvailability-$releasever-debug +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/HighAvailability/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial + +[powertools-debug] +name=Rocky Linux $releasever - PowerTools - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=PowerTools-$releasever-debug +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/PowerTools/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial + +[resilient-storage-debug] +name=Rocky Linux $releasever - Resilient Storage - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=ResilientStorage-$releasever-debug +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/ResilientStorage/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-Devel.repo +[devel] +name=Rocky Linux $releasever - Devel WARNING! FOR BUILDROOT AND KOJI USE +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=Devel-$releasever +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/Devel/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-Extras.repo +[extras] +name=Rocky Linux $releasever - Extras +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=extras-$releasever +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/extras/$basearch/os/ +gpgcheck=1 +enabled=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-HighAvailability.repo +[ha] +name=Rocky Linux $releasever - HighAvailability +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=HighAvailability-$releasever +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/HighAvailability/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-Media.repo +[media-baseos] +name=Rocky Linux $releasever - Media - BaseOS +baseurl=file:///media/Rocky/BaseOS + file:///media/cdrom/BaseOS + file:///media/cdrecorder/BaseOS +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial + +[media-appstream] +name=Rocky Linux $releasever - Media - AppStream +baseurl=file:///media/Rocky/AppStream + file:///media/cdrom/AppStream + file:///media/cdrecorder/AppStream +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-NFV.repo +[nfv] +name=Rocky Linux $releasever - NFV +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=NFV-$releasever +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/nfv/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-Plus.repo +[plus] +name=Rocky Linux $releasever - Plus +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=rockyplus-$releasever +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/plus/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-PowerTools.repo +[powertools] +name=Rocky Linux $releasever - PowerTools +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=PowerTools-$releasever +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/PowerTools/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-ResilientStorage.repo +[resilient-storage] +name=Rocky Linux $releasever - ResilientStorage +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=ResilientStorage-$releasever +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/ResilientStorage/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-RT.repo +[rt] +name=Rocky Linux $releasever - Realtime +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=RT-$releasever +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/RT/$basearch/os/ +gpgcheck=1 +enabled=0 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + cat <<'EOF' >$Dir_YumRepos/Rocky-Sources.repo +[baseos-source] +name=Rocky Linux $releasever - BaseOS - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=BaseOS-$releasever-source +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial + +[appstream-source] +name=Rocky Linux $releasever - AppStream - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=AppStream-$releasever-source +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/AppStream/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial + +#[extras-source] +#name=Rocky Linux $releasever - Extras - Source +#mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=extras-$releasever-source +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/extras/source/tree/ +#gpgcheck=1 +#enabled=0 +#gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial + +#[plus-source] +#name=Rocky Linux $releasever - Plus - Source +#mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=plus-$releasever-source +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/Plus/source/tree/ +#gpgcheck=1 +#enabled=0 +#gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial + +[ha-source] +name=Rocky Linux $releasever - High Availability - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=HighAvailability-$releasever-source +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/HighAvailability/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial + +[powertools-source] +name=Rocky Linux $releasever - PowerTools - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=PowerTools-$releasever-source +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/PowerTools/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial + +[resilient-storage-source] +name=Rocky Linux $releasever - Resilient Storage - Source +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=source&repo=ResilientStorage-$releasever-source +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/ResilientStorage/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +EOF + ;; + esac +} + +## 生成 AlmaLinux repo 源文件 +function gen_repo_files_AlmaLinux() { + case "$1" in + 10) + cat <<'EOF' >$Dir_YumRepos/almalinux-appstream.repo +[appstream] +name=AlmaLinux $releasever - AppStream +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/appstream +# baseurl=https://repo.almalinux.org/almalinux/$releasever/AppStream/$basearch/os/ +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=1 + +[appstream-debuginfo] +name=AlmaLinux $releasever - AppStream - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/appstream-debug +# baseurl=https://vault.almalinux.org/$releasever/AppStream/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[appstream-source] +name=AlmaLinux $releasever - AppStream - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/appstream-source +# baseurl=https://vault.almalinux.org/$releasever/AppStream/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-baseos.repo +[baseos] +name=AlmaLinux $releasever - BaseOS +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos +# baseurl=https://repo.almalinux.org/almalinux/$releasever/BaseOS/$basearch/os/ +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=1 + +[baseos-debuginfo] +name=AlmaLinux $releasever - BaseOS - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos-debug +# baseurl=https://vault.almalinux.org/$releasever/BaseOS/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[baseos-source] +name=AlmaLinux $releasever - BaseOS - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos-source +# baseurl=https://vault.almalinux.org/$releasever/BaseOS/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-crb.repo +[crb] +name=AlmaLinux $releasever - CRB +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/crb +# baseurl=https://repo.almalinux.org/almalinux/$releasever/CRB/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[crb-debuginfo] +name=AlmaLinux $releasever - CRB - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/crb-debug +# baseurl=https://vault.almalinux.org/$releasever/CRB/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[crb-source] +name=AlmaLinux $releasever - CRB - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/crb-source +# baseurl=https://vault.almalinux.org/$releasever/CRB/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-extras.repo +[extras] +name=AlmaLinux $releasever - Extras +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/extras +# baseurl=https://repo.almalinux.org/almalinux/$releasever/extras/$basearch/os/ +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[extras-debuginfo] +name=AlmaLinux $releasever - Extras - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/extras-debug +# baseurl=https://vault.almalinux.org/$releasever/extras/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[extras-source] +name=AlmaLinux $releasever - Extras - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/extras-source +# baseurl=https://vault.almalinux.org/$releasever/extras/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-highavailability.repo +[highavailability] +name=AlmaLinux $releasever - HighAvailability +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/highavailability +# baseurl=https://repo.almalinux.org/almalinux/$releasever/HighAvailability/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[highavailability-debuginfo] +name=AlmaLinux $releasever - HighAvailability - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/highavailability-debug +# baseurl=https://vault.almalinux.org/$releasever/HighAvailability/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[highavailability-source] +name=AlmaLinux $releasever - HighAvailability - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/highavailability-source +# baseurl=https://vault.almalinux.org/$releasever/HighAvailability/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-nfv.repo +[nfv] +name=AlmaLinux $releasever - NFV +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/nfv +# baseurl=https://repo.almalinux.org/almalinux/$releasever/NFV/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[nfv-debuginfo] +name=AlmaLinux $releasever - NFV - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/nfv-debug +# baseurl=https://vault.almalinux.org/$releasever/NFV/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[nfv-source] +name=AlmaLinux $releasever - NFV - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/nfv-source +# baseurl=https://vault.almalinux.org/$releasever/NFV/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-rt.repo +[rt] +name=AlmaLinux $releasever - RT +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/rt +# baseurl=https://repo.almalinux.org/almalinux/$releasever/RT/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[rt-debuginfo] +name=AlmaLinux $releasever - RT - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/rt-debug +# baseurl=https://vault.almalinux.org/$releasever/RT/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[rt-source] +name=AlmaLinux $releasever - RT - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/rt-source +# baseurl=https://vault.almalinux.org/$releasever/RT/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-saphana.repo +[saphana] +name=AlmaLinux $releasever - SAPHANA +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/saphana +# baseurl=https://repo.almalinux.org/almalinux/$releasever/SAPHANA/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[saphana-debuginfo] +name=AlmaLinux $releasever - SAPHANA - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/saphana-debug +# baseurl=https://vault.almalinux.org/$releasever/SAPHANA/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[saphana-source] +name=AlmaLinux $releasever - SAPHANA - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/saphana-source +# baseurl=https://vault.almalinux.org/$releasever/SAPHANA/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-sap.repo +[sap] +name=AlmaLinux $releasever - SAP +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/sap +# baseurl=https://repo.almalinux.org/almalinux/$releasever/SAP/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[sap-debuginfo] +name=AlmaLinux $releasever - SAP - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/sap-debug +# baseurl=https://vault.almalinux.org/$releasever/SAP/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 + +[sap-source] +name=AlmaLinux $releasever - SAP - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/sap-source +# baseurl=https://vault.almalinux.org/$releasever/SAP/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-10 +metadata_expire=86400 +enabled_metadata=0 +EOF + ;; + 9) + cat <<'EOF' >$Dir_YumRepos/almalinux-appstream.repo +[appstream] +name=AlmaLinux $releasever - AppStream +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/appstream +# baseurl=https://repo.almalinux.org/almalinux/$releasever/AppStream/$basearch/os/ +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=1 + +[appstream-debug] +name=AlmaLinux $releasever - AppStream - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/appstream-debug +# baseurl=https://repo.almalinux.org/vault/$releasever/AppStream/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[appstream-source] +name=AlmaLinux $releasever - AppStream - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/appstream-source +# baseurl=https://repo.almalinux.org/vault/$releasever/AppStream/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-baseos.repo +[baseos] +name=AlmaLinux $releasever - BaseOS +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos +# baseurl=https://repo.almalinux.org/almalinux/$releasever/BaseOS/$basearch/os/ +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=1 + +[baseos-debug] +name=AlmaLinux $releasever - BaseOS - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos-debug +# baseurl=https://repo.almalinux.org/vault/$releasever/BaseOS/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[baseos-source] +name=AlmaLinux $releasever - BaseOS - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos-source +# baseurl=https://repo.almalinux.org/vault/$releasever/BaseOS/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-crb.repo +[crb] +name=AlmaLinux $releasever - CRB +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/crb +# baseurl=https://repo.almalinux.org/almalinux/$releasever/CRB/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[crb-debug] +name=AlmaLinux $releasever - CRB - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/crb-debug +# baseurl=https://repo.almalinux.org/vault/$releasever/CRB/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[crb-source] +name=AlmaLinux $releasever - CRB - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/crb-source +# baseurl=https://repo.almalinux.org/vault/$releasever/CRB/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-extras.repo +[extras] +name=AlmaLinux $releasever - Extras +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/extras +# baseurl=https://repo.almalinux.org/almalinux/$releasever/extras/$basearch/os/ +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[extras-debug] +name=AlmaLinux $releasever - Extras - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/extras-debug +# baseurl=https://repo.almalinux.org/vault/$releasever/extras/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[extras-source] +name=AlmaLinux $releasever - Extras - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/extras-source +# baseurl=https://repo.almalinux.org/vault/$releasever/extras/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-highavailability.repo +[highavailability] +name=AlmaLinux $releasever - HighAvailability +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/highavailability +# baseurl=https://repo.almalinux.org/almalinux/$releasever/HighAvailability/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[highavailability-debug] +name=AlmaLinux $releasever - HighAvailability - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/highavailability-debug +# baseurl=https://repo.almalinux.org/vault/$releasever/HighAvailability/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[highavailability-source] +name=AlmaLinux $releasever - HighAvailability - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/highavailability-source +# baseurl=https://repo.almalinux.org/vault/$releasever/HighAvailability/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-nfv.repo +[nfv] +name=AlmaLinux $releasever - NFV +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/nfv +# baseurl=https://repo.almalinux.org/almalinux/$releasever/NFV/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[nfv-debug] +name=AlmaLinux $releasever - NFV - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/nfv-debug +# baseurl=https://repo.almalinux.org/vault/$releasever/NFV/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[nfv-source] +name=AlmaLinux $releasever - NFV - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/nfv-source +# baseurl=https://repo.almalinux.org/vault/$releasever/NFV/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-plus.repo +[plus] +name=AlmaLinux $releasever - Plus +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/plus +# baseurl=https://repo.almalinux.org/almalinux/$releasever/plus/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[plus-debug] +name=AlmaLinux $releasever - Plus - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/plus-debug +# baseurl=https://repo.almalinux.org/vault/$releasever/plus/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[plus-source] +name=AlmaLinux $releasever - Plus - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/plus-source +# baseurl=https://repo.almalinux.org/vault/$releasever/plus/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-resilientstorage.repo +[resilientstorage] +name=AlmaLinux $releasever - ResilientStorage +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/resilientstorage +# baseurl=https://repo.almalinux.org/almalinux/$releasever/ResilientStorage/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[resilientstorage-debug] +name=AlmaLinux $releasever - ResilientStorage - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/resilientstorage-debug +# baseurl=https://repo.almalinux.org/vault/$releasever/ResilientStorage/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[resilientstorage-source] +name=AlmaLinux $releasever - ResilientStorage - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/resilientstorage-source +# baseurl=https://repo.almalinux.org/vault/$releasever/ResilientStorage/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-rt.repo +[rt] +name=AlmaLinux $releasever - RT +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/rt +# baseurl=https://repo.almalinux.org/almalinux/$releasever/RT/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[rt-debug] +name=AlmaLinux $releasever - RT - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/rt-debug +# baseurl=https://repo.almalinux.org/vault/$releasever/RT/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[rt-source] +name=AlmaLinux $releasever - RT - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/rt-source +# baseurl=https://repo.almalinux.org/vault/$releasever/RT/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-sap.repo +[sap] +name=AlmaLinux $releasever - SAP +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/sap +# baseurl=https://repo.almalinux.org/almalinux/$releasever/SAP/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[sap-debug] +name=AlmaLinux $releasever - SAP - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/sap-debug +# baseurl=https://repo.almalinux.org/vault/$releasever/SAP/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[sap-source] +name=AlmaLinux $releasever - SAP - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/sap-source +# baseurl=https://repo.almalinux.org/vault/$releasever/SAP/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-saphana.repo +[saphana] +name=AlmaLinux $releasever - SAPHANA +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/saphana +# baseurl=https://repo.almalinux.org/almalinux/$releasever/SAPHANA/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[saphana-debug] +name=AlmaLinux $releasever - SAPHANA - Debug +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/saphana-debug +# baseurl=https://repo.almalinux.org/vault/$releasever/SAPHANA/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 + +[saphana-source] +name=AlmaLinux $releasever - SAPHANA - Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/saphana-source +# baseurl=https://repo.almalinux.org/vault/$releasever/SAPHANA/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9 +metadata_expire=86400 +enabled_metadata=0 +EOF + ;; + 8) + cat <<'EOF' >$Dir_YumRepos/almalinux-ha.repo +[ha] +name=AlmaLinux $releasever - HighAvailability +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/ha +# baseurl=https://repo.almalinux.org/almalinux/$releasever/HighAvailability/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[ha-source] +name=AlmaLinux $releasever - HighAvailability Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/ha-source +# baseurl=https://repo.almalinux.org/vault/$releasever/HighAvailability/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[ha-debuginfo] +name=AlmaLinux $releasever - HighAvailability debuginfo +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/ha-debuginfo +# baseurl=https://repo.almalinux.org/vault/$releasever/HighAvailability/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-nfv.repo +[nfv] +name=AlmaLinux $releasever - Real Time for NFV +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/nfv +# baseurl=https://repo.almalinux.org/almalinux/$releasever/NFV/$basearch/os/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[nfv-source] +name=AlmaLinux $releasever - Real Time for NFV Sources +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/nfv-source +# baseurl=https://repo.almalinux.org/vault/$releasever/NFV/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[nfv-debuginfo] +name=AlmaLinux $releasever - Real Time for NFV Debuginfo +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/nfv-debuginfo +# baseurl=https://repo.almalinux.org/vault/$releasever/NFV/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-plus.repo +[plus] +name=AlmaLinux $releasever - Plus +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/plus +# baseurl=https://repo.almalinux.org/almalinux/$releasever/plus/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[plus-source] +name=AlmaLinux $releasever - Plus Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/plus-source +# baseurl=https://repo.almalinux.org/vault/$releasever/plus/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[plus-debuginfo] +name=AlmaLinux $releasever - Plus debuginfo +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/plus-debuginfo +# baseurl=https://repo.almalinux.org/vault/$releasever/plus/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-powertools.repo +[powertools] +name=AlmaLinux $releasever - PowerTools +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/powertools +# baseurl=https://repo.almalinux.org/almalinux/$releasever/PowerTools/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[powertools-source] +name=AlmaLinux $releasever - PowerTools Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/powertools-source +# baseurl=https://repo.almalinux.org/vault/$releasever/PowerTools/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[powertools-debuginfo] +name=AlmaLinux $releasever - PowerTools debuginfo +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/powertools-debuginfo +# baseurl=https://repo.almalinux.org/vault/$releasever/PowerTools/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-resilientstorage.repo +[resilientstorage] +name=AlmaLinux $releasever - ResilientStorage +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/resilientstorage +# baseurl=https://repo.almalinux.org/almalinux/$releasever/ResilientStorage/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[resilientstorage-source] +name=AlmaLinux $releasever - ResilientStorage Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/resilientstorage-source +# baseurl=https://repo.almalinux.org/vault/$releasever/ResilientStorage/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[resilientstorage-debuginfo] +name=AlmaLinux $releasever - ResilientStorage debuginfo +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/resilientstorage-debuginfo +# baseurl=https://repo.almalinux.org/vault/$releasever/ResilientStorage/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-rt.repo +[rt] +name=AlmaLinux $releasever - Real Time +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/rt +# baseurl=https://repo.almalinux.org/almalinux/$releasever/RT/$basearch/os/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[rt-source] +name=AlmaLinux $releasever - Real Time Sources +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/rt-source +# baseurl=https://repo.almalinux.org/vault/$releasever/RT/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[rt-debuginfo] +name=AlmaLinux $releasever - Real Time Debuginfo +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/rt-debuginfo +# baseurl=https://repo.almalinux.org/vault/$releasever/RT/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-sap.repo +[sap] +name=AlmaLinux $releasever - SAP +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/sap +# baseurl=https://repo.almalinux.org/almalinux/$releasever/SAP/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[sap-source] +name=AlmaLinux $releasever - SAP Sources +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/sap-source +# baseurl=https://repo.almalinux.org/vault/$releasever/SAP/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[sap-debuginfo] +name=AlmaLinux $releasever - SAP Debuginfo +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/sap-debuginfo +# baseurl=https://repo.almalinux.org/vault/$releasever/SAP/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux-saphana.repo +[saphana] +name=AlmaLinux $releasever - SAP HANA +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/saphana +# baseurl=https://repo.almalinux.org/almalinux/$releasever/SAPHANA/$basearch/os/ +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[saphana-source] +name=AlmaLinux $releasever - SAP HANA Sources +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/saphana-source +# baseurl=https://repo.almalinux.org/vault/$releasever/SAPHANA/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[saphana-debuginfo] +name=AlmaLinux $releasever - SAP HANA Debuginfo +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/saphana-debuginfo +# baseurl=https://repo.almalinux.org/vault/$releasever/SAPHANA/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux +EOF + cat <<'EOF' >$Dir_YumRepos/almalinux.repo +[baseos] +name=AlmaLinux $releasever - BaseOS +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos +# baseurl=https://repo.almalinux.org/almalinux/$releasever/BaseOS/$basearch/os/ +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[appstream] +name=AlmaLinux $releasever - AppStream +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/appstream +# baseurl=https://repo.almalinux.org/almalinux/$releasever/AppStream/$basearch/os/ +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[extras] +name=AlmaLinux $releasever - Extras +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/extras +# baseurl=https://repo.almalinux.org/almalinux/$releasever/extras/$basearch/os/ +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[baseos-source] +name=AlmaLinux $releasever - BaseOS Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos-source +# baseurl=https://repo.almalinux.org/vault/$releasever/BaseOS/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[appstream-source] +name=AlmaLinux $releasever - AppStream Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/appstream-source +# baseurl=https://repo.almalinux.org/vault/$releasever/AppStream/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[extras-source] +name=AlmaLinux $releasever - Extras Source +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/extras-source +# baseurl=https://repo.almalinux.org/vault/$releasever/extras/Source/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[baseos-debuginfo] +name=AlmaLinux $releasever - BaseOS debuginfo +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos-debuginfo +# baseurl=https://repo.almalinux.org/vault/$releasever/BaseOS/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[appstream-debuginfo] +name=AlmaLinux $releasever - AppStream debuginfo +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/appstream-debuginfo +# baseurl=https://repo.almalinux.org/vault/$releasever/AppStream/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux + +[extras-debuginfo] +name=AlmaLinux $releasever - Extras debuginfo +mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/extras-debuginfo +# baseurl=https://repo.almalinux.org/vault/$releasever/extras/debug/$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux +EOF + ;; + esac +} + +## 生成 Fedora repo 源文件 +function gen_repo_files_Fedora() { + cat <<'EOF' >$Dir_YumRepos/fedora.repo +[fedora] +name=Fedora $releasever - $basearch +#baseurl=http://download.example/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch +enabled=1 +countme=1 +metadata_expire=7d +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[fedora-debuginfo] +name=Fedora $releasever - $basearch - Debug +#baseurl=http://download.example/pub/fedora/linux/releases/$releasever/Everything/$basearch/debug/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-debug-$releasever&arch=$basearch +enabled=0 +metadata_expire=7d +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[fedora-source] +name=Fedora $releasever - Source +#baseurl=http://download.example/pub/fedora/linux/releases/$releasever/Everything/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-source-$releasever&arch=$basearch +enabled=0 +metadata_expire=7d +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False +EOF + cat <<'EOF' >$Dir_YumRepos/fedora-updates.repo +[updates] +name=Fedora $releasever - $basearch - Updates +#baseurl=http://download.example/pub/fedora/linux/updates/$releasever/Everything/$basearch/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-f$releasever&arch=$basearch +enabled=1 +countme=1 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[updates-debuginfo] +name=Fedora $releasever - $basearch - Updates - Debug +#baseurl=http://download.example/pub/fedora/linux/updates/$releasever/Everything/$basearch/debug/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-debug-f$releasever&arch=$basearch +enabled=0 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[updates-source] +name=Fedora $releasever - Updates Source +#baseurl=http://download.example/pub/fedora/linux/updates/$releasever/Everything/SRPMS/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-source-f$releasever&arch=$basearch +enabled=0 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False +EOF + cat <<'EOF' >$Dir_YumRepos/fedora-updates-testing.repo +[updates-testing] +name=Fedora $releasever - $basearch - Test Updates +#baseurl=http://download.example/pub/fedora/linux/updates/testing/$releasever/Everything/$basearch/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-testing-f$releasever&arch=$basearch +enabled=0 +countme=1 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[updates-testing-debuginfo] +name=Fedora $releasever - $basearch - Test Updates Debug +#baseurl=http://download.example/pub/fedora/linux/updates/testing/$releasever/Everything/$basearch/debug/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-testing-debug-f$releasever&arch=$basearch +enabled=0 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[updates-testing-source] +name=Fedora $releasever - Test Updates Source +#baseurl=http://download.example/pub/fedora/linux/updates/testing/$releasever/Everything/SRPMS/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-testing-source-f$releasever&arch=$basearch +enabled=0 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False +EOF + ## 自 Fedora 39 起不再使用 modular 仓库 + if [[ $1 -lt 39 ]]; then + cat <<'EOF' >$Dir_YumRepos/fedora-modular.repo +[fedora-modular] +name=Fedora Modular $releasever - $basearch +#baseurl=http://download.example/pub/fedora/linux/releases/$releasever/Modular/$basearch/os/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-modular-$releasever&arch=$basearch +enabled=1 +countme=1 +#metadata_expire=7d +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[fedora-modular-debuginfo] +name=Fedora Modular $releasever - $basearch - Debug +#baseurl=http://download.example/pub/fedora/linux/releases/$releasever/Modular/$basearch/debug/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-modular-debug-$releasever&arch=$basearch +enabled=0 +metadata_expire=7d +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[fedora-modular-source] +name=Fedora Modular $releasever - Source +#baseurl=http://download.example/pub/fedora/linux/releases/$releasever/Modular/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-modular-source-$releasever&arch=$basearch +enabled=0 +metadata_expire=7d +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False +EOF + cat <<'EOF' >$Dir_YumRepos/fedora-updates-modular.repo +[updates-modular] +name=Fedora Modular $releasever - $basearch - Updates +#baseurl=http://download.example/pub/fedora/linux/updates/$releasever/Modular/$basearch/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-modular-f$releasever&arch=$basearch +enabled=1 +countme=1 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[updates-modular-debuginfo] +name=Fedora Modular $releasever - $basearch - Updates - Debug +#baseurl=http://download.example/pub/fedora/linux/updates/$releasever/Modular/$basearch/debug/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-modular-debug-f$releasever&arch=$basearch +enabled=0 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[updates-modular-source] +name=Fedora Modular $releasever - Updates Source +#baseurl=http://download.example/pub/fedora/linux/updates/$releasever/Modular/SRPMS/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-modular-source-f$releasever&arch=$basearch +enabled=0 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False +EOF + cat <<'EOF' >$Dir_YumRepos/fedora-updates-testing-modular.repo +[updates-testing-modular] +name=Fedora Modular $releasever - $basearch - Test Updates +#baseurl=http://download.example/pub/fedora/linux/updates/testing/$releasever/Modular/$basearch/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-testing-modular-f$releasever&arch=$basearch +enabled=0 +countme=1 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[updates-testing-modular-debuginfo] +name=Fedora Modular $releasever - $basearch - Test Updates Debug +#baseurl=http://download.example/pub/fedora/linux/updates/$releasever/Modular/$basearch/debug/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-testing-modular-debug-f$releasever&arch=$basearch +enabled=0 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False + +[updates-testing-modular-source] +name=Fedora Modular $releasever - Test Updates Source +#baseurl=http://download.example/pub/fedora/linux/updates/$releasever/Modular/SRPMS/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-testing-modular-source-f$releasever&arch=$basearch +enabled=0 +repo_gpgcheck=0 +type=rpm +gpgcheck=1 +metadata_expire=6h +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch +skip_if_unavailable=False +EOF + fi +} + +## 生成 openEuler repo 源文件 +function gen_repo_files_openEuler() { + cat <<'EOF' >$Dir_YumRepos/openEuler.repo +[OS] +name=OS +baseurl=http://repo.openeuler.org/openEuler-version/OS/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-version/OS/$basearch/RPM-GPG-KEY-openEuler + +[everything] +name=everything +baseurl=http://repo.openeuler.org/openEuler-version/everything/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-version/everything/$basearch/RPM-GPG-KEY-openEuler + +[EPOL] +name=EPOL +baseurl=http://repo.openeuler.org/openEuler-version/EPOL/main/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-version/OS/$basearch/RPM-GPG-KEY-openEuler + +[debuginfo] +name=debuginfo +baseurl=http://repo.openeuler.org/openEuler-version/debuginfo/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-version/debuginfo/$basearch/RPM-GPG-KEY-openEuler + +[source] +name=source +baseurl=http://repo.openeuler.org/openEuler-version/source/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-version/source/RPM-GPG-KEY-openEuler + +[update] +name=update +baseurl=http://repo.openeuler.org/openEuler-version/update/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-version/OS/$basearch/RPM-GPG-KEY-openEuler + +[update-source] +name=update-source +baseurl=http://repo.openeuler.org/openEuler-version/update/source/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-version/source/RPM-GPG-KEY-openEuler +EOF + ## 替换版本号 + local version_name="$(get_os_release_value VERSION | sed 's/["()]//g; s/[_ ]\+/-/g; s/^-\+\|-\+$//g')" + sed -e "s|openEuler-version|openEuler-${version_name}|g" \ + -i \ + $Dir_YumRepos/openEuler.repo +} + +## 生成 OpenCloudOS repo 源文件 +function gen_repo_files_OpenCloudOS() { + case "${1%%.*}" in + 23) + cat <<'EOF' >$Dir_YumRepos/OpenCloudOS-Stream.repo +[BaseOS] +name=BaseOS $releasever - $basearch +baseurl=https://mirrors.opencloudos.tech/opencloudos-stream/releases/$releasever/BaseOS/$basearch/Packages/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-Stream + +[AppStream] +name=AppStream $releasever - $basearch +baseurl=https://mirrors.opencloudos.tech/opencloudos-stream/releases/$releasever/AppStream/$basearch/Packages/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-Stream + +[BaseOS-debug] +name=BaseOS-debug $releasever - $basearch +baseurl=https://mirrors.opencloudos.tech/opencloudos-stream/releases/$releasever/BaseOS/$basearch/debug/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-Stream + +[AppStream-debug] +name=AppStream-debug $releasever - $basearch +baseurl=https://mirrors.opencloudos.tech/opencloudos-stream/releases/$releasever/AppStream/$basearch/debug/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-Stream + +[BaseOS-source] +name=BaseOS-source $releasever +baseurl=https://mirrors.opencloudos.tech/opencloudos-stream/releases/$releasever/BaseOS/source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-Stream + +[AppStream-source] +name=AppStream-source $releasever +baseurl=https://mirrors.opencloudos.tech/opencloudos-stream/releases/$releasever/AppStream/source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-Stream +EOF + ;; + 9) + cat <<'EOF' >$Dir_YumRepos/OpenCloudOS.repo +[BaseOS] +name=BaseOS $releasever - $basearch +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/BaseOS/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-9 + +[AppStream] +name=AppStream $releasever - $basearch +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/AppStream/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-9 + +[extras] +name=extras $releasever - $basearch +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/extras/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-9 + +[BaseOS-debuginfo] +name=BaseOS-debuginfo $releasever - $basearch +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/BaseOS/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-9 + +[AppStream-debuginfo] +name=AppStream-debuginfo $releasever - $basearch +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/AppStream/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-9 + +[extras-debuginfo] +name=extras-debuginfo $releasever - $basearch +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/extras/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-9 + +[BaseOS-source] +name=BaseOS-source $releasever +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/BaseOS/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-9 + +[AppStream-source] +name=AppStream-source $releasever +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/AppStream/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-9 + +[extras-source] +name=extras-source $releasever +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/extras/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS-9 +EOF + ;; + 8) + cat <<'EOF' >$Dir_YumRepos/OpenCloudOS-Debuginfo.repo +[BaseOS-debuginfo] +name=OpenCloudOS $releasever - BaseOS-debuginfo +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/BaseOS/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[AppStream-debuginfo] +name=OpenCloudOS $releasever - AppStream-debuginfo +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/AppStream/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[Extras-debuginfo] +name=OpenCloudOS $releasever - Extras-debuginfo +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/Extras/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[HighAvailability-debuginfo] +name=OpenCloudOS $releasever - HighAvailability-debuginfo +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/HighAvailability/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[PowerTools-debuginfo] +name=OpenCloudOS $releasever - PowerTools-debuginfo +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/PowerTools/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[ResilientStorage-debuginfo] +name=OpenCloudOS $releasever - ResilientStorage-debuginfo +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/ResilientStorage/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[Plus-debuginfo] +name=OpenCloudOS $releasever - Plus-debuginfo +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/Plus/$basearch/debug/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS +EOF + if [[ "${1}" == "8.6" ]]; then + cat <<'EOF' >$Dir_YumRepos/OpenCloudOS.repo +[BaseOS] +name=OpenCloudOS $releasever - BaseOS +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/BaseOS/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[AppStream] +name=OpenCloudOS $releasever - AppStream +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/AppStream/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[Extras] +name=OpenCloudOS $releasever - Extras +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/Extras/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[HighAvailability] +name=OpenCloudOS $releasever - HighAvailability +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/HighAvailability/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[PowerTools] +name=OpenCloudOS $releasever - PowerTools +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/PowerTools/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[ResilientStorage] +name=OpenCloudOS $releasever - ResilientStorage +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/ResilientStorage/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[Plus] +name=OpenCloudOS $releasever - Plus +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/Plus/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS +EOF + else + cat <<'EOF' >$Dir_YumRepos/OpenCloudOS.repo +[BaseOS] +name=OpenCloudOS $releasever - BaseOS +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/BaseOS/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[AppStream] +name=OpenCloudOS $releasever - AppStream +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/AppStream/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[Extras] +name=OpenCloudOS $releasever - Extras +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/Extras/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[HighAvailability] +name=OpenCloudOS $releasever - HighAvailability +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/HighAvailability/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[NFV] +name=OpenCloudOS $releasever - NFV +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/NFV/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[PowerTools] +name=OpenCloudOS $releasever - PowerTools +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/PowerTools/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[ResilientStorage] +name=OpenCloudOS $releasever - ResilientStorage +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/ResilientStorage/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[Plus] +name=OpenCloudOS $releasever - Plus +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/Plus/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS +EOF + fi + cat <<'EOF' >$Dir_YumRepos/OpenCloudOS-Sources.repo +[BaseOS-source] +name=OpenCloudOS $releasever - Base-source +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/BaseOS/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[AppStream-source] +name=OpenCloudOS $releasever - AppStream-source +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/AppStream/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[Extras-source] +name=OpenCloudOS $releasever - Extras-source +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/Extras/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[HighAvailability-source] +name=OpenCloudOS $releasever - HighAvailability-source +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/HighAvailability/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[PowerTools-source] +name=OpenCloudOS $releasever - PowerTools-source +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/PowerTools/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[ResilientStorage-source] +name=OpenCloudOS $releasever - ResilientStorage-source +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/ResilientStorage/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS + +[Plus-source] +name=OpenCloudOS $releasever - Plus-source +baseurl=https://mirrors.opencloudos.tech/opencloudos/$releasever/Plus/source/tree/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OpenCloudOS +EOF + ;; + esac +} + +## 生成 Anolis OS repo 源文件 +function gen_repo_files_AnolisOS() { + case "${1%%.*}" in + 23) + cat <<'EOF' >$Dir_YumRepos/AnolisOS.repo +[os] +name=AnolisOS-$releasever - os +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/os/$basearch/os +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[updates] +name=AnolisOS-$releasever - updates +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/updates/$basearch/os +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[kernel-6] +name=AnolisOS-$releasever - kernel-6 +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/kernel-6/$basearch/os +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/AnolisOS-Source.repo +[os-source] +name=AnolisOS-$releasever - os Source +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/os/source/ +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[updates-source] +name=AnolisOS-$releasever - updates Source +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/updates/source/ +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[kernel-source] +name=AnolisOS-$releasever - kernel-6 Source +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/kernel-6/source/ +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/AnolisOS-Debuginfo.repo +[os-debuginfo] +name=AnolisOS-$releasever - os Debuginfo +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/os/$basearch/debug +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[updates-debuginfo] +name=AnolisOS-$releasever - updates Debuginfo +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/updates/$basearch/debug +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[kernel-6-debuginfo] +name=AnolisOS-$releasever - kernel-6 Debuginfo +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/kernel-6/$basearch/debug +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + ;; + 8) + cat <<'EOF' >$Dir_YumRepos/AnolisOS-AppStream.repo +[AppStream] +name=AnolisOS-$releasever - AppStream +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/AppStream/$basearch/os +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/AnolisOS-BaseOS.repo +[BaseOS] +name=AnolisOS-$releasever - BaseOS +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/BaseOS/$basearch/os +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/AnolisOS-DDE.repo +[DDE] +name=AnolisOS-$releasever - DDE +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/DDE/$basearch/os +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/AnolisOS-Debuginfo.repo +[AppStream-debuginfo] +name=AnolisOS-$releasever - AppStream Debuginfo +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/AppStream/$basearch/debug +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[BaseOS-debuginfo] +name=AnolisOS-$releasever - BaseOS Debuginfo +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/BaseOS/$basearch/debug +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[Plus-debuginfo] +name=AnolisOS-$releasever - Plus Debuginfo +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/Plus/$basearch/debug +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[PowerTools-debuginfo] +name=AnolisOS-$releasever - PowerTools Debuginfo +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/PowerTools/$basearch/debug +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[DDE-debuginfo] +name=AnolisOS-$releasever - DDE Debuginfo +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/DDE/$basearch/debug +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/AnolisOS-Extras.repo +[Extras] +name=AnolisOS-$releasever - Extras +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/Extras/$basearch/os +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/AnolisOS-HighAvailability.repo +[HighAvailability] +name=AnolisOS-$releasever - HighAvailability +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/HighAvailability/$basearch/os +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/AnolisOS-Plus.repo +[Plus] +name=AnolisOS-$releasever - Plus +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/Plus/$basearch/os +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/AnolisOS-PowerTools.repo +[PowerTools] +name=AnolisOS-$releasever - PowerTools +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/PowerTools/$basearch/os +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/AnolisOS-Source.repo +[AppStream-source] +name=AnolisOS-$releasever - AppStream Source +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/AppStream/source/ +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[BaseOS-source] +name=AnolisOS-$releasever - BaseOS Source +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/BaseOS/source/ +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[Plus-source] +name=AnolisOS-$releasever - Plus Source +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/Plus/source/ +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[PowerTools-source] +name=AnolisOS-$releasever - PowerTools Source +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/PowerTools/source/ +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[DDE-source] +name=AnolisOS-$releasever - DDE Source +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/DDE/source/ +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + ## 8.8 新增 + if [[ "${1#*.}" -ge 8 ]]; then + cat <<'EOF' >$Dir_YumRepos/AnolisOS-kernel-5.10.repo +[kernel-5.10] +name=AnolisOS-$releasever - Kernel 5.10 +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/kernel-5.10/$basearch/os +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[kernel-5.10-source] +name=AnolisOS-$releasever - Kernel 5.10 source +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/kernel-5.10/source +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[kernel-5.10-debug] +name=AnolisOS-$releasever - Kernel 5.10 debug +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/kernel-5.10/$basearch/debug +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + fi + ## 8.10 新增 + if [[ "${1#*.}" -eq 10 ]]; then + cat <<'EOF' >$Dir_YumRepos/AnolisOS-Devel.repo +[Devel] +name=AnolisOS-$releasever - Devel +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/Devel/$basearch/os +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/AnolisOS-NDE.repo +[NDE] +name=AnolisOS-$releasever - NDE +baseurl=http://mirrors.openanolis.cn/anolis/$releasever/NDE/$basearch/os +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[NDE-debuginfo] +name=AnolisOS-$releasever - NDE Debuginfo +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/NDE/$basearch/debug +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 + +[NDE-source] +name=AnolisOS-$releasever - NDE Source +baseurl=https://mirrors.openanolis.cn/anolis/$releasever/NDE/source/ +enabled=0 +gpgkey=https://mirrors.openanolis.cn/anolis/RPM-GPG-KEY-ANOLIS +gpgcheck=1 +EOF + fi + ;; + esac +} + +## 生成 openSUSE repo 源文件 +function gen_repo_files_openSUSE() { + case "$1" in + "leap") + case "${2%%.*}" in + 16) + cat <<'EOF' >$Dir_ZYppRepos/openSUSE:repo-non-oss-debug.repo +[openSUSE:repo-non-oss-debug] +name=repo-non-oss-debug (${releasever}) +enabled=0 +autorefresh=1 +baseurl=http://cdn.opensuse.org/debug/distribution/leap/${releasever}/repo/non-oss/$basearch +gpgkey=http://cdn.opensuse.org/debug/distribution/leap/${releasever}/repo/non-oss/$basearch/repodata/repomd.xml.key +EOF + cat <<'EOF' >$Dir_ZYppRepos/openSUSE:repo-non-oss.repo +[openSUSE:repo-non-oss] +name=repo-non-oss (${releasever}) +enabled=0 +autorefresh=1 +baseurl=http://cdn.opensuse.org/distribution/leap/${releasever}/repo/non-oss/$basearch +gpgkey=http://cdn.opensuse.org/distribution/leap/${releasever}/repo/non-oss/$basearch/repodata/repomd.xml.key +EOF + cat <<'EOF' >$Dir_ZYppRepos/openSUSE:repo-openh264.repo +[openSUSE:repo-openh264] +name=repo-openh264 (${releasever}) +enabled=1 +autorefresh=1 +baseurl=http://codecs.opensuse.org/openh264/openSUSE_Leap_16 +gpgkey=https://codecs.opensuse.org/openh264/openSUSE_Leap_16/repodata/repomd.xml.key +EOF + cat <<'EOF' >$Dir_ZYppRepos/openSUSE:repo-oss-debug.repo +[openSUSE:repo-oss-debug] +name=repo-oss-debug (${releasever}) +enabled=0 +autorefresh=1 +baseurl=http://cdn.opensuse.org/debug/distribution/leap/${releasever}/repo/oss/$basearch +gpgkey=http://cdn.opensuse.org/debug/distribution/leap/${releasever}/repo/oss/$basearch/repodata/repomd.xml.key +EOF + cat <<'EOF' >$Dir_ZYppRepos/openSUSE:repo-oss.repo +[openSUSE:repo-oss] +name=repo-oss (${releasever}) +enabled=1 +autorefresh=1 +baseurl=http://cdn.opensuse.org/distribution/leap/${releasever}/repo/oss/$basearch +gpgkey=http://cdn.opensuse.org/distribution/leap/${releasever}/repo/oss/$basearch/repodata/repomd.xml.key +EOF + cat <<'EOF' >$Dir_ZYppRepos/openSUSE:repo-oss-source.repo +[openSUSE:repo-oss-source] +name=repo-oss-source (${releasever}) +enabled=0 +autorefresh=1 +baseurl=http://cdn.opensuse.org/source/distribution/leap/${releasever}/repo/oss +gpgkey=http://cdn.opensuse.org/source/distribution/leap/${releasever}/repo/oss/repodata/repomd.xml.key +EOF + ;; + 15) + case "${2#*.}" in + [0-2]) + cat <<'EOF' >$Dir_ZYppRepos/repo-debug-non-oss.repo +[repo-debug-non-oss] +name=Debug Repository (Non-OSS) +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/debug/distribution/leap/$releasever/repo/non-oss/ +type=NONE +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-debug.repo +[repo-debug] +name=Debug Repository +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/debug/distribution/leap/$releasever/repo/oss/ +type=NONE +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-debug-update-non-oss.repo +[repo-debug-update-non-oss] +name=Update Repository (Debug, Non-OSS) +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/debug/update/leap/$releasever/non-oss/ +type=NONE +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-debug-update.repo +[repo-debug-update] +name=Update Repository (Debug) +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/debug/update/leap/$releasever/oss/ +type=NONE +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-non-oss.repo +[repo-non-oss] +name=Non-OSS Repository +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/distribution/leap/$releasever/repo/non-oss/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-oss.repo +[repo-oss] +name=Main Repository +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/distribution/leap/$releasever/repo/oss/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-source-non-oss.repo +[repo-source-non-oss] +name=Source Repository (Non-OSS) +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/source/distribution/leap/$releasever/repo/non-oss/ +type=NONE +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-source.repo +[repo-source] +name=Source Repository +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/source/distribution/leap/$releasever/repo/oss/ +type=NONE +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-update-non-oss.repo +[repo-update-non-oss] +name=Update Repository (Non-Oss) +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/update/leap/$releasever/non-oss/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-update.repo +[repo-update] +name=Main Update Repository +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/update/leap/$releasever/oss/ +type=rpm-md +keeppackages=0 +EOF + ;; + *) + cat <<'EOF' >$Dir_ZYppRepos/repo-backports-debug-update.repo +[repo-backports-debug-update] +name=Update repository with updates for openSUSE Leap debuginfo packages from openSUSE Backports +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/update/leap/$releasever/backports_debug/ +type=NONE +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-backports-update.repo +[repo-backports-update] +name=Update repository of openSUSE Backports +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/update/leap/$releasever/backports/ +path=/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-debug-non-oss.repo +[repo-debug-non-oss] +name=Debug Repository (Non-OSS) +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/debug/distribution/leap/$releasever/repo/non-oss/ +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-debug.repo +[repo-debug] +name=Debug Repository +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/debug/distribution/leap/$releasever/repo/oss/ +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-debug-update-non-oss.repo +[repo-debug-update-non-oss] +name=Update Repository (Debug, Non-OSS) +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/debug/update/leap/$releasever/non-oss/ +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-debug-update.repo +[repo-debug-update] +name=Update Repository (Debug) +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/debug/update/leap/$releasever/oss/ +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-non-oss.repo +[repo-non-oss] +name=Non-OSS Repository +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/distribution/leap/$releasever/repo/non-oss/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-openh264.repo +[repo-openh264] +name=Open H.264 Codec (openSUSE Leap) +enabled=1 +autorefresh=1 +baseurl=http://codecs.opensuse.org/openh264/openSUSE_Leap/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-oss.repo +[repo-oss] +name=Main Repository +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/distribution/leap/$releasever/repo/oss/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-sle-debug-update.repo +[repo-sle-debug-update] +name=Update repository with debuginfo for updates from SUSE Linux Enterprise 15 +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/debug/update/leap/$releasever/sle/ +path=/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-sle-update.repo +[repo-sle-update] +name=Update repository with updates from SUSE Linux Enterprise 15 +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/update/leap/$releasever/sle/ +path=/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-source.repo +[repo-source] +name=Source Repository +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/source/distribution/leap/$releasever/repo/oss/ +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-update-non-oss.repo +[repo-update-non-oss] +name=Update Repository (Non-Oss) +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/update/leap/$releasever/non-oss/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-update.repo +[repo-update] +name=Main Update Repository +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/update/leap/$releasever/oss/ +type=rpm-md +keeppackages=0 +EOF + ;; + esac + ;; + esac + ;; + "tumbleweed") + cat <<'EOF' >$Dir_ZYppRepos/repo-debug.repo +[repo-debug] +name=openSUSE-Tumbleweed-Debug +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/debug/tumbleweed/repo/oss/ +path=/ +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-non-oss.repo +[repo-non-oss] +name=openSUSE-Tumbleweed-Non-Oss +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/tumbleweed/repo/non-oss/ +path=/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-openh264.repo +[repo-openh264] +name=Open H.264 Codec (openSUSE Tumbleweed) +enabled=1 +autorefresh=1 +baseurl=http://codecs.opensuse.org/openh264/openSUSE_Tumbleweed +path=/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-oss.repo +[repo-oss] +name=openSUSE-Tumbleweed-Oss +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/tumbleweed/repo/oss/ +path=/ +type=rpm-md +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-source.repo +[repo-source] +name=openSUSE-Tumbleweed-Source +enabled=0 +autorefresh=1 +baseurl=http://download.opensuse.org/source/tumbleweed/repo/oss/ +path=/ +keeppackages=0 +EOF + cat <<'EOF' >$Dir_ZYppRepos/repo-update.repo +[repo-update] +name=openSUSE-Tumbleweed-Update +enabled=1 +autorefresh=1 +baseurl=http://download.opensuse.org/update/tumbleweed/ +path=/ +type=rpm-md +keeppackages=0 +EOF + ;; + esac +} + +## 生成 EPEL 附加软件包 repo 源文件 +function gen_repo_files_EPEL() { + case "${1}" in + 10) + cat <<'EOF' >$Dir_YumRepos/epel.repo +[epel] +name=Extra Packages for Enterprise Linux $releasever - $basearch +#baseurl=https://download.example/pub/epel/$releasever_major${releasever_minor:+.$releasever_minor}/Everything/$basearch/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever_major${releasever_minor:+.$releasever_minor}&arch=$basearch +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever_major +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=24h +countme=1 +enabled=1 + +[epel-debuginfo] +name=Extra Packages for Enterprise Linux $releasever - $basearch - Debug +#baseurl=https://download.example/pub/epel/$releasever_major${releasever_minor:+.$releasever_minor}/Everything/$basearch/debug/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-$releasever_major${releasever_minor:+.$releasever_minor}&arch=$basearch +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever_major +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=24h +enabled=0 + +[epel-source] +name=Extra Packages for Enterprise Linux $releasever - $basearch - Source +#baseurl=https://download.example/pub/epel/$releasever_major${releasever_minor:+.$releasever_minor}/Everything/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-source-$releasever_major${releasever_minor:+.$releasever_minor}&arch=$basearch +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever_major +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=24h +enabled=0 +EOF + cat <<'EOF' >$Dir_YumRepos/epel-testing.repo +[epel-testing] +name=Extra Packages for Enterprise Linux $releasever - Testing - $basearch +#baseurl=https://download.example/pub/epel/testing/$releasever_major${releasever_minor:+.$releasever_minor}/Everything/$basearch/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-epel$releasever_major${releasever_minor:+.$releasever_minor}&arch=$basearch +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever_major +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=24h +countme=1 +enabled=0 + +[epel-testing-debuginfo] +name=Extra Packages for Enterprise Linux $releasever - Testing - $basearch - Debug +#baseurl=https://download.example/pub/epel/testing/$releasever_major${releasever_minor:+.$releasever_minor}/Everything/$basearch/debug/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-debug-epel$releasever_major${releasever_minor:+.$releasever_minor}&arch=$basearch +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever_major +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=24h +enabled=0 + +[epel-testing-source] +name=Extra Packages for Enterprise Linux $releasever - Testing - $basearch - Source +#baseurl=https://download.example/pub/epel/testing/$releasever_major${releasever_minor:+.$releasever_minor}/Everything/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-source-epel$releasever_major${releasever_minor:+.$releasever_minor}&arch=$basearch +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever_major +gpgcheck=1 +repo_gpgcheck=0 +metadata_expire=24h +enabled=0 +EOF + ;; + 9) + cat <<'EOF' >$Dir_YumRepos/epel.repo +[epel] +name=Extra Packages for Enterprise Linux $releasever - $basearch +#baseurl=https://download.example/pub/epel/$releasever/Everything/$basearch/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch&infra=$infra&content=$contentdir +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever + +[epel-debuginfo] +name=Extra Packages for Enterprise Linux $releasever - $basearch - Debug +#baseurl=https://download.example/pub/epel/$releasever/Everything/$basearch/debug/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-$releasever&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever +gpgcheck=1 + +[epel-source] +name=Extra Packages for Enterprise Linux $releasever - $basearch - Source +#baseurl=https://download.example/pub/epel/$releasever/Everything/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-source-$releasever&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/epel-testing.repo +[epel-testing] +name=Extra Packages for Enterprise Linux $releasever - Testing - $basearch +#baseurl=https://download.example/pub/epel/testing/$releasever/Everything/$basearch/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-epel$releasever&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever + +[epel-testing-debuginfo] +name=Extra Packages for Enterprise Linux $releasever - Testing - $basearch - Debug +#baseurl=https://download.example/pub/epel/testing/$releasever/Everything/$basearch/debug/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-debug-epel$releasever&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever +gpgcheck=1 + +[epel-testing-source] +name=Extra Packages for Enterprise Linux $releasever - Testing - $basearch - Source +#baseurl=https://download.example/pub/epel/testing/$releasever/Everything/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-source-epel$releasever&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever +gpgcheck=1 +EOF + ## 此仓库特殊,默认不启用 + cat <<'EOF' >$Dir_YumRepos/epel-cisco-openh264.repo +[epel-cisco-openh264] +name=Extra Packages for Enterprise Linux $releasever openh264 (From Cisco) - $basearch +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-cisco-openh264-$releasever&arch=$basearch +type=rpm +enabled=0 +metadata_expire=14d +repo_gpgcheck=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever +skip_if_unavailable=True + +[epel-cisco-openh264-debuginfo] +name=Extra Packages for Enterprise Linux $releasever openh264 (From Cisco) - $basearch - Debug +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-cisco-openh264-debug-$releasever&arch=$basearch +type=rpm +enabled=0 +metadata_expire=14d +repo_gpgcheck=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever +skip_if_unavailable=True + +[epel-cisco-openh264-source] +name=Extra Packages for Enterprise Linux $releasever openh264 (From Cisco) - $basearch - Source +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-cisco-openh264-source-$releasever&arch=$basearch +type=rpm +enabled=0 +metadata_expire=14d +repo_gpgcheck=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever +skip_if_unavailable=True +EOF + ;; + 8) + cat <<'EOF' >$Dir_YumRepos/epel.repo +[epel] +name=Extra Packages for Enterprise Linux 8 - $basearch +#baseurl=https://download.example/pub/epel/8/Everything/$basearch +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-8&arch=$basearch&infra=$infra&content=$contentdir +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 + +[epel-debuginfo] +name=Extra Packages for Enterprise Linux 8 - $basearch - Debug +#baseurl=https://download.example/pub/epel/8/Everything/$basearch/debug +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-8&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 +gpgcheck=1 + +[epel-source] +name=Extra Packages for Enterprise Linux 8 - $basearch - Source +#baseurl=https://download.example/pub/epel/8/Everything/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-source-8&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/epel-testing.repo +[epel-testing] +name=Extra Packages for Enterprise Linux 8 - Testing - $basearch +#baseurl=https://download.example/pub/epel/testing/8/Everything/$basearch +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-epel8&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 + +[epel-testing-debuginfo] +name=Extra Packages for Enterprise Linux 8 - Testing - $basearch - Debug +#baseurl=https://download.example/pub/epel/testing/8/Everything/$basearch/debug +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-debug-epel8&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 +gpgcheck=1 + +[epel-testing-source] +name=Extra Packages for Enterprise Linux 8 - Testing - $basearch - Source +#baseurl=https://download.example/pub/epel/testing/8/Everything/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-source-epel8&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/epel-modular.repo +[epel-modular] +name=Extra Packages for Enterprise Linux Modular 8 - $basearch - RETIRED +#baseurl=https://download.example/pub/epel/8/Modular/$basearch +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-modular-8&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 + +[epel-modular-debuginfo] +name=Extra Packages for Enterprise Linux Modular 8 - $basearch - Debug - RETIRED +#baseurl=https://download.example/pub/epel/8/Modular/$basearch/debug +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-modular-debug-8&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 +gpgcheck=1 + +[epel-modular-source] +name=Extra Packages for Enterprise Linux Modular 8 - $basearch - Source - RETIRED +#baseurl=https://download.example/pub/epel/8/Modular/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-modular-source-8&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/epel-testing-modular.repo +[epel-testing-modular] +name=Extra Packages for Enterprise Linux Modular 8 - Testing - $basearch - RETIRED +#baseurl=https://download.example/pub/epel/testing/8/Modular/$basearch +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-modular-epel8&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 + +[epel-testing-modular-debuginfo] +name=Extra Packages for Enterprise Linux Modular 8 - Testing - $basearch - Debug - RETIRED +#baseurl=https://download.example/pub/epel/testing/8/Modular/$basearch/debug +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-modular-debug-epel8&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 +gpgcheck=1 + +[epel-testing-modular-source] +name=Extra Packages for Enterprise Linux Modular 8 - Testing - $basearch - Source - RETIRED +#baseurl=https://download.example/pub/epel/testing/8/Modular/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-modular-source-epel8&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8 +gpgcheck=1 +EOF + ;; + 7) + cat <<'EOF' >$Dir_YumRepos/epel.repo +[epel] +name=Extra Packages for Enterprise Linux 7 - $basearch +#baseurl=http://download.example/pub/epel/7/$basearch +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch&infra=$infra&content=$contentdir +failovermethod=priority +enabled=1 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 + +[epel-debuginfo] +name=Extra Packages for Enterprise Linux 7 - $basearch - Debug +#baseurl=http://download.example/pub/epel/7/$basearch/debug +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-7&arch=$basearch&infra=$infra&content=$contentdir +failovermethod=priority +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 +gpgcheck=1 + +[epel-source] +name=Extra Packages for Enterprise Linux 7 - $basearch - Source +#baseurl=http://download.example/pub/epel/7/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-source-7&arch=$basearch&infra=$infra&content=$contentdir +failovermethod=priority +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/epel-testing.repo +[epel-testing] +name=Extra Packages for Enterprise Linux 7 - Testing - $basearch +#baseurl=http://download.example/pub/epel/testing/7/$basearch +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-epel7&arch=$basearch&infra=$infra&content=$contentdir +failovermethod=priority +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 + +[epel-testing-debuginfo] +name=Extra Packages for Enterprise Linux 7 - Testing - $basearch - Debug +#baseurl=http://download.example/pub/epel/testing/7/$basearch/debug +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-debug-epel7&arch=$basearch&infra=$infra&content=$contentdir +failovermethod=priority +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 +gpgcheck=1 + +[epel-testing-source] +name=Extra Packages for Enterprise Linux 7 - Testing - $basearch - Source +#baseurl=http://download.example/pub/epel/testing/7/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=testing-source-epel7&arch=$basearch&infra=$infra&content=$contentdir +failovermethod=priority +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 +gpgcheck=1 +EOF + ;; + esac +} + +## 生成 EPEL 附加软件包 NEXT repo 源文件 +function gen_repo_files_EPEL_NEXT() { + case "${1}" in + 9) + cat <<'EOF' >$Dir_YumRepos/epel-next.repo +[epel-next] +name=Extra Packages for Enterprise Linux 9 - Next - $basearch +#baseurl=https://download.example/pub/epel/next/9/Everything/$basearch/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-next-9&arch=$basearch&infra=$infra&content=$contentdir +enabled=1 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 + +[epel-next-debuginfo] +name=Extra Packages for Enterprise Linux 9 - Next - $basearch - Debug +#baseurl=https://download.example/pub/epel/next/9/Everything/$basearch/debug/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-next-debug-9&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 +gpgcheck=1 + +[epel-next-source] +name=Extra Packages for Enterprise Linux 9 - Next - $basearch - Source +#baseurl=https://download.example/pub/epel/next/9/Everything/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-next-source-9&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 +gpgcheck=1 +EOF + cat <<'EOF' >$Dir_YumRepos/epel-next-testing.repo +[epel-next-testing] +name=Extra Packages for Enterprise Linux 9 - Next - Testing - $basearch +#baseurl=https://download.example/pub/epel/testing/next/9/Everything/$basearch/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-testing-next-9&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgcheck=1 +countme=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 + +[epel-next-testing-debuginfo] +name=Extra Packages for Enterprise Linux 9 - Next - Testing - $basearch - Debug +#baseurl=https://download.example/pub/epel/testing/next/9/Everything/$basearch/debug/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-testing-next-debug-9&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 +gpgcheck=1 + +[epel-next-testing-source] +name=Extra Packages for Enterprise Linux 9 - Next - Testing - $basearch - Source +#baseurl=https://download.example/pub/epel/testing/next/9/Everything/source/tree/ +metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-testing-next-source-9&arch=$basearch&infra=$infra&content=$contentdir +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 +gpgcheck=1 +EOF + ;; + esac +} + +############################################################################## + +MESSAGE_LANG_DEFAULT='zh-hans' +MESSAGE_LANG_KEYS=( + "zh-hans" + "zh-hant" + "en" +) +declare -A MESSAGE_LANG_DISPLAY=( + ['zh-hans']='简体中文' + ['zh-hant']='繁體中文' + ['en']='English' +) +declare -A MESSAGE_CONTENTS + +function msg() { + local key="$1" + shift + local text="${MESSAGE_CONTENTS[${key}]}" + if [[ -z "${text}" ]]; then + echo "${key}" + return + fi + while [[ $# -gt 0 ]]; do + if [[ "${text}" == *"{}"* ]]; then + text="${text/\{\}/$1}" + else + break + fi + shift + done + echo "${text}" +} + +function init_msg_pack() { + function load_pack() { + local func_name="${1}" + if declare -f "${func_name}" >/dev/null 2>&1; then + eval "${func_name}" + fi + } + local current_lang="${1:-${MESSAGE_LANG_DEFAULT}}" + current_lang="$(echo "${current_lang}" | sed 's/^-*//')" + current_lang="${current_lang,,}" + if [[ "${MESSAGE_LANG_DISPLAY[${current_lang}]}" ]]; then + current_lang="${current_lang//-/_}" + load_pack "msg_pack_${current_lang}" + fi +} + +function msg_pack_zh_hans() { + MESSAGE_CONTENTS=( + ['start.welcome']='欢迎使用 GNU/Linux 更换系统软件源脚本' + ['start.runtimeEnv']='运行环境' + ['start.dateTime']='系统时间' + ['end.moreInfo']='脚本运行完毕,更多使用教程详见官网' + ['end.sponsorAds']='【赞助商广告】' + ['error.cmd.options.needConfirm']='请确认后重新输入' + ['error.cmd.options.needSpecify']='请在该选项后指定{}' + ['error.cmd.options.invalid']='命令选项 {} 无效,{}!' + ['error.cmd.options.validAddress']='有效的地址' + ['error.cmd.options.sourceAddress']='软件源地址' + ['error.cmd.options.sourceRepository']='软件源仓库' + ['error.cmd.options.codename']='版本代号' + ['error.cmd.options.boolean']=' true 或 false ' + ['error.cmd.options.protocol']=' http 或 https ' + ['error.cmd.options.needProtocol']=' Web 协议(http/https)' + ['error.cmd.options.validLangKey']='有效的语言 ID ' + ['error.cmd.options.langKey']='语言 ' + ['error.cmd.options.unsupportTwoSourceMode']='不可同时使用两种软件源模式,请确认后重试!' + ['error.cmd.options.unsupportCodename']='当前系统不支持使用指定版本代号命令选项,请确认后重试!' + ['error.cmd.options.unsupportEPEL']='当前系统不支持安装 EPEL 附加软件包,请确认后重试!' + ['error.unsupportSystem']='不支持当前操作系统({}),请前往官网查看支持列表!' + ['error.unsupportVersion']='不支持当前系统版本' + ['error.unknownSystem']='未知系统' + ['error.unknownVersion']='系统版本未知' + ['error.input']='输入错误,{}!' + ['error.needRoot']='权限不足,请切换至 root 账户后运行本脚本,切换命令 {}' + ['error.defaultBehavior.https']='默认使用 HTTPS 协议' + ['error.defaultBehavior.noReplace']='默认不更换' + ['error.defaultBehavior.noOverwrite']='默认不覆盖' + ['error.defaultBehavior.noUpdate']='默认不更新' + ['error.defaultBehavior.noClean']='默认不清理' + ['error.defaultBehavior.noUseIntranetSource']='默认不使用内网地址' + ['warn.usedIntranetSource']='已切换至内网专用地址,仅限在特定环境下使用!' + ['warn.unstableDebian']='检测到当前系统为 {} 版本,可能会产生一些无法预料的问题。' + ['warn.EPEL7']='Extra Packages for Enterprise Linux 7 已结束生命周期并被官方移至归档库!' + ['warn.needValidNumberIndex']='请输入有效的数字序号!' + ['warn.needInputNumberIndex']='请输入数字序号!' + ['info.backuped.sourceFile']='已备份原有 {} 源文件' + ['tip.EPEL7']='目前部分镜像站没有同步该归档仓库,若换源后出现错误那么请先检查目标镜像站是否支持该仓库。' + ['interaction.source.type.public']='公网' + ['interaction.source.type.intranet']='内网' + ['interaction.source.type.select']='请选择软件源的网络地址(访问方式):' + ['interaction.source.type.usePublicAddress']='默认使用软件源的公网地址,是否继续' + ['interaction.source.select']='请选择你想使用的软件源:' + ['interaction.source.selectAndInput']='请选择并输入你想使用的软件源' + ['interaction.protocol.select']='请选择软件源网络协议:' + ['interaction.protocol.useHttp']='软件源是否使用 HTTP 协议' + ['interaction.epel.skipReplace']='检测到系统已安装 EPEL 附加软件包,是否替换/覆盖软件源' + ['interaction.epel.install']='是否安装 EPEL 附加软件包' + ['interaction.backup.skipOverwrite.sourceFile']='检测到系统存在已备份的 {} 源文件,是否跳过覆盖备份' + ['interaction.upgrade.skip']='是否跳过更新软件包' + ['interaction.cache.autoClean']='在更新软件包后,是否自动清理下载缓存' + ['interaction.common.tip']='提示' + ['interaction.common.operationCanceled']='操作已取消' + ['interaction.common.yes']='是' + ['interaction.common.no']='否' + ['work.upgradeSoftware']='更新软件包' + ['work.installEPELPackage']='安装 epel-release 软件包...' + ['source.sync.text1']='更新软件源' + ['source.sync.text2']='生成软件源缓存' + ['source.sync.text3']='刷新软件源' + ['source.sync.text4']='同步软件源' + ['source.sync.text5']='更新二进制缓存与频道源' + ['source.comment.disabledSourceCode']='默认禁用源码镜像以提高更新速度,如需启用请自行取消注释' + ['source.comment.securitySource']='安全更新软件源' + ['source.comment.proposedSource']='预发布软件源(不建议启用)' + ['source.changeResult.success']='软件源更换完毕' + ['source.changeResult.fail']='软件源更换完毕,但{}失败' + ['source.changeResult.tipTitle']='请再次执行脚本并更换相同软件源后进行尝试,若仍然{}失败那么可能由以下原因导致:' + ['source.changeResult.tip1']='网络连通性问题:例如连接异常、由地区影响的网络间歇式中断、禁止外部访问、软件源网站防火墙阻断等' + ['source.changeResult.tip2']='目标软件源异常:请手动前往软件源(镜像站)地址进行验证:{}' + ['source.changeResult.tip2.1']='若报错内容是提示某个文件不存在那么有可能是软件源的问题,多常见于正在同步中的软件源仓库' + ['source.changeResult.tip2.2']='若报错内容是目录(path)不存在也有可能是目标软件源不存在当前系统镜像仓库,即不支持当前系统' + ['source.changeResult.tip2.3']='建议更换其它镜像站进行尝试,少数情况下软件源若处于同步中状态则可能会出现文件同步错误问题' + ['source.changeResult.tip3']='原有软件源报错:请先排除系统原有的其它软件源报错,因为脚本不会干预这些无关的软件源配置,解决后重新运行脚本即可' + ['commands.help']='命令选项(名称/含义/值): + + --abroad 使用境外以及海外软件源 无 + --edu 使用中国大陆教育网软件源 无 + --source 指定软件源地址(域名或IP) 地址 + --source-epel 指定 EPEL 附加软件包仓库的软件源地址(域名或IP) 地址 + --source-security 指定 Debian / Ubuntu 系统 security 仓库的软件源地址(域名或IP) 地址 + --source-vault 指定 CentOS / AlmaLinux 系统 vault 仓库的软件源地址(域名或IP) 地址 + --source-portage 指定 Gentoo 系统 portage 仓库的软件源地址(域名或IP) 地址 + --source-base-system 指定 Linux Mint / Raspberry Pi OS 底层系统的软件源地址(域名或IP) 地址 + --branch 指定软件源仓库(路径) 仓库名 + --branch-epel 指定 EPEL 附加软件包仓库的软件源仓库(路径) 仓库名 + --branch-security 指定 Debian 系统 security 仓库的软件源仓库(路径) 仓库名 + --branch-vault 指定 CentOS / AlmaLinux 系统 vault 仓库的软件源仓库(路径) 仓库名 + --branch-portage 指定 Gentoo 系统 portage 仓库的软件源仓库(路径) 仓库名 + --branch-base-system 指定 Linux Mint / Raspberry Pi OS 底层系统的软件源仓库(路径) 仓库名 + --codename 指定 Debian 系 / openKylin 操作系统的版本代号 代号名称 + --protocol 指定 Web 协议 http 或 https + --use-intranet-source 是否优先使用内网软件源地址 true 或 false + --use-official-source 是否使用目标操作系统的官方软件源 true 或 false + --use-official-source-epel 是否使用 EPEL 附加软件包的官方软件源 true 或 false + --install-epel 是否安装 EPEL 附加软件包 true 或 false + --backup 是否备份原有软件源 true 或 false + --upgrade-software 是否更新软件包 true 或 false + --clean-cache 是否在更新软件包后清理下载缓存 true 或 false + --clean-screen 是否在运行前清除屏幕上的所有内容 true 或 false + --lang 指定脚本输出的语言 语言 + --only-epel 仅更换 EPEL 软件源模式 无 + --ignore-backup-tips 忽略覆盖备份提示 无 + --print-diff 打印源文件修改前后差异 无 + --pure-mode 纯净模式,精简打印内容 无 + --help 查看帮助菜单 无 + +问题报告 {}' + ['mirrors.default.0']='阿里云' + ['mirrors.default.1']='腾讯云' + ['mirrors.default.2']='华为云' + ['mirrors.default.3']='移动云' + ['mirrors.default.4']='天翼云' + ['mirrors.default.5']='网易' + ['mirrors.default.6']='火山引擎' + ['mirrors.default.7']='清华大学' + ['mirrors.default.8']='北京大学' + ['mirrors.default.9']='浙江大学' + ['mirrors.default.10']='南京大学' + ['mirrors.default.11']='兰州大学' + ['mirrors.default.12']='上海交通大学' + ['mirrors.default.13']='重庆邮电大学' + ['mirrors.default.14']='中国科学技术大学' + ['mirrors.default.15']='中国科学院软件研究所' + ['mirrors.default.16']='官方源' + ['mirrors.edu.0']='北京大学' + ['mirrors.edu.1']='北京交通大学' + ['mirrors.edu.2']='北京外国语大学' + ['mirrors.edu.3']='北京邮电大学' + ['mirrors.edu.4']='重庆大学' + ['mirrors.edu.5']='重庆邮电大学' + ['mirrors.edu.6']='大连东软信息学院' + ['mirrors.edu.7']='电子科技大学' + ['mirrors.edu.8']='华南农业大学' + ['mirrors.edu.9']='华中科技大学' + ['mirrors.edu.10']='吉林大学' + ['mirrors.edu.11']='荆楚理工学院' + ['mirrors.edu.12']='江西理工大学' + ['mirrors.edu.13']='兰州大学' + ['mirrors.edu.14']='南京大学' + ['mirrors.edu.15']='南京工业大学' + ['mirrors.edu.16']='南京邮电大学' + ['mirrors.edu.17']='南方科技大学' + ['mirrors.edu.18']='南阳理工学院' + ['mirrors.edu.19']='齐鲁工业大学' + ['mirrors.edu.20']='清华大学' + ['mirrors.edu.21']='山东大学' + ['mirrors.edu.22']='上海科技大学' + ['mirrors.edu.23']='上海交通大学(思源)' + ['mirrors.edu.24']='上海交通大学(致远)' + ['mirrors.edu.25']='武昌首义学院' + ['mirrors.edu.26']='西安交通大学' + ['mirrors.edu.27']='西北农林科技大学' + ['mirrors.edu.28']='浙江大学' + ['mirrors.edu.29']='中国科学技术大学' + ['mirrors.edu.30']='官方源' + ['mirrors.abroad.0']='亚洲 · xTom · 香港' + ['mirrors.abroad.1']='亚洲 · 01Link · 香港' + ['mirrors.abroad.2']='亚洲 · 新加坡国立大学(NUS) · 新加坡' + ['mirrors.abroad.3']='亚洲 · SG.GS · 新加坡' + ['mirrors.abroad.4']='亚洲 · xTom · 新加坡' + ['mirrors.abroad.5']='亚洲 · 自由软件实验室(NCHC) · 台湾' + ['mirrors.abroad.6']='亚洲 · OSS Planet · 台湾' + ['mirrors.abroad.7']='亚洲 · 国立阳明交通大学 · 台湾' + ['mirrors.abroad.8']='亚洲 · 淡江大学 · 台湾' + ['mirrors.abroad.9']='亚洲 · Taiwan Digital Streaming · 台湾' + ['mirrors.abroad.10']='亚洲 · AniGil Linux Archive · 韩国' + ['mirrors.abroad.11']='亚洲 · 工业网络安全中心(ICSCoE) · 日本' + ['mirrors.abroad.12']='亚洲 · 北陆先端科学技术大学院大学(JAIST) · 日本' + ['mirrors.abroad.13']='亚洲 · 山形大学 · 日本' + ['mirrors.abroad.14']='亚洲 · xTom · 日本' + ['mirrors.abroad.15']='亚洲 · GB Network Solutions · 马来西亚' + ['mirrors.abroad.16']='亚洲 · 孔敬大学 · 泰国' + ['mirrors.abroad.17']='欧洲 · Vorboss Ltd · 英国' + ['mirrors.abroad.18']='欧洲 · QuickHost · 英国' + ['mirrors.abroad.19']='欧洲 · dogado · 德国' + ['mirrors.abroad.20']='欧洲 · xTom · 德国' + ['mirrors.abroad.21']='欧洲 · 亚琛工业大学(RWTH Aachen) · 德国' + ['mirrors.abroad.22']='欧洲 · 德累斯顿大学(AG DSN) · 德国' + ['mirrors.abroad.23']='欧洲 · CCIN2P3 · 法国' + ['mirrors.abroad.24']='欧洲 · Ircam · 法国' + ['mirrors.abroad.25']='欧洲 · Crans · 法国' + ['mirrors.abroad.26']='欧洲 · CRIHAN · 法国' + ['mirrors.abroad.27']='欧洲 · xTom · 荷兰' + ['mirrors.abroad.28']='欧洲 · DataPacket · 荷兰' + ['mirrors.abroad.29']='欧洲 · Linux Kernel · 荷兰' + ['mirrors.abroad.30']='欧洲 · xTom · 爱沙尼亚' + ['mirrors.abroad.31']='欧洲 · netsite · 丹麦' + ['mirrors.abroad.32']='欧洲 · Dotsrc · 丹麦' + ['mirrors.abroad.33']='欧洲 · Academic Computer Club · 瑞典' + ['mirrors.abroad.34']='欧洲 · Lysator · 瑞典' + ['mirrors.abroad.35']='欧洲 · Yandex · 俄罗斯' + ['mirrors.abroad.36']='欧洲 · ia64 · 俄罗斯' + ['mirrors.abroad.37']='欧洲 · Truenetwork · 俄罗斯' + ['mirrors.abroad.38']='欧洲 · Belgian Research Network · 比利时' + ['mirrors.abroad.39']='欧洲 · 克里特大学计算机中心 · 希腊' + ['mirrors.abroad.40']='欧洲 · 马萨里克大学信息学院 · 捷克' + ['mirrors.abroad.41']='欧洲 · 捷克理工大学学生会俱乐部(Silicon Hill) · 捷克' + ['mirrors.abroad.42']='欧洲 · Vodafone · 捷克' + ['mirrors.abroad.43']='欧洲 · CZ.NIC · 捷克' + ['mirrors.abroad.44']='欧洲 · 苏黎世联邦理工学院 · 瑞士' + ['mirrors.abroad.45']='北美 · Linux Kernel · 美国' + ['mirrors.abroad.46']='北美 · 麻省理工学院(MIT) · 美国' + ['mirrors.abroad.47']='北美 · 普林斯顿大学数学系 · 美国' + ['mirrors.abroad.48']='北美 · 俄勒冈州立大学开源实验室 · 美国' + ['mirrors.abroad.49']='北美 · Fremont Cabal Internet Exchange(FCIX) · 美国' + ['mirrors.abroad.50']='北美 · xTom · 美国' + ['mirrors.abroad.51']='北美 · Steadfast · 美国' + ['mirrors.abroad.52']='北美 · 不列颠哥伦比亚大学 · 加拿大' + ['mirrors.abroad.53']='北美 · GoCodeIT · 加拿大' + ['mirrors.abroad.54']='北美 · Switch · 加拿大' + ['mirrors.abroad.55']='南美 · PoP-SC · 巴西' + ['mirrors.abroad.56']='南美 · 蓬塔格罗萨州立大学 · 巴西' + ['mirrors.abroad.57']='南美 · UFSCar · 巴西' + ['mirrors.abroad.58']='南美 · Sysarmy Community · 阿根廷' + ['mirrors.abroad.59']='大洋 · Fremont Cabal Internet Exchange(FCIX) · 澳大利亚' + ['mirrors.abroad.60']='大洋 · AARNet · 澳大利亚' + ['mirrors.abroad.61']='大洋 · DataMossa · 澳大利亚' + ['mirrors.abroad.62']='大洋 · Amaze · 澳大利亚' + ['mirrors.abroad.63']='大洋 · xTom · 澳大利亚' + ['mirrors.abroad.64']='大洋 · Over the Wire · 澳大利亚' + ['mirrors.abroad.65']='大洋 · Free Software Mirror Group · 新西兰' + ['mirrors.abroad.66']='非洲 · Liquid Telecom · 肯尼亚' + ['mirrors.abroad.67']='非洲 · Dimension Data · 南非' + ['mirrors.abroad.68']='官方源' + ) +} + +function msg_pack_zh_hant() { + MESSAGE_CONTENTS=( + ['start.welcome']='歡迎使用 GNU/Linux 更換系統軟體源腳本' + ['start.runtimeEnv']='執行環境' + ['start.dateTime']='系統時間' + ['end.moreInfo']='腳本執行完畢,更多使用教學詳見官網' + ['end.sponsorAds']='【贊助商廣告】' + ['error.cmd.options.needConfirm']='請確認後重新輸入' + ['error.cmd.options.needSpecify']='請在該選項後指定{}' + ['error.cmd.options.invalid']='命令選項 {} 無效,{}!' + ['error.cmd.options.invalid']='命令選項 {} 無效,{}!' + ['error.cmd.options.validAddress']='有效的地址' + ['error.cmd.options.sourceAddress']='軟體源地址' + ['error.cmd.options.sourceRepository']='軟體源倉庫' + ['error.cmd.options.codename']='版本代號' + ['error.cmd.options.boolean']=' true 或 false ' + ['error.cmd.options.protocol']=' http 或 https ' + ['error.cmd.options.needProtocol']=' Web 協定(http/https)' + ['error.cmd.options.validLangKey']='有效的語言 ID ' + ['error.cmd.options.langKey']='語言 ID ' + ['error.cmd.options.unsupportTwoSourceMode']='不可同時使用兩種軟體源模式,請確認後重試!' + ['error.cmd.options.unsupportCodename']='當前系統不支援使用指定版本代號命令選項,請確認後重試!' + ['error.cmd.options.unsupportEPEL']='當前系統不支援安裝 EPEL 附加軟體包,請確認後重試!' + ['error.unsupportSystem']='不支援當前系統({}),請前往官網查看支援清單!' + ['error.unsupportVersion']='不支援當前系統版本' + ['error.unknownSystem']='未知系統' + ['error.unknownVersion']='系統版本未知' + ['error.input']='輸入錯誤,{}!' + ['error.needRoot']='權限不足,請切換至 root 帳戶後執行本腳本,切換指令 {}' + ['error.defaultBehavior.https']='預設使用 HTTPS 協定' + ['error.defaultBehavior.noReplace']='預設不更換' + ['error.defaultBehavior.noOverwrite']='預設不覆蓋' + ['error.defaultBehavior.noUpdate']='預設不更新' + ['error.defaultBehavior.noClean']='預設不清理' + ['error.defaultBehavior.noUseIntranetSource']='預設不使用內網地址' + ['warn.usedIntranetSource']='已切換至內網專用地址,僅限在特定環境下使用!' + ['warn.unstableDebian']='偵測到當前系統為 {} 版本,可能會產生一些無法預料的問題。' + ['warn.EPEL7']='Extra Packages for Enterprise Linux 7 已結束生命週期並被官方移至封存庫!' + ['warn.needValidNumberIndex']='請輸入有效的數字序號!' + ['warn.needInputNumberIndex']='請輸入數字序號!' + ['info.backuped.sourceFile']='已備份原有 {} 源檔案' + ['tip.EPEL7']='目前部分鏡像站尚未同步該封存倉庫,若換源後出現錯誤請先檢查目標鏡像站是否支援該倉庫。' + ['interaction.source.type.public']='外網' + ['interaction.source.type.intranet']='內網' + ['interaction.source.type.select']='請選擇軟體源的網路地址(存取方式):' + ['interaction.source.type.usePublicAddress']='預設使用軟體源的外網地址,是否繼續' + ['interaction.source.select']='請選擇你想使用的軟體源:' + ['interaction.source.selectAndInput']='請選擇並輸入你想使用的軟體源' + ['interaction.protocol.select']='請選擇軟體源網路協定:' + ['interaction.protocol.useHttp']='軟體源是否使用 HTTP 协议' + ['interaction.epel.skipReplace']='偵測到系統已安裝 EPEL 附加軟體包,是否替換/覆蓋軟體源' + ['interaction.epel.install']='是否安裝 EPEL 附加軟體包' + ['interaction.backup.skipOverwrite.sourceFile']='偵測到系統存在已備份的 {} 源檔案,是否跳過覆蓋備份' + ['interaction.upgrade.skip']='是否跳過更新軟體包' + ['interaction.cache.autoClean']='在更新軟體包後,是否自動清理下載快取' + ['interaction.common.tip']='提示' + ['interaction.common.operationCanceled']='操作已取消' + ['interaction.common.yes']='是' + ['interaction.common.no']='否' + ['work.upgradeSoftware']='更新軟體包' + ['work.installEPELPackage']='正在安裝 epel-release 套件...' + ['source.sync.text1']='更新軟體源' + ['source.sync.text2']='產生軟體源快取' + ['source.sync.text3']='重新整理軟體源' + ['source.sync.text4']='同步軟體源' + ['source.sync.text5']='更新二進位快取與頻道來源' + ['source.comment.disabledSourceCode']='預設停用原始碼鏡像以提升更新速度,如需啟用請自行取消註解' + ['source.comment.securitySource']='安全更新軟體源' + ['source.comment.proposedSource']='預發布軟體源(不建議啟用)' + ['source.changeResult.success']='軟體源更換完畢' + ['source.changeResult.fail']='軟體源更換完畢,但{}失敗' + ['source.changeResult.tipTitle']='請再次執行腳本並更換相同軟體源後重試,若仍然{}失敗則可能由下列原因造成:' + ['source.changeResult.tip1']='網路連通性問題:例如連線異常、地域因素造成的網路間歇中斷、禁止外部存取、軟體源站台防火牆阻斷等' + ['source.changeResult.tip2']='目標軟體源異常:請手動前往軟體源(鏡像站)地址進行驗證:{}' + ['source.changeResult.tip2.1']='若錯誤內容是提示某個檔案不存在,可能是軟體源的問題,常見於鏡像站同步期間' + ['source.changeResult.tip2.2']='若錯誤內容是目錄不存在,也可能代表目標軟體源不含當前系統的鏡像倉庫,即不支援當前系統' + ['source.changeResult.tip2.3']='建議更換其他鏡像站再試,少數情況下軟體源若處於同步中狀態則可能會出現檔案同步錯誤' + ['source.changeResult.tip3']='原有軟體源報錯:請先排除系統其他軟體源的錯誤,因為腳本不會處理無關的軟體源配置,解決後重新執行腳本即可' + ['commands.help']='命令選項(名稱/含義/值): + + --abroad 使用境外以及海外軟體源 無 + --edu 使用中國大陸教育網軟體源 無 + --source 指定軟體源地址(網域名稱或IP) 位址 + --source-epel 指定 EPEL 附加軟體包倉庫的軟體源地址(網域名稱或IP) 位址 + --source-security 指定 Debian / Ubuntu 系統 security 倉庫的軟體源地址(網域名稱或IP) 位址 + --source-vault 指定 CentOS / AlmaLinux 系統 vault 倉庫的軟體源地址(網域名稱或IP) 位址 + --source-portage 指定 Gentoo 系統 portage 倉庫的軟體源地址(網域名稱或IP) 位址 + --source-base-system 指定 Linux Mint / Raspberry Pi OS 底層系統的軟體源地址(網域名稱或IP) 位址 + --branch 指定軟體源倉庫(路徑) 倉庫名稱 + --branch-epel 指定 EPEL 附加軟體包倉庫的軟體源倉庫(路徑) 倉庫名稱 + --branch-security 指定 Debian 系統 security 倉庫的軟體源倉庫(路徑) 倉庫名稱 + --branch-vault 指定 CentOS / AlmaLinux 系統 vault 倉庫的軟體源倉庫(路徑) 倉庫名稱 + --branch-portage 指定 Gentoo 系統 portage 倉庫的軟體源倉庫(路徑) 倉庫名稱 + --branch-base-system 指定 Linux Mint / Raspberry Pi OS 底層系統的軟體源倉庫(路徑) 倉庫名稱 + --codename 指定 Debian 系 / openKylin 系統的版本代號 代號名稱 + --protocol 指定 Web 協定 http 或 https + --use-intranet-source 是否優先使用內部網路軟體源位址 true 或 false + --use-official-source 是否使用目標系統的官方軟體源 true 或 false + --use-official-source-epel 是否使用 EPEL 附加軟體包的官方軟體源 true 或 false + --install-epel 是否安裝 EPEL 附加軟體包 true 或 false + --backup 是否備份原有軟體源 true 或 false + --upgrade-software 是否更新軟體包 true 或 false + --clean-cache 是否在更新軟體包後清理下載快取 true 或 false + --clean-screen 是否在運行前清除螢幕上的所有內容 true 或 false + --lang 指定腳本輸出的語言 语言 + --only-epel 僅更換 EPEL 軟體源模式 無 + --ignore-backup-tips 忽略覆蓋備份提示 無 + --print-diff 是否列印原始文件修改前後差異 無 + --pure-mode 純淨模式,精簡列印內容 無 + --help 查看幫助選單 無 + +問題報告 {}' + ['mirrors.default.0']='阿里雲' + ['mirrors.default.1']='騰訊雲' + ['mirrors.default.2']='華為雲' + ['mirrors.default.3']='移動雲' + ['mirrors.default.4']='天翼雲' + ['mirrors.default.5']='網易' + ['mirrors.default.6']='火山引擎' + ['mirrors.default.7']='清華大學' + ['mirrors.default.8']='北京大學' + ['mirrors.default.9']='浙江大學' + ['mirrors.default.10']='南京大學' + ['mirrors.default.11']='蘭州大學' + ['mirrors.default.12']='上海交通大學' + ['mirrors.default.13']='重慶郵電大學' + ['mirrors.default.14']='中國科學技術大學' + ['mirrors.default.15']='中國科學院軟件研究所' + ['mirrors.default.16']='官方源' + ['mirrors.edu.0']='北京大學' + ['mirrors.edu.1']='北京交通大學' + ['mirrors.edu.2']='北京外國語大學' + ['mirrors.edu.3']='北京郵電大學' + ['mirrors.edu.4']='重慶大學' + ['mirrors.edu.5']='重慶郵電大學' + ['mirrors.edu.6']='大連東軟信息學院' + ['mirrors.edu.7']='電子科技大學' + ['mirrors.edu.8']='華南農業大學' + ['mirrors.edu.9']='華中科技大學' + ['mirrors.edu.10']='吉林大學' + ['mirrors.edu.11']='荊楚理工學院' + ['mirrors.edu.12']='江西理工大學' + ['mirrors.edu.13']='蘭州大學' + ['mirrors.edu.14']='南京大學' + ['mirrors.edu.15']='南京工業大學' + ['mirrors.edu.16']='南京郵電大學' + ['mirrors.edu.17']='南方科技大學' + ['mirrors.edu.18']='南陽理工學院' + ['mirrors.edu.19']='齊魯工業大學' + ['mirrors.edu.20']='清華大學' + ['mirrors.edu.21']='山東大學' + ['mirrors.edu.22']='上海科技大學' + ['mirrors.edu.23']='上海交通大學(思源)' + ['mirrors.edu.24']='上海交通大學(致遠)' + ['mirrors.edu.25']='武昌首義學院' + ['mirrors.edu.26']='西安交通大學' + ['mirrors.edu.27']='西北農林科技大學' + ['mirrors.edu.28']='浙江大學' + ['mirrors.edu.29']='中國科學技術大學' + ['mirrors.edu.30']='官方源' + ['mirrors.abroad.0']='亞洲 · xTom · 香港' + ['mirrors.abroad.1']='亞洲 · 01Link · 香港' + ['mirrors.abroad.2']='亞洲 · 新加坡國立大學(NUS) · 新加坡' + ['mirrors.abroad.3']='亞洲 · SG.GS · 新加坡' + ['mirrors.abroad.4']='亞洲 · xTom · 新加坡' + ['mirrors.abroad.5']='亞洲 · 自由軟體實驗室(NCHC) · 臺灣' + ['mirrors.abroad.6']='亞洲 · OSS Planet · 臺灣' + ['mirrors.abroad.7']='亞洲 · 國立陽明交通大學 · 臺灣' + ['mirrors.abroad.8']='亞洲 · 淡江大學 · 臺灣' + ['mirrors.abroad.9']='亞洲 · Taiwan Digital Streaming · 臺灣' + ['mirrors.abroad.10']='亞洲 · AniGil Linux Archive · 韓國' + ['mirrors.abroad.11']='亞洲 · 工業網路安全中心(ICSCoE) · 日本' + ['mirrors.abroad.12']='亞洲 · 北陸先端科學技術大學院大學(JAIST) · 日本' + ['mirrors.abroad.13']='亞洲 · 山形大學 · 日本' + ['mirrors.abroad.14']='亞洲 · xTom · 日本' + ['mirrors.abroad.15']='亞洲 · GB Network Solutions · 馬來西亞' + ['mirrors.abroad.16']='亞洲 · 孔敬大學 · 泰國' + ['mirrors.abroad.17']='歐洲 · Vorboss Ltd · 英國' + ['mirrors.abroad.18']='歐洲 · QuickHost · 英國' + ['mirrors.abroad.19']='歐洲 · dogado · 德國' + ['mirrors.abroad.20']='歐洲 · xTom · 德國' + ['mirrors.abroad.21']='歐洲 · 亞琛工業大學(RWTH Aachen) · 德國' + ['mirrors.abroad.22']='歐洲 · 德勒斯登大學(AG DSN) · 德國' + ['mirrors.abroad.23']='歐洲 · CCIN2P3 · 法國' + ['mirrors.abroad.24']='歐洲 · Ircam · 法國' + ['mirrors.abroad.25']='歐洲 · Crans · 法國' + ['mirrors.abroad.26']='歐洲 · CRIHAN · 法國' + ['mirrors.abroad.27']='歐洲 · xTom · 荷蘭' + ['mirrors.abroad.28']='歐洲 · DataPacket · 荷蘭' + ['mirrors.abroad.29']='歐洲 · Linux Kernel · 荷蘭' + ['mirrors.abroad.30']='歐洲 · xTom · 愛沙尼亞' + ['mirrors.abroad.31']='歐洲 · netsite · 丹麥' + ['mirrors.abroad.32']='歐洲 · Dotsrc · 丹麥' + ['mirrors.abroad.33']='歐洲 · Academic Computer Club · 瑞典' + ['mirrors.abroad.34']='歐洲 · Lysator · 瑞典' + ['mirrors.abroad.35']='歐洲 · Yandex · 俄羅斯' + ['mirrors.abroad.36']='歐洲 · ia64 · 俄羅斯' + ['mirrors.abroad.37']='歐洲 · Truenetwork · 俄羅斯' + ['mirrors.abroad.38']='歐洲 · Belgian Research Network · 比利時' + ['mirrors.abroad.39']='歐洲 · 克里特大學計算機中心 · 希臘' + ['mirrors.abroad.40']='歐洲 · 馬薩里克大學信息學院 · 捷克' + ['mirrors.abroad.41']='歐洲 · 捷克理工大學學生會俱樂部(Silicon Hill) · 捷克' + ['mirrors.abroad.42']='歐洲 · Vodafone · 捷克' + ['mirrors.abroad.43']='歐洲 · CZ.NIC · 捷克' + ['mirrors.abroad.44']='歐洲 · 蘇黎世聯邦理工學院 · 瑞士' + ['mirrors.abroad.45']='北美 · Linux Kernel · 美國' + ['mirrors.abroad.46']='北美 · 麻省理工學院(MIT) · 美國' + ['mirrors.abroad.47']='北美 · 普林斯頓大學數學系 · 美國' + ['mirrors.abroad.48']='北美 · 俄勒岡州立大學開源實驗室 · 美國' + ['mirrors.abroad.49']='北美 · Fremont Cabal Internet Exchange(FCIX) · 美國' + ['mirrors.abroad.50']='北美 · xTom · 美國' + ['mirrors.abroad.51']='北美 · Steadfast · 美國' + ['mirrors.abroad.52']='北美 · 不列顛哥倫比亞大學 · 加拿大' + ['mirrors.abroad.53']='北美 · GoCodeIT · 加拿大' + ['mirrors.abroad.54']='北美 · Switch · 加拿大' + ['mirrors.abroad.55']='南美 · PoP-SC · 巴西' + ['mirrors.abroad.56']='南美 · 蓬塔格羅薩州立大學 · 巴西' + ['mirrors.abroad.57']='南美 · UFSCar · 巴西' + ['mirrors.abroad.58']='南美 · Sysarmy Community · 阿根廷' + ['mirrors.abroad.59']='大洋 · Fremont Cabal Internet Exchange(FCIX) · 澳大利亞' + ['mirrors.abroad.60']='大洋 · AARNet · 澳大利亞' + ['mirrors.abroad.61']='大洋 · DataMossa · 澳大利亞' + ['mirrors.abroad.62']='大洋 · Amaze · 澳大利亞' + ['mirrors.abroad.63']='大洋 · xTom · 澳大利亞' + ['mirrors.abroad.64']='大洋 · Over the Wire · 澳大利亞' + ['mirrors.abroad.65']='大洋 · Free Software Mirror Group · 紐西蘭' + ['mirrors.abroad.66']='非洲 · Liquid Telecom · 肯亞' + ['mirrors.abroad.67']='非洲 · Dimension Data · 南非' + ['mirrors.abroad.68']='官方源' + ) + SPONSOR_ADS[0]="1Panel · 新一代的 Linux 伺服器維運管理面板 ➜ \033[3mhttps://1panel.cn\033[0m" +} + +function msg_pack_en() { + MESSAGE_CONTENTS=( + ['start.welcome']=' GNU/Linux mirror switching script' + ['start.runtimeEnv']='Runtime Env' + ['start.dateTime']='System Time' + ['end.moreInfo']='Script execution completed, visit our website for more tutorials' + ['end.sponsorAds']='[Sponsor Ads]' + ['error.cmd.options.needConfirm']='Please confirm and re-enter' + ['error.cmd.options.needSpecify']='Please specify {} after this option' + ['error.cmd.options.invalid']='Command option {} is invalid, {}!' + ['error.cmd.options.validAddress']='a valid address' + ['error.cmd.options.sourceAddress']='mirror address' + ['error.cmd.options.sourceRepository']='mirror repository' + ['error.cmd.options.codename']='version codename' + ['error.cmd.options.boolean']=' true or false ' + ['error.cmd.options.protocol']=' http or https ' + ['error.cmd.options.needProtocol']=' Web protocol(http/https)' + ['error.cmd.options.validLangKey']='A valid language ID ' + ['error.cmd.options.langKey']='language ID ' + ['error.cmd.options.unsupportTwoSourceMode']='Two mirror modes cannot be used at the same time. Please retry!' + ['error.cmd.options.unsupportCodename']='The current system does not support specifying a codename. Please retry!' + ['error.cmd.options.unsupportEPEL']='The current system cannot install the EPEL add-on package. Please retry!' + ['error.unsupportSystem']='The operating system ({}) is not supported. Check the supported list on the website!' + ['error.unsupportVersion']='The current system version is not supported' + ['error.unknownSystem']='Unknown system' + ['error.unknownVersion']='System version unknown' + ['error.input']='Input error, {}!' + ['error.needRoot']='Insufficient privileges, please run this script as root. Switch command: {}' + ['error.defaultBehavior.https']='HTTPS is used by default' + ['error.defaultBehavior.noReplace']='No replacement by default' + ['error.defaultBehavior.noOverwrite']='No overwrite by default' + ['error.defaultBehavior.noUpdate']='No update by default' + ['error.defaultBehavior.noClean']='No cleanup by default' + ['error.defaultBehavior.noUseIntranetSource']='Intranet mirrors are disabled by default' + ['warn.usedIntranetSource']='Switched to an intranet-only mirror. Use only in the intended environment!' + ['warn.unstableDebian']='Detected system version {} which may cause unpredictable issues.' + ['warn.EPEL7']='Extra Packages for Enterprise Linux 7 reached end-of-life and was moved to the archive!' + ['warn.needValidNumberIndex']='Please enter a valid number index!' + ['warn.needInputNumberIndex']='Please enter a number index!' + ['info.backuped.sourceFile']='Backed up existing {} source file' + ['tip.EPEL7']="Some mirrors don't sync that archive. If errors occur, verify the target mirror provides it." + ['interaction.source.type.public']='Public' + ['interaction.source.type.intranet']='Intranet' + ['interaction.source.type.select']='Please select network address (access method) for mirror:' + ['interaction.source.type.usePublicAddress']='Use public network address for mirror by default, continue' + ['interaction.source.select']='Please select the mirror you want to use:' + ['interaction.source.selectAndInput']='Please select and enter the mirror you want to use' + ['interaction.protocol.select']='Please select network protocol for mirror:' + ['interaction.protocol.useHttp']='Use HTTP protocol for mirror' + ['interaction.epel.skipReplace']='EPEL already installed. Replace/overwrite mirror' + ['interaction.epel.install']='Install EPEL add-on package' + ['interaction.backup.skipOverwrite.sourceFile']='A backup of {} already exists. Skip overwriting' + ['interaction.upgrade.skip']='Skip upgrading packages' + ['interaction.cache.autoClean']='Clean download cache after upgrading packages' + ['interaction.common.tip']='Tip' + ['interaction.common.operationCanceled']='Operation canceled' + ['interaction.common.yes']='Yes' + ['interaction.common.no']='No' + ['work.upgradeSoftware']='Upgrading packages' + ['work.installEPELPackage']='Installing epel-release package...' + ['source.sync.text1']='Update APT package index' + ['source.sync.text2']='Generate mirror cache' + ['source.sync.text3']='Refreshing mirrors' + ['source.sync.text4']='Synchronizing mirrors' + ['source.sync.text5']='Updating binary cache and channels' + ['source.comment.disabledSourceCode']='Source code mirrors are disabled by default for speed. Uncomment to enable' + ['source.comment.securitySource']='Security updates' + ['source.comment.proposedSource']='Proposed repository (not recommended)' + ['source.changeResult.success']='Mirror switching complete' + ['source.changeResult.fail']='Mirror switching complete, but {} failed' + ['source.changeResult.tipTitle']='Run the script again with the same mirror. If {} still fails, consider:' + ['source.changeResult.tip1']='Connectivity issues: unstable network, blocked access, or mirror-side firewall rules' + ['source.changeResult.tip2']='Mirror issues: test the mirror manually at {}' + ['source.changeResult.tip2.1']='If a file is missing, the mirror might still be syncing' + ['source.changeResult.tip2.2']='If a path is missing, the mirror may not provide this system repository' + ['source.changeResult.tip2.3']='Try another mirror. Syncing mirrors may temporarily serve broken content' + ['source.changeResult.tip3']='Original mirrors failing: fix unrelated mirror errors and rerun the script' + ['commands.help']='Command options(name/meaning/value): + + --abroad Use overseas mirrors none + --edu Use China education network mirrors none + --source Specify mirror address (domain or IP) address + --source-epel Specify EPEL repository address (domain or IP) address + --source-security Specify Debian/Ubuntu security repo address (domain or IP) address + --source-vault Specify CentOS/AlmaLinux vault repo address (domain or IP) address + --source-portage Specify Gentoo portage repo address (domain or IP) address + --source-base-system Specify Linux Mint/Raspberry Pi OS base system repo address (domain or IP) address + --branch Specify mirror repository (repo name) repo name + --branch-epel Specify EPEL repository (path) repo name + --branch-security Specify Debian security repo (path) repo name + --branch-vault Specify CentOS/AlmaLinux vault repo (path) repo name + --branch-portage Specify Gentoo portage repo (path) repo name + --branch-base-system Specify Linux Mint/Raspberry Pi OS base system repo (path) repo name + --codename Specify Debian/openKylin codename codename + --protocol Specify web protocol http or https + --use-intranet-source Prefer intranet mirror address true or false + --use-official-source Use official mirror of target OS true or false + --use-official-source-epel Use official EPEL repo true or false + --install-epel Install EPEL repository true or false + --backup Backup original mirrors true or false + --upgrade-software Upgrade packages true or false + --clean-cache Clean cache after upgrade true or false + --clean-screen Clear screen before running true or false + --lang Specify the language of the script output language + --only-epel Only switch EPEL repo none + --ignore-backup-tips Ignore backup overwrite prompt none + --print-diff Print diff before and after modification none + --pure-mode Pure mode, minimal output none + --help Show help menu none + +Issue Report {}' + ['mirrors.default.0']='Alibaba Cloud' + ['mirrors.default.1']='Tencent Cloud' + ['mirrors.default.2']='Huawei Cloud' + ['mirrors.default.3']='China Mobile Cloud' + ['mirrors.default.4']='China Telecom Cloud' + ['mirrors.default.5']='NetEase' + ['mirrors.default.6']='Volcengine' + ['mirrors.default.7']='Tsinghua University' + ['mirrors.default.8']='Peking University' + ['mirrors.default.9']='Zhejiang University' + ['mirrors.default.10']='Nanjing University' + ['mirrors.default.11']='Lanzhou University' + ['mirrors.default.12']='Shanghai Jiao Tong University' + ['mirrors.default.13']='Chongqing University of Posts and Telecommunications' + ['mirrors.default.14']='University of Science and Technology of China' + ['mirrors.default.15']='Institute of Software, Chinese Academy of Sciences' + ['mirrors.default.16']='Official Source' + ['mirrors.edu.0']='Peking University' + ['mirrors.edu.1']='Beijing Jiaotong University' + ['mirrors.edu.2']='Beijing Foreign Studies University' + ['mirrors.edu.3']='Beijing University of Posts and Telecommunications' + ['mirrors.edu.4']='Chongqing University' + ['mirrors.edu.5']='Chongqing University of Posts and Telecommunications' + ['mirrors.edu.6']='Dalian Neusoft University of Information' + ['mirrors.edu.7']='University of Electronic Science and Technology of China' + ['mirrors.edu.8']='South China Agricultural University' + ['mirrors.edu.9']='Huazhong University of Science and Technology' + ['mirrors.edu.10']='Jilin University' + ['mirrors.edu.11']='Jingchu University of Technology' + ['mirrors.edu.12']='Jiangxi University of Science and Technology' + ['mirrors.edu.13']='Lanzhou University' + ['mirrors.edu.14']='Nanjing University' + ['mirrors.edu.15']='Nanjing Tech University' + ['mirrors.edu.16']='Nanjing University of Posts and Telecommunications' + ['mirrors.edu.17']='Southern University of Science and Technology' + ['mirrors.edu.18']='Nanyang Institute of Technology' + ['mirrors.edu.19']='Qilu University of Technology' + ['mirrors.edu.20']='Tsinghua University' + ['mirrors.edu.21']='Shandong University' + ['mirrors.edu.22']='ShanghaiTech University' + ['mirrors.edu.23']='Shanghai Jiao Tong University (Siyuan)' + ['mirrors.edu.24']='Shanghai Jiao Tong University (Zhiyuan)' + ['mirrors.edu.25']='Wuchang Shouyi University' + ['mirrors.edu.26']="Xi'an Jiaotong University" + ['mirrors.edu.27']='Northwest A&F University' + ['mirrors.edu.28']='Zhejiang University' + ['mirrors.edu.29']='University of Science and Technology of China' + ['mirrors.edu.30']='Official Source' + ['mirrors.abroad.0']='AS · xTom · Hong Kong' + ['mirrors.abroad.1']='AS · 01Link · Hong Kong' + ['mirrors.abroad.2']='AS · National University of Singapore (NUS) · Singapore' + ['mirrors.abroad.3']='AS · SG.GS · Singapore' + ['mirrors.abroad.4']='AS · xTom · Singapore' + ['mirrors.abroad.5']='AS · NCHC Free Software Lab · Taiwan' + ['mirrors.abroad.6']='AS · OSS Planet · Taiwan' + ['mirrors.abroad.7']='AS · National Yang Ming Chiao Tung University · Taiwan' + ['mirrors.abroad.8']='AS · Tamkang University · Taiwan' + ['mirrors.abroad.9']='AS · Taiwan Digital Streaming · Taiwan' + ['mirrors.abroad.10']='AS · AniGil Linux Archive · Korea' + ['mirrors.abroad.11']='AS · ICSCoE (Industrial Cyber Security Center of Excellence) · Japan' + ['mirrors.abroad.12']='AS · JAIST (Japan Advanced Institute of Science and Technology) · Japan' + ['mirrors.abroad.13']='AS · Yamagata University · Japan' + ['mirrors.abroad.14']='AS · xTom · Japan' + ['mirrors.abroad.15']='AS · GB Network Solutions · Malaysia' + ['mirrors.abroad.16']='AS · Khon Kaen University · Thailand' + ['mirrors.abroad.17']='EU · Vorboss Ltd · United Kiongdom' + ['mirrors.abroad.18']='EU · QuickHost · United Kiongdom' + ['mirrors.abroad.19']='EU · dogado · Germany' + ['mirrors.abroad.20']='EU · xTom · Germany' + ['mirrors.abroad.21']='EU · RWTH Aachen University · Germany' + ['mirrors.abroad.22']='EU · Dresden University (AG DSN) · Germany' + ['mirrors.abroad.23']='EU · CCIN2P3 · France' + ['mirrors.abroad.24']='EU · Ircam · France' + ['mirrors.abroad.25']='EU · Crans · France' + ['mirrors.abroad.26']='EU · CRIHAN · France' + ['mirrors.abroad.27']='EU · xTom · Netherlands' + ['mirrors.abroad.28']='EU · DataPacket · Netherlands' + ['mirrors.abroad.29']='EU · Linux Kernel · Netherlands' + ['mirrors.abroad.30']='EU · xTom · Estonia' + ['mirrors.abroad.31']='EU · netsite · Denmark' + ['mirrors.abroad.32']='EU · Dotsrc · Denmark' + ['mirrors.abroad.33']='EU · Academic Computer Club · Sweden' + ['mirrors.abroad.34']='EU · Lysator · Sweden' + ['mirrors.abroad.35']='EU · Yandex · Russia' + ['mirrors.abroad.36']='EU · ia64 · Russia' + ['mirrors.abroad.37']='EU · Truenetwork · Russia' + ['mirrors.abroad.38']='EU · Belgian Research Network · Belgium' + ['mirrors.abroad.39']='EU · University of Crete Computer Center · Greece' + ['mirrors.abroad.40']='EU · Masaryk University Faculty of Informatics · Czech' + ['mirrors.abroad.41']='EU · Czech Technical University Student Club (Silicon Hill) · Czech' + ['mirrors.abroad.42']='EU · Vodafone · Czech' + ['mirrors.abroad.43']='EU · CZ.NIC · Czech' + ['mirrors.abroad.44']='EU · ETH Zurich · Switzerland' + ['mirrors.abroad.45']='NA · Linux Kernel · United States' + ['mirrors.abroad.46']='NA · MIT · United States' + ['mirrors.abroad.47']='NA · Princeton University Department of Mathematics · United States' + ['mirrors.abroad.48']='NA · Oregon State University Open Source Lab · United States' + ['mirrors.abroad.49']='NA · Fremont Cabal Internet Exchange(FCIX) · United States' + ['mirrors.abroad.50']='NA · xTom · United States' + ['mirrors.abroad.51']='NA · Steadfast · United States' + ['mirrors.abroad.52']='NA · University of British Columbia · Canada' + ['mirrors.abroad.53']='NA · GoCodeIT · Canada' + ['mirrors.abroad.54']='NA · Switch · Canada' + ['mirrors.abroad.55']='SA · PoP-SC · Brazil' + ['mirrors.abroad.56']='SA · State University of Ponta Grossa · Brazil' + ['mirrors.abroad.57']='SA · UFSCar · Brazil' + ['mirrors.abroad.58']='SA · Sysarmy Community · Argentina' + ['mirrors.abroad.59']='OC · Fremont Cabal Internet Exchange(FCIX) · Australia' + ['mirrors.abroad.60']='OC · AARNet · Australia' + ['mirrors.abroad.61']='OC · DataMossa · Australia' + ['mirrors.abroad.62']='OC · Amaze · Australia' + ['mirrors.abroad.63']='OC · xTom · Australia' + ['mirrors.abroad.64']='OC · Over the Wire · Australia' + ['mirrors.abroad.65']='OC · Free Software Mirror Group · New Zealand' + ['mirrors.abroad.66']='AF · Liquid Telecom · Kenya' + ['mirrors.abroad.67']='AF · Dimension Data · South Africa' + ['mirrors.abroad.68']='Official Source' + ) + SPONSOR_ADS=( + "1Panel · Top-Rated Web-based Linux Server Management Tool ➜ \033[3mhttps://1panel.cn\033[0m" + ) +} + +############################################################################## + +init_msg_pack +handle_command_options "$@" +main diff --git a/change-mirror/DockerInstallation.sh b/change-mirror/DockerInstallation.sh new file mode 100644 index 0000000..fa0c167 --- /dev/null +++ b/change-mirror/DockerInstallation.sh @@ -0,0 +1,2569 @@ +#!/bin/bash +## Author: SuperManito +## Modified: 2025-12-06 +## License: MIT +## GitHub: https://github.com/SuperManito/LinuxMirrors +## Website: https://linuxmirrors.cn + +## Docker CE 软件源列表 +mirror_list_docker_ce=( + "mirrors.aliyun.com/docker-ce" + "mirrors.tencent.com/docker-ce" + "mirrors.huaweicloud.com/docker-ce" + "mirrors.cmecloud.cn/docker-ce" + "mirrors.163.com/docker-ce" + "mirrors.volces.com/docker" + "mirror.azure.cn/docker-ce" + "mirrors.tuna.tsinghua.edu.cn/docker-ce" + "mirrors.pku.edu.cn/docker-ce" + "mirrors.zju.edu.cn/docker-ce" + "mirrors.nju.edu.cn/docker-ce" + "mirror.sjtu.edu.cn/docker-ce" + "mirrors.cqupt.edu.cn/docker-ce" + "mirrors.ustc.edu.cn/docker-ce" + "mirror.iscas.ac.cn/docker-ce" + "download.docker.com" +) + +## Docker Registry 仓库列表 +mirror_list_registry=( + "docker.1ms.run" + "dockerproxy.net" + "docker.m.daocloud.io" + "docker.1panel.live" + "registry.cn-hangzhou.aliyuncs.com" + "registry.cn-shanghai.aliyuncs.com" + "registry.cn-qingdao.aliyuncs.com" + "registry.cn-beijing.aliyuncs.com" + "registry.cn-zhangjiakou.aliyuncs.com" + "registry.cn-huhehaote.aliyuncs.com" + "registry.cn-wulanchabu.aliyuncs.com" + "registry.cn-shenzhen.aliyuncs.com" + "registry.cn-heyuan.aliyuncs.com" + "registry.cn-guangzhou.aliyuncs.com" + "registry.cn-chengdu.aliyuncs.com" + "registry.cn-hongkong.aliyuncs.com" + "registry.ap-northeast-1.aliyuncs.com" + "registry.ap-southeast-1.aliyuncs.com" + "registry.ap-southeast-3.aliyuncs.com" + "registry.ap-southeast-5.aliyuncs.com" + "registry.eu-central-1.aliyuncs.com" + "registry.eu-west-1.aliyuncs.com" + "registry.us-west-1.aliyuncs.com" + "registry.us-east-1.aliyuncs.com" + "registry.me-east-1.aliyuncs.com" + "mirror.ccs.tencentyun.com" + "gcr.io" + "asia.gcr.io" + "eu.gcr.io" + "registry.hub.docker.com" +) + +## 配置需要区分公网地址和内网地址的软件源(不分地域) +# 需要同时在两个数组变量中分别定义软件源地址,并且保证排列顺序一致 +# 软件源公网地址列表 +mirror_list_extranet=( + "mirrors.aliyun.com/docker-ce" + "mirrors.tencent.com/docker-ce" + "mirrors.huaweicloud.com/docker-ce" + "mirrors.volces.com/docker-ce" +) +# 软件源内网地址列表 +mirror_list_intranet=( + "mirrors.cloud.aliyuncs.com/docker-ce" + "mirrors.tencentyun.com/docker-ce" + "mirrors.myhuaweicloud.com/docker-ce" + "mirrors.ivolces.com/docker-ce" +) + +## 赞助商广告 +SPONSOR_ADS=( + "1Panel · Linux 面板|极简运维 ➜ \033[3mhttps://1panel.cn\033[0m" + "多途云 · 智能化防护,每一次连接皆在安全之下 ➜ \033[3mhttps://www.duotuyun.com\033[0m" + "毫秒镜像 · 专为中国开发者提供Docker镜像加速下载服务 ➜ \033[3mhttps://1ms.run\033[0m" + "林枫云 · 专注独立IP高频VPS|R9/i9系列定制 ➜ \033[3mhttps://www.dkdun.cn\033[0m" + "不死鸟CDN · 香港日本高防CDN,免实名/免备案,轻松阻断DDOS/CC攻击 ➜ \033[3mhttps://www.bsncdn.org\033[0m" + "青叶云 · 香港1T高防|自助防火墙,无视CC|大带宽回国优化线路 ➜ \033[3mhttps://www.qingyeyun.com\033[0m" + "莱卡云 · 专业云计算服务器提供商 ➜ \033[3m https://www.lcayun.com\033[0m" + "云悠YUNYOO · 全球高性价比云服务器|低至15.99元起 ➜ \033[3mhttps://yunyoo.cc\033[0m" + "HKGserver · 全球家宽|双ISP|住宅原生云服务器54元/月起 ➜ \033[3mhttps://www.hkgserver.com\033[0m" + "速拓云 · 国内高防云28元/月|香港云100M优化线路9元/月 ➜ \033[3mhttps://www.sutuoyun.com\033[0m" + "语鹿云盾 · 专业CDN加速、防御,亚太百兆三网优化CDN低至9元起 ➜ \033[3mhttps://www.lucdn.cn\033[0m" + "不二云 · 国内外建站快响应服务器的不二之选 ➜ \033[3mhttps://cb2.cn\033[0m" + "CN2network · 超低价优质机器免实名自动开通 ➜ \033[3mhttps://idc.cn2network.com\033[0m" + "破碎工坊云 · 专注高性能国内外云服务器 ➜ \033[3mhttps://www.crash.work\033[0m" + "润信云 · 国内挂机宝海外云服务器低至9.9元/月 ➜ \033[3mhttps://www.runxinyun.com\033[0m" + "浪浪云 · BGP网络让每一次连接都纵享丝滑,明码标价、无套路续费 ➜ \033[3mhttps://langlangy.cn\033[0m" +) + +############################################################################## + +## 定义系统判定变量 +SYSTEM_DEBIAN="Debian" +SYSTEM_UBUNTU="Ubuntu" +SYSTEM_KALI="Kali" +SYSTEM_DEEPIN="Deepin" +SYSTEM_LINUX_MINT="Linuxmint" +SYSTEM_ZORIN="Zorin" +SYSTEM_RASPBERRY_PI_OS="Raspberry Pi OS" +SYSTEM_REDHAT="RedHat" +SYSTEM_RHEL="Red Hat Enterprise Linux" +SYSTEM_CENTOS="CentOS" +SYSTEM_CENTOS_STREAM="CentOS Stream" +SYSTEM_ROCKY="Rocky" +SYSTEM_ALMALINUX="AlmaLinux" +SYSTEM_FEDORA="Fedora" +SYSTEM_ORACLE="Oracle Linux" +SYSTEM_OPENCLOUDOS="OpenCloudOS" +SYSTEM_OPENCLOUDOS_STREAM="OpenCloudOS Stream" +SYSTEM_TENCENTOS="TencentOS" +SYSTEM_OPENEULER="openEuler" +SYSTEM_ANOLISOS="Anolis" +SYSTEM_KYLIN_DESKTOP="Kylin Desktop" +SYSTEM_KYLIN_SERVER="Kylin Server" +SYSTEM_OPENKYLIN="openKylin" +SYSTEM_OPENSUSE="openSUSE" +SYSTEM_ARCH="Arch" +SYSTEM_MANJARO="Manjaro" +SYSTEM_ALPINE="Alpine" +SYSTEM_GENTOO="Gentoo" +SYSTEM_NIXOS="NixOS" + +## 定义系统版本文件 +File_LinuxRelease=/etc/os-release +File_RedHatRelease=/etc/redhat-release +File_DebianVersion=/etc/debian_version +File_ArmbianRelease=/etc/armbian-release +File_RaspberryPiOSRelease=/etc/rpi-issue +File_openEulerRelease=/etc/openEuler-release +File_HuaweiCloudEulerOSRelease=/etc/hce-release +File_OpenCloudOSRelease=/etc/opencloudos-release +File_TencentOSServerRelease=/etc/tlinux-release +File_AnolisOSRelease=/etc/anolis-release +File_AlibabaCloudLinuxRelease=/etc/alinux-release +File_OracleLinuxRelease=/etc/oracle-release +File_ArchLinuxRelease=/etc/arch-release +File_ManjaroRelease=/etc/manjaro-release +File_AlpineRelease=/etc/alpine-release +File_GentooRelease=/etc/gentoo-release +File_KylinRelease=/etc/kylin-release +File_kylinVersion=/etc/kylin-version/kylin-system-version.conf +File_ProxmoxVersion=/etc/pve/.version + +## 定义软件源相关文件或目录 +File_AptSourceList=/etc/apt/sources.list +Dir_AptAdditionalSources=/etc/apt/sources.list.d +Dir_YumRepos=/etc/yum.repos.d + +## 定义 Docker 相关变量 +Dir_Docker=/etc/docker +File_DockerConfig=$Dir_Docker/daemon.json +File_DockerConfigBackup=$Dir_Docker/daemon.json.bak +File_DockerVersionTmp=docker-version.txt +File_DockerCEVersionTmp=docker-ce-version.txt +File_DockerCECliVersionTmp=docker-ce-cli-version.txt +File_DockerSourceList=$Dir_AptAdditionalSources/docker.list +File_DockerRepo=$Dir_YumRepos/docker-ce.repo + +## 定义颜色和样式变量 +RED='\033[31m' +GREEN='\033[32m' +YELLOW='\033[33m' +BLUE='\033[34m' +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 WARN ${PLAIN}" +ERROR="\033[1;31m✘${PLAIN}" +FAIL="\033[1;31m✘${PLAIN}" +TIP="\033[1;44m TIP ${PLAIN}" +WORKING="\033[1;36m◉${PLAIN}" + +function main() { + permission_judgment + collect_system_info + run_start + choose_mirrors + if [[ "${ONLY_REGISTRY}" == "true" ]]; then + only_change_docker_registry_mirror + else + choose_protocol + close_firewall_service + install_dependency_packages + configure_docker_ce_mirror + install_docker_engine + change_docker_registry_mirror + check_installed_result + fi + run_end +} + +function handle_command_options() { + ## 判断参数 + while [ $# -gt 0 ]; do + case "$1" in + ## 指定 Docker CE 软件源地址 + --source) + if [ "$2" ]; then + echo "$2" | grep -Eq "\(|\)|\[|\]|\{|\}" + if [ $? -eq 0 ]; then + command_error "$2" "$(msg "error.cmd.options.validAddress")" + else + SOURCE="$(echo "$2" | sed -e 's,^http[s]\?://,,g' -e 's,/$,,')" + shift + fi + else + command_error "$1" "$(msg "error.cmd.options.sourceAddress")" + fi + ;; + ## 指定 Docker Registry 仓库地址 + --source-registry) + if [ "$2" ]; then + echo "$2" | grep -Eq "\(|\)|\[|\]|\{|\}" + if [ $? -eq 0 ]; then + command_error "$2" "$(msg "error.cmd.options.validAddress")" + else + SOURCE_REGISTRY="$(echo "$2" | sed -e 's,^http[s]\?://,,g' -e 's,/$,,')" + shift + fi + else + command_error "$1" "$(msg "error.cmd.options.registryAddress")" + fi + ;; + ## 指定 Docker CE 软件源仓库 + --branch) + if [ "$2" ]; then + SOURCE_BRANCH="$2" + shift + else + command_error "$1" "$(msg "error.cmd.options.sourceRepository")" + fi + ;; + ## 指定 Docker CE 软件源仓库版本 + --branch-version) + if [ "$2" ]; then + echo "$2" | grep -Eq "^[0-9]{1,2}$" + if [ $? -eq 0 ]; then + SOURCE_BRANCH_VERSION="$2" + shift + else + command_error "$2" "$(msg "error.cmd.options.validVersion")" + fi + else + command_error "$1" "$(msg "error.cmd.options.ceRepositoryVersion")" + fi + ;; + ## 指定 Docker Engine 安装版本 + --designated-version) + if [ "$2" ]; then + echo "$2" | grep -Eq "^[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}$" + if [ $? -eq 0 ]; then + DESIGNATED_DOCKER_VERSION="$2" + shift + else + command_error "$2" "$(msg "error.cmd.options.validVersion")" + fi + else + command_error "$1" "$(msg "error.cmd.options.version")" + fi + ;; + ## 指定 Debian 版本代号 + --codename) + if [ "$2" ]; then + DEBIAN_CODENAME="$2" + shift + else + command_error "$1" "$(msg "error.cmd.options.codename")" + fi + ;; + ## Web 协议(HTTP/HTTPS) + --protocol) + if [ "$2" ]; then + case "$2" in + http | https | HTTP | HTTPS) + WEB_PROTOCOL="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.protocol")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.needProtocol")" + fi + ;; + ## 使用内网地址 + --use-intranet-source) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + USE_INTRANET_SOURCE="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.needIntranetSource")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.needIntranetSource")" + fi + ;; + ## 安装最新版本 + --install-latest | --install-latested) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + INSTALL_LATESTED_DOCKER="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.needIntranetSource")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.needIntranetSource")" + fi + ;; + ## 忽略覆盖备份提示 + --ignore-backup-tips) + IGNORE_BACKUP_TIPS="true" + ;; + ## 关闭防火墙 + --close-firewall) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + CLOSE_FIREWALL="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.needIntranetSource")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.needIntranetSource")" + fi + ;; + ## 清除屏幕上的所有内容 + --clean-screen) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + CLEAN_SCREEN="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.needIntranetSource")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.needIntranetSource")" + fi + ;; + ## Locale + --lang) + if [ "$2" ]; then + local lang_norm="${2//_/-}" + lang_norm="${lang_norm,,}" + case "$lang_norm" in + zh | zh-cn | zh-hans | zh-hans-*) + init_msg_pack "zh-hans" + shift + ;; + zh-hant | zh-hant-* | zh-tw | zh-hk) + init_msg_pack "zh-hant" + shift + ;; + en | en-us | en-*) + init_msg_pack "en" + shift + ;; + auto) + choose_display_language + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.validLangKey")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.langKey")" + fi + ;; + --zh | --zh-[Cc][Nn]) + init_msg_pack "zh-hans" + ;; + --en | --en-[Uu][Ss]) + init_msg_pack "en" + ;; + --zh-[Hh]an[st]) + init_msg_pack "$1" + ;; + ## 仅更换镜像仓库模式 + --only-registry) + ONLY_REGISTRY="true" + ;; + ## 纯净模式 + --pure-mode) + PURE_MODE="true" + ;; + ## 命令帮助 + --help) + echo -e "\n$(msg "commands.help" "https://github.com/SuperManito/LinuxMirrors/issues")\n" + exit + ;; + *) + command_error "$1" + ;; + esac + shift + done + ## 设置部分功能的默认值 + IGNORE_BACKUP_TIPS="${IGNORE_BACKUP_TIPS:-"false"}" + if [[ "${DESIGNATED_DOCKER_VERSION}" ]]; then + INSTALL_LATESTED_DOCKER="false" + fi + PURE_MODE="${PURE_MODE:-"false"}" +} + +function run_start() { + if [ -z "${CLEAN_SCREEN}" ]; then + if [[ "${ONLY_REGISTRY}" == "true" ]]; then + [[ -z "${SOURCE_REGISTRY}" ]] && clear + else + [[ -z "${SOURCE}" || -z "${SOURCE_REGISTRY}" ]] && clear + fi + elif [ "${CLEAN_SCREEN}" == "true" ]; then + clear + fi + if [[ "${PURE_MODE}" == "true" ]]; then + return + fi + local system_name="${SYSTEM_PRETTY_NAME:-"${SYSTEM_NAME} ${SYSTEM_VERSION_ID}"}" + local arch="${DEVICE_ARCH}" + local date_time="$(date "+%Y-%m-%d %H:%M")" + local time_zone="$(timedatectl status 2>/dev/null | grep "Time zone" | awk -F ':' '{print$2}' | awk -F ' ' '{print$1}')" + echo -e "+-----------------------------------+" + echo -e "| \033[0;1;35;95m⡇\033[0m \033[0;1;33;93m⠄\033[0m \033[0;1;32;92m⣀⡀\033[0m \033[0;1;36;96m⡀\033[0;1;34;94m⢀\033[0m \033[0;1;35;95m⡀⢀\033[0m \033[0;1;31;91m⡷\033[0;1;33;93m⢾\033[0m \033[0;1;32;92m⠄\033[0m \033[0;1;36;96m⡀⣀\033[0m \033[0;1;34;94m⡀\033[0;1;35;95m⣀\033[0m \033[0;1;31;91m⢀⡀\033[0m \033[0;1;33;93m⡀\033[0;1;32;92m⣀\033[0m \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[0m \033[0;1;36;96m⠇⠸\033[0m \033[0;1;34;94m⠣\033[0;1;35;95m⠼\033[0m \033[0;1;31;91m⠜⠣\033[0m \033[0;1;33;93m⠇\033[0;1;32;92m⠸\033[0m \033[0;1;36;96m⠇\033[0m \033[0;1;34;94m⠏\033[0m \033[0;1;35;95m⠏\033[0m \033[0;1;33;93m⠣⠜\033[0m \033[0;1;32;92m⠏\033[0m \033[0;1;34;94m⠭⠕\033[0m |" + echo -e "+-----------------------------------+" + echo -e "$(msg "start.welcome")" + echo -e '' + echo -e "$(msg "start.runtimeEnv") ${BLUE}${system_name} ${arch}${PLAIN}" + echo -e "$(msg "start.dateTime") ${BLUE}${date_time} ${time_zone}${PLAIN}" + sleep 1 >/dev/null 2>&1 +} + +function run_end() { + if [[ "${PURE_MODE}" == "true" ]]; then + echo '' + return + fi + echo -e "\n✨ $(msg "end.moreInfo") 👉 \033[3mhttps://linuxmirrors.cn\033[0m" + if [[ "${#SPONSOR_ADS[@]}" -gt 0 ]]; then + echo -e "\n\033[2m$(msg "end.sponsorAds")\033[0m" + for ad in "${SPONSOR_ADS[@]}"; do + sleep 0.1 + echo -e " \033[2m${ad}\033[0m" + done + fi + echo -e "\n\033[3;1mPowered by \033[34mLinuxMirrors\033[0m\n" +} + +function output_error() { + [ "$1" ] && echo -e "\n$ERROR $1\n" + exit 1 +} + +function command_error() { + local tmp_text="$(msg "error.cmd.options.needConfirm")" + if [[ "${2}" ]]; then + tmp_text="$(msg "error.cmd.options.needSpecify" "${2}")" + fi + output_error "$(msg "error.cmd.options.invalid" "${BLUE}$1${PLAIN}" "${tmp_text}")" +} + +function unsupport_system_error() { + if [[ "${2}" ]]; then + output_error "$(msg "error.unsupportSystem2" "${1}")\n\n${BLUE}$2${PLAIN}" + else + output_error "$(msg "error.unsupportSystem1" "${1}")" + fi +} + +function input_error() { + echo -e "\n$WARN $(msg "error.input" "${1}")" +} + +function command_exists() { + command -v "$@" &>/dev/null +} + +function permission_judgment() { + if [ $UID -ne 0 ]; then + local change_cmd="su root" + if command_exists sudo; then + change_cmd="sudo -i" + fi + output_error "$(msg "error.needRoot" "${BLUE}${change_cmd}${PLAIN}")" + fi +} + +function get_os_release_value() { + grep -E "^${1}=" $File_LinuxRelease | cut -d= -f2- | sed "s/[\'\"]//g" +} + +function collect_system_info() { + if [ ! -s "${File_LinuxRelease}" ]; then + unsupport_system_error "$(msg "error.unknownSystem")" + fi + ## 定义系统名称 + SYSTEM_NAME="$(get_os_release_value NAME)" + SYSTEM_PRETTY_NAME="$(get_os_release_value PRETTY_NAME)" + ## 定义系统版本号 + SYSTEM_VERSION_ID="$(get_os_release_value VERSION_ID)" + SYSTEM_VERSION_ID_MAJOR="${SYSTEM_VERSION_ID%%.*}" + SYSTEM_VERSION_ID_MINOR="${SYSTEM_VERSION_ID#*.}" + ## 定义系统ID + SYSTEM_ID="$(get_os_release_value ID)" + ## 判定当前系统派系 + if [ -s "${File_DebianVersion}" ]; then + SYSTEM_FACTIONS="${SYSTEM_DEBIAN}" + if [ -s "${File_kylinVersion}" ]; then + [[ "${ONLY_REGISTRY}" != "true" ]] && unsupport_system_error "Kylin Desktop" "apt-get install -y docker\nsystemctl enable --now docker.io" + fi + elif [ -s "${File_RedHatRelease}" ]; then + SYSTEM_FACTIONS="${SYSTEM_REDHAT}" + elif [ -s "${File_openEulerRelease}" ] || [ -s "${File_HuaweiCloudEulerOSRelease}" ]; 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_TencentOSServerRelease}" ]; then + SYSTEM_FACTIONS="${SYSTEM_TENCENTOS}" # 自 4 版本起不再基于红帽 + elif [ -s "${File_kylinVersion}" ] || [ -s "${File_KylinRelease}" ]; then + if [[ "${SYSTEM_ID}" == *"openkylin"* ]]; then + SYSTEM_FACTIONS="${SYSTEM_OPENKYLIN}" + else + SYSTEM_FACTIONS="${SYSTEM_KYLIN_SERVER}" + fi + elif [ -f "${File_ArchLinuxRelease}" ]; then + [[ "${ONLY_REGISTRY}" != "true" ]] && unsupport_system_error "Arch Linux" "pacman -S docker\nsystemctl enable --now docker" + elif [ -f "${File_GentooRelease}" ]; then + [[ "${ONLY_REGISTRY}" != "true" ]] && unsupport_system_error "Gentoo" + elif [[ "${SYSTEM_NAME}" == *"openSUSE"* ]]; then + [[ "${ONLY_REGISTRY}" != "true" ]] && unsupport_system_error "openSUSE" "zypper install docker\nsystemctl enable --now docker" + elif [[ "${SYSTEM_NAME}" == *"NixOS"* ]]; then + [[ "${ONLY_REGISTRY}" != "true" ]] && unsupport_system_error "NixOS" + else + unsupport_system_error "$(msg "error.unknownSystem")" + fi + ## 判定系统类型、版本、版本号 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + if command_exists lsb_release; then + SYSTEM_JUDGMENT="$(lsb_release -is)" + SYSTEM_VERSION_CODENAME="${DEBIAN_CODENAME:-"$(lsb_release -cs)"}" + else + ## https://codeberg.org/gioele/lsb-release-minimal + SYSTEM_JUDGMENT="${SYSTEM_ID^}" + if [ "${SYSTEM_NAME}" ]; then + if [[ "${SYSTEM_ID,,}" == "${SYSTEM_NAME,,}" ]]; then + SYSTEM_JUDGMENT="${SYSTEM_NAME}" + fi + fi + SYSTEM_VERSION_CODENAME="${DEBIAN_CODENAME:-"$(get_os_release_value VERSION_CODENAME)"}" + fi + # Raspberry Pi OS + if [ -s "${File_RaspberryPiOSRelease}" ]; then + SYSTEM_JUDGMENT="${SYSTEM_RASPBERRY_PI_OS}" + SYSTEM_PRETTY_NAME="${SYSTEM_RASPBERRY_PI_OS}" + fi + ;; + "${SYSTEM_REDHAT}") + SYSTEM_JUDGMENT="$(awk '{printf $1}' $File_RedHatRelease)" + ## 特殊系统判断 + # Red Hat Enterprise Linux + grep -q "${SYSTEM_RHEL}" $File_RedHatRelease && SYSTEM_JUDGMENT="${SYSTEM_RHEL}" + # CentOS Stream + grep -q "${SYSTEM_CENTOS_STREAM}" $File_RedHatRelease && SYSTEM_JUDGMENT="${SYSTEM_CENTOS_STREAM}" + # Oracle Linux + [ -s "${File_OracleLinuxRelease}" ] && SYSTEM_JUDGMENT="${SYSTEM_ORACLE}" + ;; + *) + SYSTEM_JUDGMENT="${SYSTEM_FACTIONS}" + ;; + esac + ## 判定系统处理器架构 + DEVICE_ARCH_RAW="$(uname -m)" + case "${DEVICE_ARCH_RAW}" in + x86_64) + DEVICE_ARCH="x86_64" + ;; + aarch64) + DEVICE_ARCH="ARM64" + ;; + armv8l) + DEVICE_ARCH="ARMv8_32" + ;; + armv7l) + DEVICE_ARCH="ARMv7" + ;; + armv6l) + DEVICE_ARCH="ARMv6" + ;; + armv5tel) + DEVICE_ARCH="ARMv5" + ;; + ppc64le) + DEVICE_ARCH="ppc64le" + ;; + s390x) + DEVICE_ARCH="s390x" + ;; + i386 | i686) + output_error "$(msg "error.unsupportX86_32")" + ;; + *) + output_error "$(msg "error.unknownArch" "${DEVICE_ARCH_RAW}")" + ;; + esac + ## 定义软件源仓库名称 + if [[ -z "${SOURCE_BRANCH}" ]]; then + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + local debian_codename_latest="trixie" + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_DEBIAN}") + SOURCE_BRANCH="debian" + ;; + "${SYSTEM_UBUNTU}" | "${SYSTEM_ZORIN}") + SOURCE_BRANCH="ubuntu" + ;; + "${SYSTEM_KALI}") + SOURCE_BRANCH="debian" + SOURCE_BRANCH_CODENAME="${debian_codename_latest}" + ;; + "${SYSTEM_LINUX_MINT}") + if [[ "${SYSTEM_NAME}" == *"LMDE"* ]]; then + SOURCE_BRANCH="debian" + SOURCE_BRANCH_CODENAME="$(get_os_release_value DEBIAN_CODENAME)" + else + SOURCE_BRANCH="ubuntu" + SOURCE_BRANCH_CODENAME="$(get_os_release_value UBUNTU_CODENAME)" + fi + if [[ -z "${SOURCE_BRANCH_CODENAME}" ]]; then + SOURCE_BRANCH="debian" + SOURCE_BRANCH_CODENAME="bookworm" + fi + ;; + "${SYSTEM_RASPBERRY_PI_OS}") + case "${DEVICE_ARCH_RAW}" in + x86_64 | aarch64) + SOURCE_BRANCH="debian" + ;; + *) + # 注:自 Docker 29 版本起将不再提供此分支仓库 + SOURCE_BRANCH="raspbian" + ;; + esac + ;; + # "${SYSTEM_KYLIN_DESKTOP}") + # SOURCE_BRANCH="ubuntu" + # case "${SYSTEM_VERSION_ID_MAJOR}" in + # "v10") + # SOURCE_BRANCH_CODENAME="focal" + # ;; + # "v11") + # SOURCE_BRANCH_CODENAME="noble" + # ;; + # *) + # SOURCE_BRANCH_CODENAME="noble" + # ;; + # esac + # ;; + "${SYSTEM_OPENKYLIN}") + SOURCE_BRANCH="debian" + SOURCE_BRANCH_CODENAME="${debian_codename_latest}" + ;; + *) + # 其余 Debian 系衍生操作系统 + SOURCE_BRANCH="debian" + SOURCE_BRANCH_CODENAME="bookworm" + ;; + esac + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_FEDORA}") + SOURCE_BRANCH="fedora" + ;; + "${SYSTEM_RHEL}") + SOURCE_BRANCH="rhel" + ;; + *) + SOURCE_BRANCH="centos" + ;; + esac + if [[ "${DEVICE_ARCH_RAW}" == "s390x" ]]; then + output_error "$(msg "error.unsupportS390x")" + fi + ;; + esac + fi + ## 定义软件源更新文字 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + SYNC_MIRROR_TEXT="$(msg "source.sync.text1")" + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + SYNC_MIRROR_TEXT="$(msg "source.sync.text2")" + ;; + esac + ## 判断是否可以使用高级交互式选择器 + CAN_USE_ADVANCED_INTERACTIVE_SELECTION="false" + if command_exists tput; then + CAN_USE_ADVANCED_INTERACTIVE_SELECTION="true" + fi +} + +## 选择显示语言 +function choose_display_language() { + local result + if command_exists tput; then + local -a lang_key_labels=() + local language_text + for ((i = 0; i < ${#MESSAGE_LANG_KEYS[@]}; i++)); do + language_text="${MESSAGE_LANG_DISPLAY[${MESSAGE_LANG_KEYS[$i]}]}" + if [[ "${language_text}" ]]; then + lang_key_labels+=("${language_text}") + else + lang_key_labels+=("") + fi + done + interactive_select_list "MESSAGE_LANG_KEYS" "\n ${BOLD}Please select the display language:${PLAIN}\n" "lang_key_labels" + result="${_SELECT_RESULT%%@@*}" + else + echo '' + for ((i = 0; i < ${#MESSAGE_LANG_KEYS[@]}; i++)); do + echo -e " $((i + 1)). ${MESSAGE_LANG_DISPLAY[${MESSAGE_LANG_KEYS[$i]}]}" + done + local CHOICE="$(echo -e "\n${BOLD}└─ Please select and enter the display language [ 1-${#MESSAGE_LANG_KEYS[@]} ]:${PLAIN}")" + while true; do + read -rp "${CHOICE}" INPUT + case "${INPUT}" in + [1-9] | [1-9][0-9]) + local tmp_result="${MESSAGE_LANG_KEYS[$((INPUT - 1))]}" + if [[ -z "${tmp_result}" ]]; then + echo -e "\n$WARN $(msg "warn.needValidNumberIndex")" + else + result="${tmp_result}" + break + fi + ;; + *) + echo -e "\n$WARN $(msg "warn.needInputNumberIndex")" + ;; + esac + done + fi + init_msg_pack "${result}" +} + +function choose_mirrors() { + ## 打印软件源列表 + function print_mirrors_list() { + local tmp_name tmp_index i j + function StringLength() { + local text=$1 + echo "${#text}" + } + local -a list_arr=() + local list_arr_sum="$(eval echo \${#$1[@]})" + for ((i = 0; i < $list_arr_sum; i++)); do + list_arr[$i]="$(eval echo \${$1[i]})" + done + local name_width=${2:-"30"} + local -a list_labels=() + if [[ "${3}" ]]; then + eval "list_labels=(\"\${${3}[@]}\")" + fi + if command_exists printf; then + local tmp_uchar_1 tmp_uchar_2 tmp_uchar_3 tmp_uchar_4 tmp_default_length tmp_length tmp_unicode_length tmp_spaces_nums tmp_max_length + for ((i = 0; i < ${#list_arr[@]}; i++)); do + if [[ "${list_labels[$i]}" ]]; then + tmp_name="${list_labels[$i]}" + else + tmp_name="${list_arr[i]}" + fi + tmp_index=$((i + 1)) + tmp_default_length="${name_width}" + tmp_uchar_1=$(echo "${tmp_name}" | grep -c "“") + tmp_uchar_2=$(echo "${tmp_name}" | grep -c "”") + tmp_uchar_3=$(echo "${tmp_name}" | grep -c "‘") + tmp_uchar_4=$(echo "${tmp_name}" | grep -c "’") + [[ "${tmp_uchar_1}" -gt 0 ]] && ((tmp_default_length += tmp_uchar_1)) + [[ "${tmp_uchar_2}" -gt 0 ]] && ((tmp_default_length += tmp_uchar_2)) + [[ "${tmp_uchar_3}" -gt 0 ]] && ((tmp_default_length += tmp_uchar_3)) + [[ "${tmp_uchar_4}" -gt 0 ]] && ((tmp_default_length += tmp_uchar_4)) + tmp_length=$(StringLength "${tmp_name}") + tmp_unicode_length=$(StringLength "$(echo "${tmp_name}" | sed "s|[0-9a-zA-Z -~]||g; s| ||g")") + tmp_max_length=$((tmp_default_length + tmp_unicode_length)) + tmp_spaces_nums=$((((tmp_default_length - tmp_unicode_length - tmp_length)) / 2)) + if [[ $tmp_spaces_nums -gt 0 ]]; then + tmp_name="${tmp_name}$(printf '%*s' ${tmp_spaces_nums} '')" + fi + printf "❖ %-${tmp_max_length}s %4s\n" "${tmp_name}" "${tmp_index})" + done + else + for ((i = 0; i < ${#list_arr[@]}; i++)); do + if [[ "${list_labels[$i]}" ]]; then + tmp_name="${list_labels[$i]}" + else + tmp_name="${list_arr[i]}" + fi + tmp_index=$((i + 1)) + echo -e " ❖ $tmp_index. ${tmp_name}" + done + fi + } + + ## 选择使用软件源内网地址 + function choose_use_intranet_address() { + local intranet_source + for ((i = 0; i < ${#mirror_list_extranet[@]}; i++)); do + if [[ "${SOURCE}" == "${mirror_list_extranet[i]}" ]]; then + intranet_source="${mirror_list_intranet[i]}" + break + else + continue + fi + done + if [[ -z "${USE_INTRANET_SOURCE}" ]]; then + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}$(msg "interaction.source.type.select")${PLAIN}" "$(msg "interaction.source.type.public")" "$(msg "interaction.source.type.intranet")" + if [[ "${_SELECT_RESULT}" == "false" ]]; then + SOURCE="${intranet_source}" + ONLY_HTTP="true" # 强制使用 HTTP 协议 + [[ "${PURE_MODE}" != "true" ]] && echo -e "\n$WARN $(msg "warn.usedIntranetSource")" + fi + else + local CHOICE="$(echo -e "\n${BOLD}└─ $(msg "interaction.source.type.usePublicAddress")? [Y/n] ${PLAIN}")" + read -rp "${CHOICE}" INPUT + [[ -z "${INPUT}" ]] && INPUT=Y + case "${INPUT}" in + [Yy] | [Yy][Ee][Ss]) ;; + [Nn] | [Nn][Oo]) + SOURCE="${intranet_source}" + ONLY_HTTP="true" # 强制使用 HTTP 协议 + [[ "${PURE_MODE}" != "true" ]] && echo -e "\n$WARN $(msg "warn.usedIntranetSource")" + ;; + *) + input_error "$(msg "error.defaultBehavior.noUseIntranetSource")" + ;; + esac + fi + elif [[ "${USE_INTRANET_SOURCE}" == "true" ]]; then + SOURCE="${intranet_source}" + fi + } + + local mirror_list_name mirror_list_length + local -a mirror_list_labels=() + local label_msg_index label_msg_content + if [[ -z "${SOURCE}" ]] && [[ "${ONLY_REGISTRY}" != "true" ]]; then + mirror_list_name="mirror_list_docker_ce" + mirror_list_length=$(eval "echo \${#${mirror_list_name}[@]}") + for ((i = 0; i < ${mirror_list_length}; i++)); do + label_msg_index="mirrors.dockerCE.${i}" + label_msg_content="$(msg "${label_msg_index}")" + if [[ "${label_msg_content}" == "${label_msg_index}" ]]; then + mirror_list_labels+=("") + else + mirror_list_labels+=("${label_msg_content}") + fi + done + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + interactive_select_list "${mirror_list_name}" "\n ${BOLD}$(msg "interaction.source.dockerCE.select")${PLAIN}\n" "mirror_list_labels" + SOURCE="${_SELECT_RESULT%%@@*}" + echo -e "\n${GREEN}➜${PLAIN} ${BOLD}Docker CE: ${_SELECT_RESULT#*@@}${PLAIN}" + else + echo '' + print_mirrors_list "${mirror_list_name}" 39 "mirror_list_labels" + local CHOICE_B="$(echo -e "\n${BOLD}└─ $(msg "interaction.source.dockerCE.selectAndInput") [ 1-$(eval echo \${#${mirror_list_name}[@]}) ]:${PLAIN}")" + while true; do + read -rp "${CHOICE_B}" INPUT + case "${INPUT}" in + [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) + local tmp_result="$(eval echo \${${mirror_list_name}[$((INPUT - 1))]})" + if [[ -z "${tmp_result}" ]]; then + echo -e "\n$WARN $(msg "warn.needValidNumberIndex")" + else + SOURCE="$(echo "${tmp_result}" | awk -F '@' '{print$2}')" + break + fi + ;; + *) + echo -e "\n$WARN $(msg "warn.needInputNumberIndex")" + ;; + esac + done + fi + fi + + ## 选择软件源内网地址 + if [[ "${mirror_list_extranet[*]}" =~ (^|[^[:alpha:]])"${SOURCE}"([^[:alpha:]]|$) ]]; then + choose_use_intranet_address + fi + + if [[ -z "${SOURCE_REGISTRY}" ]]; then + mirror_list_name="mirror_list_registry" + mirror_list_labels=() + mirror_list_length=$(eval "echo \${#${mirror_list_name}[@]}") + for ((i = 0; i < ${mirror_list_length}; i++)); do + label_msg_index="mirrors.registry.${i}" + label_msg_content="$(msg "${label_msg_index}")" + if [[ "${label_msg_content}" == "${label_msg_index}" ]]; then + mirror_list_labels+=("") + else + mirror_list_labels+=("${label_msg_content}") + fi + done + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + sleep 1 >/dev/null 2>&1 + interactive_select_list "${mirror_list_name}" "\n ${BOLD}$(msg "interaction.source.dockerRegistry.select")${PLAIN}\n" "mirror_list_labels" + SOURCE_REGISTRY="${_SELECT_RESULT%%@@*}" + echo -e "\n${GREEN}➜${PLAIN} ${BOLD}Docker Registry: $(echo "${_SELECT_RESULT#*@@}" | sed 's|(推荐)||g; s|(推薦)||g')${PLAIN}" + else + echo '' + print_mirrors_list "${mirror_list_name}" 45 "mirror_list_labels" + local CHOICE_C="$(echo -e "\n${BOLD}└─ $(msg "interaction.source.dockerRegistry.selectAndInput") [ 1-$(eval echo \${#${mirror_list_name}[@]}) ]:${PLAIN}")" + while true; do + read -rp "${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 $(msg "warn.needValidNumberIndex")" + else + SOURCE_REGISTRY="$(eval echo \${${mirror_list_name}[$(($INPUT - 1))]} | awk -F '@' '{print$2}')" + break + fi + ;; + *) + echo -e "\n$WARN $(msg "warn.needInputNumberIndex")" + ;; + esac + done + fi + fi +} + +## 选择同步或更新软件源所使用的 Web 协议( HTTP/HTTPS) +function choose_protocol() { + if [[ -z "${WEB_PROTOCOL}" ]]; then + if [[ "${ONLY_HTTP}" == "true" ]]; then + WEB_PROTOCOL="http" + else + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}$(msg "interaction.protocol.select")${PLAIN}" "HTTP" "HTTPS" + if [[ "${_SELECT_RESULT}" == "true" ]]; then + WEB_PROTOCOL="http" + else + WEB_PROTOCOL="https" + fi + else + local CHOICE="$(echo -e "\n${BOLD}└─ $(msg "interaction.protocol.useHttp")? [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" + ;; + *) + input_error "$(msg "error.defaultBehavior.https")" + WEB_PROTOCOL="https" + ;; + esac + fi + fi + fi + WEB_PROTOCOL="${WEB_PROTOCOL,,}" +} + +## 关闭防火墙和SELinux +function close_firewall_service() { + if ! command_exists systemctl; then + return + fi + if [[ "$(systemctl is-active firewalld)" == "active" ]]; then + if [[ -z "${CLOSE_FIREWALL}" ]]; then + local ask_text="$(msg "interaction.firewall.close")?" + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}${ask_text}${PLAIN}" + if [[ "${_SELECT_RESULT}" == "true" ]]; then + CLOSE_FIREWALL="true" + fi + else + local CHOICE="$(echo -e "\n${BOLD}└─ ${ask_text} [Y/n] ${PLAIN}")" + read -rp "${CHOICE}" INPUT + [[ -z "${INPUT}" ]] && INPUT=Y + case "${INPUT}" in + [Yy] | [Yy][Ee][Ss]) + CLOSE_FIREWALL="true" + ;; + [Nn] | [Nn][Oo]) ;; + *) + input_error "$(msg "error.defaultBehavior.noClose")" + ;; + esac + fi + fi + if [[ "${CLOSE_FIREWALL}" == "true" ]]; then + local SelinuxConfig=/etc/selinux/config + systemctl disable --now firewalld >/dev/null 2>&1 + [ -s "${SelinuxConfig}" ] && sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" $SelinuxConfig && setenforce 0 >/dev/null 2>&1 + fi + fi +} + +## 安装环境包 +function install_dependency_packages() { + local commands package_manager + ## 删除原有源 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + sed -i '/docker-ce/d' $File_AptSourceList + rm -rf $File_DockerSourceList + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + rm -rf $Dir_YumRepos/*docker*.repo + ;; + esac + ## 更新软件源 + commands=() + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + package_manager="apt-get" + commands+=("${package_manager} update") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + package_manager="$(get_package_manager)" + commands+=("${package_manager} makecache") + ;; + esac + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + echo '' + animate_exec "${exec_cmd}" "${SYNC_MIRROR_TEXT}" + else + echo '' + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + fi + if [ $? -ne 0 ]; then + output_error "$(msg "error.sync" "${SYNC_MIRROR_TEXT}" "${BLUE}${package_manager}${PLAIN}")" + fi + + commands=() + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + commands+=("${package_manager} install -y ca-certificates curl") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 7) + commands+=("${package_manager} install -y yum-utils device-mapper-persistent-data lvm2") + ;; + *) + if [[ "${package_manager}" == "dnf" ]]; then + commands+=("${package_manager} install -y dnf-plugins-core") + else + commands+=("${package_manager} install -y yum-utils device-mapper-persistent-data lvm2") + fi + ;; + esac + ;; + esac + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + echo '' + animate_exec "${exec_cmd}" "$(msg "work.installDependents")" + else + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + fi +} + +## 配置 Docker CE 源 +function configure_docker_ce_mirror() { + local -a commands=() + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + ## 处理 GPG 密钥 + local file_keyring="/etc/apt/keyrings/docker.asc" + apt-key del 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 >/dev/null 2>&1 # 删除旧的密钥 + [ -f "${file_keyring}" ] && rm -rf $file_keyring + install -m 0755 -d /etc/apt/keyrings + curl -fsSL "${WEB_PROTOCOL}://${SOURCE}/linux/${SOURCE_BRANCH}/gpg" -o $file_keyring >/dev/null + if [ $? -ne 0 ]; then + output_error "$(msg "error.downloadGPG")" + fi + chmod a+r $file_keyring + ## 添加源 + [ -d "${Dir_AptAdditionalSources}" ] || mkdir -p $Dir_AptAdditionalSources + local apt_source_content="deb [arch=$(dpkg --print-architecture) signed-by=${file_keyring}] ${WEB_PROTOCOL}://${SOURCE}/linux/${SOURCE_BRANCH} ${DEBIAN_CODENAME:-${SOURCE_BRANCH_CODENAME:-${SYSTEM_VERSION_CODENAME}}} stable" + echo "${apt_source_content}" | tee $File_DockerSourceList >/dev/null 2>&1 + commands+=("apt-get update") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + local repo_file_url="${WEB_PROTOCOL}://${SOURCE}/linux/${SOURCE_BRANCH}/docker-ce.repo" + local package_manager="$(get_package_manager)" + case "${SYSTEM_VERSION_ID_MAJOR}" in + 7) + yum-config-manager -y --add-repo "${repo_file_url}" + ;; + *) + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_FEDORA}" ]]; then + dnf-3 config-manager -y --add-repo "${repo_file_url}" + else + if [[ "${package_manager}" == "dnf" ]]; then + dnf config-manager -y --add-repo "${repo_file_url}" + else + yum-config-manager -y --add-repo "${repo_file_url}" + fi + fi + ;; + esac + sed -e "s|https://download.docker.com|${WEB_PROTOCOL}://${SOURCE}|g" \ + -e "s|http[s]\?://.*/linux/${SOURCE_BRANCH}/|${WEB_PROTOCOL}://${SOURCE}/linux/${SOURCE_BRANCH}/|g" \ + -i \ + $File_DockerRepo + ## 处理版本号 + if [[ "${SOURCE_BRANCH_VERSION}" ]]; then + # 指定版本 + sed -e "s|\$releasever|${SOURCE_BRANCH_VERSION}|g" \ + -i \ + $File_DockerRepo + commands+=("${package_manager} makecache") + elif [[ "${SYSTEM_JUDGMENT}" != "${SYSTEM_FEDORA}" ]]; then + # 兼容处理 + local target_version + case "${SYSTEM_VERSION_ID_MAJOR}" in + 7 | 8 | 9 | 10) + target_version="${SYSTEM_VERSION_ID_MAJOR}" + ;; + *) + target_version="8" # 注:部分系统使用9版本分支会有兼容性问题 + ## 适配国产操作系统 + # OpenCloudOS、Anolis OS 的 23 版本 + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_OPENCLOUDOS}" || "${SYSTEM_JUDGMENT}" == "${SYSTEM_ANOLISOS}" ]]; then + if [[ "${SYSTEM_VERSION_ID_MAJOR}" == 23 ]]; then + target_version="9" + fi + fi + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_OPENEULER}" ]]; then + if [ -s "${File_HuaweiCloudEulerOSRelease}" ]; then + # Huawei Cloud EulerOS + case "${SYSTEM_VERSION_ID_MAJOR}" in + 1) + target_version="8" # openEuler 20 + ;; + 2) + target_version="9" # openEuler 22 + ;; + esac + else + # openEuler + if [[ "${SYSTEM_VERSION_ID_MAJOR}" -ge 22 ]]; then + target_version="9" + fi + fi + fi + # TencentOS Server + if [ -s "${File_TencentOSServerRelease}" ]; then + case "${SYSTEM_VERSION_ID_MAJOR}" in + 4) + target_version="9" + ;; + 3) + target_version="8" + ;; + 2) + target_version="7" + ;; + esac + fi + # Alibaba Cloud Linux + if [ -s "${File_AnolisOSRelease}" ] && [ -s "${File_AlibabaCloudLinuxRelease}" ]; then + case "${SYSTEM_VERSION_ID_MAJOR}" in + 3) + target_version="8" + ;; + 2) + target_version="7" + ;; + esac + fi + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_KYLIN_SERVER}" ]]; then + case "${SYSTEM_VERSION_ID_MAJOR}" in + "V10") + target_version="8" + ;; + "V11") + target_version="10" + ;; + *) + target_version="10" + ;; + esac + fi + ;; + esac + sed -e "s|\$releasever|${target_version}|g" \ + -i \ + $File_DockerRepo + commands+=("${package_manager} makecache") + fi + ;; + esac + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + echo '' + animate_exec "${exec_cmd}" "${SYNC_MIRROR_TEXT}" + else + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + fi +} + +## 安装 Docker Engine +function install_docker_engine() { + ## 导出可安装的版本列表 + function export_version_list() { + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + apt-cache madison docker-ce | awk '{print $3}' | grep -Eo "[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}" >$File_DockerCEVersionTmp + apt-cache madison docker-ce-cli | awk '{print $3}' | grep -Eo "[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}" >$File_DockerCECliVersionTmp + grep -wf $File_DockerCEVersionTmp $File_DockerCECliVersionTmp >$File_DockerVersionTmp + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + local package_manager="$(get_package_manager)" + $package_manager list docker-ce --showduplicates | sort -r | awk '{print $2}' | grep -Eo "[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}" >$File_DockerCEVersionTmp + $package_manager list docker-ce-cli --showduplicates | sort -r | awk '{print $2}' | grep -Eo "[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}" >$File_DockerCECliVersionTmp + grep -wf $File_DockerCEVersionTmp $File_DockerCECliVersionTmp >$File_DockerVersionTmp + ;; + esac + rm -rf $File_DockerCEVersionTmp $File_DockerCECliVersionTmp + } + + ## 卸载 Docker Engine 原有版本软件包 + function uninstall_original_version() { + if command_exists docker; then + # 先停止并禁用 Docker 服务 + systemctl disable --now docker >/dev/null 2>&1 + sleep 2s + fi + # 确定需要卸载的软件包 + local package_list + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + package_list='docker* podman podman-docker containerd runc' + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + package_list='docker* podman podman-docker runc' + ;; + esac + # 卸载软件包并清理残留 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + apt-get remove -y $package_list >/dev/null 2>&1 + apt-get autoremove -y >/dev/null 2>&1 + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + local package_manager="$(get_package_manager)" + $package_manager remove -y $package_list >/dev/null 2>&1 + $package_manager autoremove -y >/dev/null 2>&1 + ;; + esac + } + + ## 安装 + function install_main() { + local target_docker_version + local pkgs="" + local -a commands=() + if [[ "${INSTALL_LATESTED_DOCKER}" == "true" ]]; then + pkgs="docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin" + else + export_version_list + if [ ! -s "${File_DockerVersionTmp}" ]; then + rm -rf $File_DockerVersionTmp + output_error "$(msg "error.queryVersionFailed")" + fi + if [[ "${DESIGNATED_DOCKER_VERSION}" ]]; then + cat $File_DockerVersionTmp | grep -Eq "^${DESIGNATED_DOCKER_VERSION}$" + if [ $? -ne 0 ]; then + rm -rf $File_DockerVersionTmp + output_error "$(msg "error.designatedVersion")" + fi + target_docker_version="${DESIGNATED_DOCKER_VERSION}" + else + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + local -a version_list=( + $(cat $File_DockerVersionTmp | sort -t '.' -k1,1nr -k2,2nr -k3,3nr | tr '\n' ' ' | sed 's/ $//') + ) + local mirror_list_name="version_list" + interactive_select_list "${mirror_list_name}" "\n ${BOLD}$(msg "interaction.install.selectVersion")${PLAIN}\n" + target_docker_version="${_SELECT_RESULT}" + echo -e "\n${GREEN}➜${PLAIN} ${BOLD}$(msg "interaction.install.selectedVersion")${target_docker_version}${PLAIN}\n" + else + echo -e "\n${GREEN} --------- $(msg "interaction.install.selectedTitle" "28.3.0") ---------- ${PLAIN}\n" + cat $File_DockerVersionTmp + while true; do + local CHOICE="$(echo -e "\n${BOLD}└─ $(msg "interaction.install.inputVersion")${PLAIN}\n")" + read -rp "${CHOICE}" target_docker_version + echo '' + cat $File_DockerVersionTmp | grep -Eqw "${target_docker_version}" + if [ $? -eq 0 ]; then + echo "${target_docker_version}" | grep -Eqw '[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}' + if [ $? -eq 0 ]; then + break + else + echo -e "$ERROR $(msg "error.invalidVersion")" + fi + else + echo -e "$ERROR $(msg "error.reEnter")" + fi + done + fi + fi + rm -rf $File_DockerVersionTmp + local major_version="$(echo ${target_docker_version} | cut -d'.' -f1)" + local minor_version="$(echo ${target_docker_version} | cut -d'.' -f2)" + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + if [[ $major_version -gt 18 ]] || [[ $major_version -eq 18 && $minor_version -ge 9 ]]; then + local tmp_version="$(apt-cache madison docker-ce-cli | grep "${target_docker_version}" | head -1 | awk '{print $3}' | awk -F "${target_docker_version}" '{print$1}')" + pkgs="docker-ce=${tmp_version}${target_docker_version}* docker-ce-cli=${tmp_version}${target_docker_version}*" + else + pkgs="docker-ce=${target_docker_version}* docker-ce-cli=${target_docker_version}*" + fi + ;; + + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + pkgs="docker-ce-${target_docker_version}" + if [[ $major_version -gt 18 ]] || [[ $major_version -eq 18 && $minor_version -ge 9 ]]; then + pkgs="${pkgs} docker-ce-cli-${target_docker_version}" + fi + ;; + esac + pkgs="${pkgs} containerd.io" + if [[ $major_version -gt 20 ]] || [[ $major_version -eq 20 && $minor_version -ge 10 ]]; then + pkgs="${pkgs} docker-compose-plugin" + fi + if [[ $major_version -ge 23 ]]; then + pkgs="${pkgs} docker-buildx-plugin" + fi + fi + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + commands+=("apt-get install -y ${pkgs}") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + commands+=("$(get_package_manager) install -y ${pkgs}") + ;; + esac + echo '' + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + animate_exec "${exec_cmd}" "$(msg "work.installDockerEngine")" + else + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + fi + [ $? -ne 0 ] && output_error "$(msg "error.installDockerEngineFailed")" + } + + ## 判断是否手动选择安装版本 + if [[ -z "${INSTALL_LATESTED_DOCKER}" ]]; then + local ask_text="$(msg "interaction.install.latestVersion")?" + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}${ask_text}${PLAIN}" + if [[ "${_SELECT_RESULT}" == "true" ]]; then + INSTALL_LATESTED_DOCKER="true" + else + INSTALL_LATESTED_DOCKER="false" + fi + else + local CHOICE_A="$(echo -e "\n${BOLD}└─ ${ask_text} [Y/n] ${PLAIN}")" + read -rp "${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" + ;; + *) + INSTALL_LATESTED_DOCKER="true" + input_error "$(msg "error.defaultBehavior.installLatest")" + ;; + esac + fi + fi + + ## 判定是否已安装 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + dpkg -l | grep docker-ce-cli -q + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + rpm -qa | grep docker-ce-cli -q + ;; + esac + if [ $? -eq 0 ]; then + export_version_list + local current_docker_version="$(docker -v | grep -Eo "[0-9][0-9]\.[0-9]{1,2}\.[0-9]{1,2}")" + local latest_docker_version="$(cat $File_DockerVersionTmp | head -n 1)" + rm -rf $File_DockerVersionTmp + if [[ "${current_docker_version}" == "${latest_docker_version}" ]] && [[ "${INSTALL_LATESTED_DOCKER}" == "true" ]]; then + echo -e "\n$TIP $(msg "tip.skipInstallDockerEngine")" + else + uninstall_original_version + install_main + fi + else + uninstall_original_version + install_main + fi +} + +## 修改 Docker Registry 镜像仓库源 +function change_docker_registry_mirror() { + ## 使用官方 Docker Hub + if [[ "${REGISTRY_SOURCEL}" == "registry.hub.docker.com" ]]; then + if [ -s "${File_DockerConfig}" ]; then + ## 安装 jq + local package_manager="$(get_package_manager)" + $package_manager install -y jq + if command_exists jq; then + jq 'del(.["registry-mirrors"])' $File_DockerConfig >$File_DockerConfig.tmp && mv $File_DockerConfig.tmp $File_DockerConfig + # 重启服务 + systemctl daemon-reload + if [[ "$(systemctl is-active docker 2>/dev/null)" == "active" ]]; then + systemctl restart docker + fi + else + echo -e "\n${WARN} $(msg "warn.needManuallyDeleteConfig" "${File_DockerConfig}" "${BLUE}registry-mirrors${PLAIN}" "${BLUE}systemctl daemon-reload && systemctl restart docker${PLAIN}")\n" + fi + fi + return + fi + ## 备份原有配置文件 + if [ -d "${Dir_Docker}" ] && [ -e "${File_DockerConfig}" ]; then + if [ -e "${File_DockerConfigBackup}" ]; then + if [[ "${IGNORE_BACKUP_TIPS}" == "false" ]]; then + local ask_text="$(msg "interaction.backup.skipOverwrite")?" + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}${ask_text}${PLAIN}" + if [[ "${_SELECT_RESULT}" == "false" ]]; then + echo '' + cp -rvf $File_DockerConfig $File_DockerConfigBackup 2>&1 + fi + else + local CHOICE_BACKUP="$(echo -e "\n${BOLD}└─ ${ask_text} [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 $File_DockerConfig $File_DockerConfigBackup 2>&1 + ;; + *) + input_error "$(msg "error.defaultBehavior.noOverwrite")" + ;; + esac + fi + fi + else + echo '' + cp -rvf $File_DockerConfig $File_DockerConfigBackup 2>&1 + echo -e "\n$COMPLETE $(msg "info.backuped.dockerConfig")" + fi + sleep 2s + else + mkdir -p $Dir_Docker >/dev/null 2>&1 + touch $File_DockerConfig + fi + + echo -e '{\n "registry-mirrors": '"$(handleRegistryMirrorsValue ${SOURCE_REGISTRY})"'\n}' >$File_DockerConfig + ## 重启服务 + systemctl daemon-reload + if [[ "$(systemctl is-active docker 2>/dev/null)" == "active" ]]; then + systemctl restart docker + fi +} + +## 仅修改 Docker Registry 镜像仓库源模式 +function only_change_docker_registry_mirror() { + ## 判定是否已安装 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + dpkg -l | grep docker-ce-cli -q + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + rpm -qa | grep docker-ce-cli -q + ;; + esac + if [ $? -ne 0 ]; then + ## 仅镜像仓库换源模式 + if [[ "${ONLY_REGISTRY}" == "true" ]]; then + output_error "$(msg "result.registry.dockerEngineNotExsit" "${BLUE}--only-registry${PLAIN}")" + fi + fi + + [ -d "${Dir_Docker}" ] || mkdir -p "${Dir_Docker}" + if [ -s "${File_DockerConfig}" ]; then + ## 安装 jq + if ! command_exists jq; then + ## 更新软件源 + local package_manager + local -a commands=() + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + package_manager="apt-get" + commands+=("${package_manager} update") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + package_manager="$(get_package_manager)" + commands+=("${package_manager} makecache") + ;; + esac + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + echo '' + animate_exec "${exec_cmd}" "${SYNC_MIRROR_TEXT}" + else + echo '' + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + fi + if [ $? -ne 0 ]; then + output_error "$(msg "error.sync" "${SYNC_MIRROR_TEXT}" "${BLUE}${package_manager}${PLAIN}")" + fi + $package_manager install -y jq + if ! command_exists jq; then + output_error "$(msg "error.installPackageFailed" "${BLUE}jq${PLAIN}")" + fi + fi + [ -s "${File_DockerConfig}" ] || echo "{}" >$File_DockerConfig + jq '.["registry-mirrors"] = '"$(handleRegistryMirrorsValue ${SOURCE_REGISTRY})"'' $File_DockerConfig >$File_DockerConfig.tmp && mv $File_DockerConfig.tmp $File_DockerConfig + else + echo -e '{\n "registry-mirrors": '"$(handleRegistryMirrorsValue ${SOURCE_REGISTRY})"'\n}' >$File_DockerConfig + fi + ## 重启服务 + systemctl daemon-reload + if [[ "$(systemctl is-active docker 2>/dev/null)" == "active" ]]; then + systemctl restart docker + fi + + echo -e "\n${BLUE}\$${PLAIN} docker info --format '{{json .RegistryConfig.Mirrors}}'" + echo -e "\033[2m>${PLAIN} $(docker info --format '{{json .RegistryConfig.Mirrors}}')" + if [[ "${PURE_MODE}" != "true" ]]; then + echo -e "\n$COMPLETE $(msg "result.registry.success")" + fi +} + +function handleRegistryMirrorsValue() { + local content="$1" + local result="" + content="$(echo "${content}" | sed 's| ||g')" + local -a items=(${content//,/ }) + for item in "${items[@]}"; do + [[ -z "${item}" ]] && continue + if [[ -z "${result}" ]]; then + result='"https://'"${item}"'"' + else + result="${result},\"https://${item}\"" + fi + done + if [[ "${result}" ]]; then + echo "[${result}]" + else + echo "" + fi +} + +## 查看版本并验证安装结果 +function check_installed_result() { + if command_exists docker; then + systemctl enable --now docker >/dev/null 2>&1 + echo -en "\n$COMPLETE " + docker -v + if [ $? -eq 0 ]; then + echo -e " $(docker compose version 2>&1)" + # echo -e "\n$COMPLETE 安装完成" + else + echo -e "\n$FAIL $(msg "result.install.failed")" + local source_file package_manager + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + source_file="${File_DockerSourceList}" + package_manager="apt-get" + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + source_file="${File_DockerRepo}" + package_manager="$(get_package_manager)" + ;; + esac + echo -e "\n$(msg "result.install.checkSourceFile" "cat ${source_file}")" + echo -e "$(msg "result.install.manuallyExecCmd" "${package_manager} install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin")\n" + exit 1 + fi + if [[ "$(systemctl is-active docker 2>/dev/null)" != "active" ]]; then + sleep 2 + systemctl disable --now docker >/dev/null 2>&1 + sleep 2 + systemctl enable --now docker >/dev/null 2>&1 + sleep 2 + if [[ "$(systemctl is-active docker)" != "active" ]]; then + echo -e "\n$WARN $(msg "result.install.notRunning")" + local start_cmd + if command_exists systemctl; then + start_cmd="systemctl start docker" + else + start_cmd="service docker start" + fi + echo -e "\n$TIP $(msg "result.install.manuallyRun" "${BLUE}${start_cmd}${PLAIN}")" + fi + fi + else + echo -e "\n$FAIL $(msg "result.install.failed")" + fi +} + +## 选择系统包管理器 +function get_package_manager() { + local command="yum" + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_RHEL}" | "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ROCKY}" | "${SYSTEM_ALMALINUX}" | "${SYSTEM_ORACLE}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 9 | 10) + command="dnf" + ;; + esac + ;; + "${SYSTEM_FEDORA}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + command="dnf" + ;; + esac + echo "${command}" +} + +function interactive_select_list() { + _SELECT_RESULT="" + eval "local -a __values=(\"\${${1}[@]}\")" + local -a __labels=() + local message="${2}" + local selected=0 + local start=0 + local page_size=$(($(tput lines 2>/dev/null) - 3)) + if [[ "${3}" ]]; then + eval "__labels=(\"\${${3}[@]}\")" + fi + function clear_menu() { + tput rc 2>/dev/null + for ((i = 0; i < ${#__values[@]} + 1; i++)); do + echo -e "\r\033[K" + done + tput rc 2>/dev/null + } + function cleanup() { + clear_menu + tput rc 2>/dev/null + tput cnorm 2>/dev/null + tput rmcup 2>/dev/null + echo -e "\n\033[1;44m $(msg "interaction.common.tip") \033[0m \033[31m$(msg "interaction.common.operationCanceled")\033[0m\n" + exit 130 + } + function draw_menu() { + tput clear 2>/dev/null + tput cup 0 0 2>/dev/null + echo -e "${message}" + local end=$((start + page_size - 1)) + local label + if [ $end -ge ${#__values[@]} ]; then + end=${#__values[@]}-1 + fi + for ((i = start; i <= end; i++)); do + if [[ "${__labels[$i]}" ]]; then + label="${__labels[$i]}" + else + label="${__values[$i]}" + fi + if [ "$i" -eq "${selected}" ]; then + echo -e "\e[34;4m➤ ${label}\e[0m" + else + echo -e " ${label}" + fi + done + } + function read_key() { + IFS= read -rsn1 key + if [[ $key == $'\x1b' ]]; then + IFS= read -rsn2 key + key="$key" + fi + echo "$key" + } + tput smcup 2>/dev/null + tput sc 2>/dev/null + tput civis 2>/dev/null + trap "cleanup" INT TERM + draw_menu + while true; do + key=$(read_key) + case "$key" in + "[A" | "w" | "W") + if [ "${selected}" -gt 0 ]; then + selected=$((selected - 1)) + if [ "${selected}" -lt "$start" ]; then + start=$((start - 1)) + fi + fi + ;; + "[B" | "s" | "S") + if [ "${selected}" -lt $((${#__values[@]} - 1)) ]; then + selected=$((selected + 1)) + if [ "${selected}" -ge $((start + page_size)) ]; then + start=$((start + 1)) + fi + fi + ;; + "") + tput rmcup + break + ;; + *) ;; + esac + draw_menu + done + tput cnorm 2>/dev/null + tput rmcup 2>/dev/null + _SELECT_RESULT="${__values[${selected}]}" + if [ "${__labels[${selected}]}" ]; then + _SELECT_RESULT="${_SELECT_RESULT}@@${__labels[${selected}]}" + fi +} + +function interactive_select_boolean() { + _SELECT_RESULT="" + local selected=0 + local message="$1" + local positive_title="${2:-"$(msg "interaction.common.yes")"}" + local negative_title="${3:-"$(msg "interaction.common.no")"}" + local menu_height=3 + local original_line + function store_position() { + original_line=$(tput lines 2>/dev/null) + } + function clear_menu() { + for ((i = 0; i < $menu_height; i++)); do + tput cuu1 2>/dev/null + tput el 2>/dev/null + done + } + function cleanup() { + clear_menu + tput cnorm 2>/dev/null + echo -e "\n\033[1;44m $(msg "interaction.common.tip") \033[0m \033[31m$(msg "interaction.common.operationCanceled")\033[0m\n" + exit 130 + } + function draw_menu() { + echo -e "╭─ ${message}" + echo -e "│" + if [ "${selected}" -eq 0 ]; then + echo -e "╰─ \033[34m●\033[0m ${positive_title}\033[2m / ○ ${negative_title}\033[0m" + else + echo -e "╰─ \033[2m○ ${positive_title} / \033[0m\033[34m●\033[0m ${negative_title}" + fi + } + function read_key() { + IFS= read -rsn1 key + if [[ $key == $'\x1b' ]]; then + IFS= read -rsn2 key + key="$key" + fi + echo "$key" + } + tput civis 2>/dev/null + store_position + trap "cleanup" INT TERM + draw_menu + while true; do + key=$(read_key) + case "$key" in + "[D" | "a" | "A") + if [ "${selected}" -gt 0 ]; then + selected=$((selected - 1)) + clear_menu + draw_menu + fi + ;; + "[C" | "d" | "D") + if [ "${selected}" -lt 1 ]; then + selected=$((selected + 1)) + clear_menu + draw_menu + fi + ;; + "") + clear_menu + break + ;; + *) ;; + esac + done + echo -e "╭─ ${message}" + echo -e "│" + if [ "${selected}" -eq 0 ]; then + echo -e "╰─ \033[32m●\033[0m \033[1m${positive_title}\033[0m\033[2m / ○ ${negative_title}\033[0m" + _SELECT_RESULT="true" + else + echo -e "╰─ \033[2m○ ${positive_title} / \033[0m\033[32m●\033[0m \033[1m${negative_title}\033[0m" + _SELECT_RESULT="false" + fi + tput cnorm 2>/dev/null +} + +function animate_exec() { + local cmd="$1" + local title="$2" + local max_lines=${3:-5} + local spinner_style="${4:-dots}" + local refresh_rate="${5:-0.1}" + local scroll_mode="${6:-1}" + if [[ "${scroll_mode}" == "0" ]]; then + echo -e "◉ ${title} \n" + eval "${cmd}" + return $? + fi + local -A spinners=([dots]="⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏" [circle]="◐ ◓ ◑ ◒" [classic]="-\\ |/") + local -A recommended_rates=([dots]="0.08" [circle]="0.12" [classic]="0.12") + [[ -z "${spinners[$spinner_style]}" ]] && spinner_style="dots" + [[ "${refresh_rate}" == "0.1" ]] && refresh_rate="${recommended_rates[$spinner_style]}" + local term_width=$(tput cols 2>/dev/null || echo 80) + local display_width=$((term_width - 2)) + function simple_truncate() { + local line="$1" + local truncate_marker="..." + local max_length=$((display_width - 3)) + if [[ "${line}" =~ ^[[:ascii:]]*$ && ${#line} -le $display_width ]]; then + echo "${line}" + return + fi + local non_ascii_count=$(echo "${line}" | sed "s|[0-9a-zA-Z -~]||g; s| ||g" | wc -m) + local total_length=${#line} + local display_length=$((total_length + non_ascii_count)) + local quote_count=0 + [[ $(echo "${line}" | grep -c "“") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "“")")) + [[ $(echo "${line}" | grep -c "”") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "”")")) + [[ $(echo "${line}" | grep -c "‘") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "‘")")) + [[ $(echo "${line}" | grep -c "’") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "’")")) + display_length=$((display_length - quote_count)) + if [[ $display_length -le $display_width ]]; then + echo "$line" + return + fi + local result="" + local current_width=0 + local i=0 + while [ $i -lt ${#line} ]; do + local char="${line:$i:1}" + local char_width=1 + if ! [[ "$char" =~ [0-9a-zA-Z\.\=\:\_\(\)\'\"\-\/\!\·] ]]; then + if [[ "$char" != "“" && "$char" != "”" && "$char" != "‘" && "$char" != "’" ]]; then + char_width=2 + fi + fi + if [[ $((current_width + char_width)) -gt $max_length ]]; then + echo "${result}${truncate_marker}" + return + fi + result+="${char}" + current_width=$((current_width + char_width)) + ((i++)) + done + echo "${line}" + } + function cleanup() { + [ -f "${temp_file}" ] && rm -f "${temp_file}" + tput cnorm 2>/dev/null + echo -e "\n\033[1;44m $(msg "interaction.common.tip") \033[0m \033[31m$(msg "interaction.common.operationCanceled")\033[0m\n" + exit 130 + } + function make_temp_file() { + local -a temp_dirs=("." "/tmp") + local tmp_file="" + for dir in "${temp_dirs[@]}"; do + [[ ! -d "${dir}" || ! -w "${dir}" ]] && continue + tmp_file="${dir}/animate_exec_$$_$(date +%s)" + touch "${tmp_file}" 2>/dev/null || continue + if [[ -f "${tmp_file}" && -w "${tmp_file}" ]]; then + echo "${tmp_file}" + return + fi + done + echo "${tmp_file}" + } + function update_display() { + local current_size=$(wc -c <"${temp_file}" 2>/dev/null || echo 0) + if [[ $current_size -le $last_size ]]; then + return 1 + fi + local -a lines=() + mapfile -t -n "${max_lines}" lines < <(tail -n "$max_lines" "${temp_file}") + local -a processed_lines=() + for ((i = 0; i < ${#lines[@]}; i++)); do + processed_lines[i]=$(simple_truncate "${lines[i]}") + done + tput cud1 2>/dev/null + echo -ne "\r\033[K" + tput cud1 2>/dev/null + for ((i = 0; i < $max_lines; i++)); do + echo -ne "\r\033[K" + [[ $i -lt ${#processed_lines[@]} ]] && echo -ne "\033[2m${processed_lines[$i]}\033[0m" + [[ $i -lt $((max_lines - 1)) ]] && tput cud1 2>/dev/null + done + for ((i = 0; i < $max_lines + 1; i++)); do + tput cuu1 2>/dev/null + done + last_size=$current_size + return 0 + } + local spinner_frames=(${spinners[$spinner_style]}) + local temp_file="$(make_temp_file)" + trap "cleanup" INT TERM + tput civis 2>/dev/null + echo '' + echo '' + for ((i = 0; i < $max_lines; i++)); do + echo '' + done + eval "${cmd}" >"${temp_file}" 2>&1 & + local cmd_pid=$! + local last_size=0 + local spin_idx=0 + tput cuu $((max_lines + 2)) 2>/dev/null + sleep 0.05 + echo -ne "\r\033[K◉ ${title} [\033[1m\033[34m${spinner_frames[$spin_idx]}\033[0m]" + spin_idx=$(((spin_idx + 1) % ${#spinner_frames[@]})) + update_display + local update_count=0 + local adaptive_rate=$refresh_rate + while kill -0 $cmd_pid 2>/dev/null; do + echo -ne "\r\033[K◉ ${title} [\033[1m\033[34m${spinner_frames[$spin_idx]}\033[0m]" + spin_idx=$(((spin_idx + 1) % ${#spinner_frames[@]})) + if update_display; then + update_count=$((update_count + 1)) + if [[ $update_count -gt 5 ]]; then + adaptive_rate=$(awk "BEGIN {print $adaptive_rate * 1.5; exit}") + [[ $(awk "BEGIN {print ($adaptive_rate > 0.5); exit}") -eq 1 ]] && adaptive_rate=0.5 + update_count=0 + fi + else + update_count=0 + adaptive_rate=$refresh_rate + fi + sleep $adaptive_rate + done + wait $cmd_pid + local exit_status=$? + update_display + if [ $exit_status -eq 0 ]; then + echo -ne "\r\033[K◉ ${title} [\033[1m\033[32m✓\033[0m]\n" + else + echo -ne "\r\033[K◉ ${title} [\033[1m\033[31m✗\033[0m]\n" + fi + echo -ne "\r\033[K\n" + local actual_lines=$(wc -l <"${temp_file}" 2>/dev/null || echo 0) + [[ $actual_lines -gt $max_lines ]] && actual_lines=$max_lines + if [[ $actual_lines -gt 0 ]]; then + local -a final_lines=() + mapfile -t -n "$actual_lines" final_lines < <(tail -n "$actual_lines" "${temp_file}") + + for ((i = 0; i < actual_lines; i++)); do + local line=$(simple_truncate "${final_lines[$i]}") + echo -ne "\r\033[K\033[2m${line}\033[0m\n" + done + fi + tput cnorm 2>/dev/null + rm -f "${temp_file}" + return $exit_status +} + +############################################################################## + +MESSAGE_LANG_DEFAULT='zh-hans' +MESSAGE_LANG_KEYS=( + "zh-hans" + "zh-hant" + "en" +) +declare -A MESSAGE_LANG_DISPLAY=( + ['zh-hans']='简体中文' + ['zh-hant']='繁體中文' + ['en']='English' +) +declare -A MESSAGE_CONTENTS + +function msg() { + local key="$1" + shift + local text="${MESSAGE_CONTENTS[${key}]}" + if [[ -z "${text}" ]]; then + echo "${key}" + return + fi + while [[ $# -gt 0 ]]; do + if [[ "${text}" == *"{}"* ]]; then + text="${text/\{\}/$1}" + else + break + fi + shift + done + echo "${text}" +} + +function init_msg_pack() { + function load_pack() { + local func_name="${1}" + if declare -f "${func_name}" >/dev/null 2>&1; then + eval "${func_name}" + fi + } + local current_lang="${1:-${MESSAGE_LANG_DEFAULT}}" + current_lang="$(echo "${current_lang}" | sed 's/^-*//')" + current_lang="${current_lang,,}" + if [[ "${MESSAGE_LANG_DISPLAY[${current_lang}]}" ]]; then + current_lang="${current_lang//-/_}" + load_pack "msg_pack_${current_lang}" + fi +} + +function msg_pack_zh_hans() { + MESSAGE_CONTENTS=( + ['start.welcome']='欢迎使用 Docker Engine 安装与换源脚本' + ['start.runtimeEnv']='运行环境' + ['start.dateTime']='系统时间' + ['end.moreInfo']='脚本运行完毕,更多使用教程详见官网' + ['end.sponsorAds']='【赞助商广告】' + ['error.cmd.options.needConfirm']='请确认后重新输入' + ['error.cmd.options.needSpecify']='请在该选项后指定{}' + ['error.cmd.options.invalid']='命令选项 {} 无效,{}!' + ['error.cmd.options.validAddress']='有效的地址' + ['error.cmd.options.sourceAddress']='软件源地址' + ['error.cmd.options.registryAddress']='镜像仓库地址' + ['error.cmd.options.sourceRepository']='软件源仓库' + ['error.cmd.options.validVersion']='有效的版本号' + ['error.cmd.options.ceRepositoryVersion']='Docker CE 软件源仓库的版本号' + ['error.cmd.options.version']='版本号' + ['error.cmd.options.codename']='版本代号' + ['error.cmd.options.boolean']=' true 或 false ' + ['error.cmd.options.protocol']=' http 或 https ' + ['error.cmd.options.needProtocol']=' Web 协议(http/https)' + ['error.cmd.options.validLangKey']='有效的语言 ID ' + ['error.cmd.options.langKey']='语言 ' + ['error.unsupportSystem1']='不支持当前操作系统({})' + ['error.unsupportSystem2']='不支持当前操作系统({}),请参考如下命令自行安装:' + ['error.unknownSystem']='未知系统' + ['error.unsupportX86_32']='Docker Engine 不支持安装在 x86_32 架构的环境上!' + ['error.unknownArch']='未知的系统架构:{}' + ['error.unsupportS390x']='请查阅 RHEL 发行版声明以了解 s390x 支持' + ['error.input']='输入错误,{}!' + ['error.needRoot']='权限不足,请切换至 root 账户后运行本脚本,切换命令 {}' + ['error.sync']='{}出错,请先解决系统原有软件源错误以确保 {} 软件包管理工具可用!' + ['error.downloadGPG']='GPG 密钥下载失败,请检查网络或更换 Docker CE 软件源后重试!' + ['error.queryVersionFailed']='查询 Docker Engine 版本列表失败!' + ['error.designatedVersion']='指定的 Docker Engine 版本不存在或不支持安装!' + ['error.invalidVersion']='请输入正确的版本号!' + ['error.reEnter']='输入错误请重新输入!' + ['error.installDockerEngineFailed']='安装 Docker Engine 失败!' + ['error.installPackageFailed']='软件包 {} 安装失败,请自行安装后重新运行脚本!' + ['error.defaultBehavior.https']='默认使用 HTTPS 协议' + ['error.defaultBehavior.noClose']='默认不关闭' + ['error.defaultBehavior.installLatest']='默认安装最新版本' + ['error.defaultBehavior.noOverwrite']='默认不覆盖' + ['error.defaultBehavior.noUseIntranetSource']='默认不使用内网地址' + ['warn.usedIntranetSource']='已切换至内网专用地址,仅限在特定环境下使用!' + ['warn.needValidNumberIndex']='请输入有效的数字序号!' + ['warn.needInputNumberIndex']='请输入数字序号!' + ['warn.needManuallyDeleteConfig']='请自行删除 {} 中的 {} 配置并重启服务 {}' + ['tip.skipInstallDockerEngine']='检测到系统已安装 Docker Engine 且是最新版本,跳过安装' + ['info.backuped.dockerConfig']='已备份原有 Docker 配置文件' + ['interaction.source.type.public']='公网' + ['interaction.source.type.intranet']='内网' + ['interaction.source.type.select']='请选择 Docker CE 源的网络地址(访问方式):' + ['interaction.source.type.usePublicAddress']='默认使用 Docker CE 源的公网地址,是否继续' + ['interaction.source.dockerCE.select']='请选择你想使用的 Docker CE 源:' + ['interaction.source.dockerCE.selectAndInput']='请选择并输入你想使用的 Docker CE 源' + ['interaction.source.dockerRegistry.select']='请选择你想使用的 Docker Registry 源:' + ['interaction.source.dockerRegistry.selectAndInput']='请选择并输入你想使用的 Docker Registry 源' + ['interaction.protocol.select']='请选择 Docker CE 软件源的网络协议:' + ['interaction.protocol.useHttp']='Docker CE 软件源是否使用 HTTP 协议' + ['interaction.firewall.close']='是否关闭系统防火墙和 SELinux ' + ['interaction.install.selectVersion']='请选择你想安装的版本:' + ['interaction.install.selectedVersion']='指定安装版本:' + ['interaction.install.selectedTitle']='请选择你要安装的版本,如:{}' + ['interaction.install.inputVersion']='请根据上面的列表,选择并输入你想要安装的具体版本号:' + ['interaction.install.latestVersion']='Docker Engine 是否安装最新版本' + ['interaction.backup.skipOverwrite']='检测到已备份的 Docker 配置文件,是否跳过覆盖备份' + ['interaction.common.tip']='提示' + ['interaction.common.operationCanceled']='操作已取消' + ['interaction.common.yes']='是' + ['interaction.common.no']='否' + ['work.installDependents']='安装环境软件包' + ['work.installDockerEngine']='安装 Docker Engine' + ['source.sync.text1']='更新软件源' + ['source.sync.text2']='生成软件源缓存' + ['result.install.failed']='安装失败' + ['result.install.checkSourceFile']='检查源文件:' + ['result.install.manuallyExecCmd']='请尝试手动执行安装命令:{}' + ['result.install.notRunning']='检测到 Docker 服务启动异常,可尝试再次执行本脚本重试' + ['result.install.manuallyRun']='请执行 {} 命令尝试启动或自行查询错误原因' + ['result.registry.success']='已更换镜像仓库' + ['result.registry.dockerEngineNotExsit']='当前尚未安装 Docker Engine,请取消设置 {} 命令选项后重新执行脚本!' + ['commands.help']='命令选项(名称/含义/值): + + --source 指定 Docker CE 软件源地址(域名或IP) 地址 + --source-registry 指定 Docker 镜像仓库地址(域名或IP) 地址 + --branch 指定 Docker CE 软件源仓库(路径) 仓库名 + --branch-version 指定 Docker CE 软件源仓库版本 版本号 + --designated-version 指定 Docker Engine 安装版本 版本号 + --codename 指定 Debian 系操作系统的版本代号 代号名称 + --protocol 指定 Docker CE 软件源的 Web 协议 http 或 https + --use-intranet-source 是否优先使用内网 Docker CE 软件源地址 true 或 false + --install-latest 是否安装最新版本的 Docker Engine true 或 false + --close-firewall 是否关闭防火墙 true 或 false + --clean-screen 是否在运行前清除屏幕上的所有内容 true 或 false + --lang 指定脚本使用的语言 ID 语言 + --only-registry 仅更换镜像仓库模式 无 + --ignore-backup-tips 忽略覆盖备份提示 无 + --pure-mode 纯净模式,精简打印内容 无 + --help 查看帮助菜单 无 + +问题报告 {}' + ['mirrors.dockerCE.0']='阿里云' + ['mirrors.dockerCE.1']='腾讯云' + ['mirrors.dockerCE.2']='华为云' + ['mirrors.dockerCE.3']='移动云' + ['mirrors.dockerCE.4']='网易' + ['mirrors.dockerCE.5']='火山引擎' + ['mirrors.dockerCE.6']='微软 Azure 中国' + ['mirrors.dockerCE.7']='清华大学' + ['mirrors.dockerCE.8']='北京大学' + ['mirrors.dockerCE.9']='浙江大学' + ['mirrors.dockerCE.10']='南京大学' + ['mirrors.dockerCE.11']='上海交通大学' + ['mirrors.dockerCE.12']='重庆邮电大学' + ['mirrors.dockerCE.13']='中国科学技术大学' + ['mirrors.dockerCE.14']='中国科学院软件研究所' + ['mirrors.dockerCE.15']='官方源' + ['mirrors.registry.0']='毫秒镜像(推荐)' + ['mirrors.registry.1']='Docker Proxy' + ['mirrors.registry.2']='DaoCloud 道客' + ['mirrors.registry.3']='1Panel 镜像' + ['mirrors.registry.4']='阿里云(杭州)' + ['mirrors.registry.5']='阿里云(上海)' + ['mirrors.registry.6']='阿里云(青岛)' + ['mirrors.registry.7']='阿里云(北京)' + ['mirrors.registry.8']='阿里云(张家口)' + ['mirrors.registry.9']='阿里云(呼和浩特)' + ['mirrors.registry.10']='阿里云(乌兰察布)' + ['mirrors.registry.11']='阿里云(深圳)' + ['mirrors.registry.12']='阿里云(河源)' + ['mirrors.registry.13']='阿里云(广州)' + ['mirrors.registry.14']='阿里云(成都)' + ['mirrors.registry.15']='阿里云(香港)' + ['mirrors.registry.16']='阿里云(日本-东京)' + ['mirrors.registry.17']='阿里云(新加坡)' + ['mirrors.registry.18']='阿里云(马来西亚-吉隆坡)' + ['mirrors.registry.19']='阿里云(印度尼西亚-雅加达)' + ['mirrors.registry.20']='阿里云(德国-法兰克福)' + ['mirrors.registry.21']='阿里云(英国-伦敦)' + ['mirrors.registry.22']='阿里云(美国西部-硅谷)' + ['mirrors.registry.23']='阿里云(美国东部-弗吉尼亚)' + ['mirrors.registry.24']='阿里云(阿联酋-迪拜)' + ['mirrors.registry.25']='腾讯云' + ['mirrors.registry.26']='谷歌云(北美)' + ['mirrors.registry.27']='谷歌云(亚洲)' + ['mirrors.registry.28']='谷歌云(欧洲)' + ['mirrors.registry.29']='官方 Docker Hub' + ) +} + +function msg_pack_zh_hant() { + MESSAGE_CONTENTS=( + ['start.welcome']='歡迎使用 Docker Engine 安裝與換源腳本' + ['start.runtimeEnv']='執行環境' + ['start.dateTime']='系統時間' + ['end.moreInfo']='腳本執行完畢,更多使用教學詳見官網' + ['end.sponsorAds']='【贊助商廣告】' + ['error.cmd.options.needConfirm']='請確認後重新輸入' + ['error.cmd.options.needSpecify']='請在該選項後指定{}' + ['error.cmd.options.invalid']='命令選項 {} 無效,{}!' + ['error.cmd.options.validAddress']='有效的位址' + ['error.cmd.options.sourceAddress']='軟體源位址' + ['error.cmd.options.registryAddress']='映象倉庫位址' + ['error.cmd.options.sourceRepository']='軟體源倉庫' + ['error.cmd.options.validVersion']='有效的版本號' + ['error.cmd.options.ceRepositoryVersion']='Docker CE 軟體源倉庫的版本號' + ['error.cmd.options.version']='版本號' + ['error.cmd.options.codename']='版本代號' + ['error.cmd.options.boolean']=' true 或 false ' + ['error.cmd.options.protocol']=' http 或 https ' + ['error.cmd.options.needProtocol']=' Web 協定(http/https)' + ['error.cmd.options.validLangKey']='有效的語言 ID ' + ['error.cmd.options.langKey']='語言 ID ' + ['error.unsupportSystem1']='不支援當前作業系統({})' + ['error.unsupportSystem2']='不支援當前作業系統({}),請參考如下命令自行安裝:\n\n{}' + ['error.unknownSystem']='未知系統' + ['error.unsupportX86_32']='Docker Engine 不支援安裝在 x86_32 架構的環境上!' + ['error.unknownArch']='未知的系統架構:{}' + ['error.unsupportS390x']='請查閱 RHEL 發行版宣告以瞭解 s390x 支援' + ['error.input']='輸入錯誤,{}!' + ['error.needRoot']='權限不足,請切換至 root 帳戶後執行本腳本,切換指令 {}' + ['error.sync']='{}出錯,請先解決系統原有軟體源錯誤以確保 {} 軟體包管理工具可用!' + ['error.downloadGPG']='GPG 金鑰下載失敗,請檢查網路或更換 Docker CE 軟體源後重試!' + ['error.queryVersionFailed']='查詢 Docker Engine 版本清單失敗!' + ['error.designatedVersion']='指定的 Docker Engine 版本不存在或不支援安裝!' + ['error.invalidVersion']='請輸入正確的版本號!' + ['error.reEnter']='輸入錯誤請重新輸入!' + ['error.installDockerEngineFailed']='安裝 Docker Engine 失敗!' + ['error.installPackageFailed']='軟體包 {} 安裝失敗,請自行安裝後重新執行腳本!' + ['error.defaultBehavior.https']='預設使用 HTTPS 協定' + ['error.defaultBehavior.noClose']='預設不關閉' + ['error.defaultBehavior.installLatest']='預設安裝最新版本' + ['error.defaultBehavior.noOverwrite']='預設不覆寫' + ['error.defaultBehavior.noUseIntranetSource']='預設不使用內網位址' + ['warn.usedIntranetSource']='已切換至內網專用位址,僅限在特定環境下使用!' + ['warn.needValidNumberIndex']='請輸入有效的數字序號!' + ['warn.needInputNumberIndex']='請輸入數字序號!' + ['warn.needManuallyDeleteConfig']='請自行刪除 {} 中的 {} 設定並重新啟動服務 {}' + ['tip.skipInstallDockerEngine']='偵測到系統已安裝 Docker Engine 且是最新版本,跳過安裝' + ['info.backuped.dockerConfig']='已備份原有 Docker 設定檔' + ['interaction.source.type.public']='公網' + ['interaction.source.type.intranet']='內網' + ['interaction.source.type.select']='請選擇 Docker CE 源的網路位址(存取方式):' + ['interaction.source.type.usePublicAddress']='預設使用 Docker CE 源的公網位址,是否繼續' + ['interaction.source.dockerCE.select']='請選擇你想使用的 Docker CE 源:' + ['interaction.source.dockerCE.selectAndInput']='請選擇並輸入你想使用的 Docker CE 源' + ['interaction.source.dockerRegistry.select']='請選擇你想使用的 Docker Registry 源:' + ['interaction.source.dockerRegistry.selectAndInput']='請選擇並輸入你想使用的 Docker Registry 源' + ['interaction.protocol.select']='請選擇 Docker CE 軟體源的網路協定:' + ['interaction.protocol.useHttp']='Docker CE 軟體源是否使用 HTTP 協定' + ['interaction.firewall.close']='是否關閉系統防火牆和 SELinux ' + ['interaction.install.selectVersion']='請選擇你想安裝的版本:' + ['interaction.install.selectedVersion']='指定安裝版本:' + ['interaction.install.selectedTitle']='請選擇你要安裝的版本,如:{}' + ['interaction.install.inputVersion']='請根據上面的清單,選擇並輸入你想要安裝的具體版本號:' + ['interaction.install.latestVersion']='Docker Engine 是否安裝最新版本' + ['interaction.backup.skipOverwrite']='偵測到已備份的 Docker 設定檔,是否跳過覆寫備份' + ['interaction.common.tip']='提示' + ['interaction.common.operationCanceled']='操作已取消' + ['interaction.common.yes']='是' + ['interaction.common.no']='否' + ['work.installDependents']='安裝環境軟體包' + ['work.installDockerEngine']='安裝 Docker Engine' + ['source.sync.text1']='更新軟體源' + ['source.sync.text2']='產生軟體源快取' + ['result.install.failed']='安裝失敗' + ['result.install.checkSourceFile']='檢查源檔案:' + ['result.install.manuallyExecCmd']='請嘗試手動執行安裝命令:{}' + ['result.install.notRunning']='偵測到 Docker 服務啟動異常,可嘗試再次執行本腳本重試' + ['result.install.manuallyRun']='請執行 {} 命令嘗試啟動或自行查詢錯誤原因' + ['result.registry.success']='已更換映象倉庫' + ['result.registry.dockerEngineNotExsit']='目前尚未安裝 Docker Engine,請取消設定 {} 命令選項後重新執行腳本!' + ['commands.help']='命令選項(名稱/含義/值): + + --source 指定 Docker CE 軟體源位址(網域名稱或IP) 位址 + --source-registry 指定 Docker 映像倉庫位址 (網域名稱或IP) 位址 + --branch 指定 Docker CE 軟體源倉庫 (路徑) 倉庫名稱 + --branch-version 指定 Docker CE 軟體源倉庫版本 版本號 + --designated-version 指定 Docker Engine 安裝版本 版本號 + --codename 指定 Debian 係作業系統的版本代號 代號名稱 + --protocol 指定 Docker CE 源的 Web 協定 http 或 https + --use-intranet-source 是否優先使用內部網路 Docker CE 軟體源位址 true 或 false + --install-latest 是否安裝最新版本的 Docker Engine true 或 false + --close-firewall 是否關閉防火牆 true 或 false + --clean-screen 是否在運行前清除螢幕上的所有內容 true 或 false + --lang 指定腳本輸出的語言 语言 + --only-registry 僅更換映像倉庫模式 無 + --ignore-backup-tips 忽略覆蓋備份提示 無 + --pure-mode 純淨模式,精簡列印內容 無 + --help 查看幫助選單 無 + +問題報告 {}' + ['mirrors.dockerCE.0']='阿里雲' + ['mirrors.dockerCE.1']='騰訊雲' + ['mirrors.dockerCE.2']='華為雲' + ['mirrors.dockerCE.3']='移動雲' + ['mirrors.dockerCE.4']='網易' + ['mirrors.dockerCE.5']='火山引擎' + ['mirrors.dockerCE.6']='微軟 Azure 中國' + ['mirrors.dockerCE.7']='清華大學' + ['mirrors.dockerCE.8']='北京大學' + ['mirrors.dockerCE.9']='浙江大學' + ['mirrors.dockerCE.10']='南京大學' + ['mirrors.dockerCE.11']='上海交通大學' + ['mirrors.dockerCE.12']='重慶郵電大學' + ['mirrors.dockerCE.13']='中國科學技術大學' + ['mirrors.dockerCE.14']='中國科學院軟體研究所' + ['mirrors.dockerCE.15']='官方源' + ['mirrors.registry.0']='毫秒鏡像(推薦)' + ['mirrors.registry.1']='Docker Proxy' + ['mirrors.registry.2']='DaoCloud 道客' + ['mirrors.registry.3']='1Panel 鏡像' + ['mirrors.registry.4']='阿里雲(杭州)' + ['mirrors.registry.5']='阿里雲(上海)' + ['mirrors.registry.6']='阿里雲(青島)' + ['mirrors.registry.7']='阿里雲(北京)' + ['mirrors.registry.8']='阿里雲(張家口)' + ['mirrors.registry.9']='阿里雲(呼和浩特)' + ['mirrors.registry.10']='阿里雲(烏蘭察布)' + ['mirrors.registry.11']='阿里雲(深圳)' + ['mirrors.registry.12']='阿里雲(河源)' + ['mirrors.registry.13']='阿里雲(廣州)' + ['mirrors.registry.14']='阿里雲(成都)' + ['mirrors.registry.15']='阿里雲(香港)' + ['mirrors.registry.16']='阿里雲(日本-東京)' + ['mirrors.registry.17']='阿里雲(新加坡)' + ['mirrors.registry.18']='阿里雲(馬來西亞-吉隆坡)' + ['mirrors.registry.19']='阿里雲(印度尼西亞-雅加達)' + ['mirrors.registry.20']='阿里雲(德國-法蘭克福)' + ['mirrors.registry.21']='阿里雲(英國-倫敦)' + ['mirrors.registry.22']='阿里雲(美國西部-矽谷)' + ['mirrors.registry.23']='阿里雲(美國東部-弗吉尼亞)' + ['mirrors.registry.24']='阿里雲(阿聯酋-迪拜)' + ['mirrors.registry.25']='騰訊雲' + ['mirrors.registry.26']='谷歌雲(北美)' + ['mirrors.registry.27']='谷歌雲(亞洲)' + ['mirrors.registry.28']='谷歌雲(歐洲)' + ['mirrors.registry.29']='官方 Docker Hub' + ) + SPONSOR_ADS[0]="1Panel · 新一代的 Linux 伺服器維運管理面板 ➜ \033[3mhttps://1panel.cn\033[0m" +} + +function msg_pack_en() { + MESSAGE_CONTENTS=( + ['start.welcome']='Docker installation & mirror switcher' + ['start.runtimeEnv']='Runtime Env' + ['start.dateTime']='System Time' + ['end.moreInfo']='Script execution completed, visit our website for more tutorials' + ['end.sponsorAds']='[Sponsor Ads]' + ['error.cmd.options.needConfirm']='Please confirm and re-enter' + ['error.cmd.options.needSpecify']='Please specify {} after this option' + ['error.cmd.options.invalid']='Command option {} is invalid, {}!' + ['error.cmd.options.validAddress']='a valid address' + ['error.cmd.options.sourceAddress']='mirror address' + ['error.cmd.options.registryAddress']='registry mirror address' + ['error.cmd.options.sourceRepository']='mirror repository' + ['error.cmd.options.validVersion']='a valid version number' + ['error.cmd.options.ceRepositoryVersion']='Docker CE mirror repository version' + ['error.cmd.options.version']='version number' + ['error.cmd.options.codename']='version codename' + ['error.cmd.options.boolean']=' true or false ' + ['error.cmd.options.protocol']=' http or https ' + ['error.cmd.options.needProtocol']=' Web protocol(http/https)' + ['error.cmd.options.validLangKey']='A valid language ID ' + ['error.cmd.options.langKey']='language ID ' + ['error.unsupportSystem1']='Unsupported operating system ({})' + ['error.unsupportSystem2']='Unsupported operating system ({}), please install manually with commands:' + ['error.unknownSystem']='Unknown system' + ['error.unsupportX86_32']='Docker Engine does not support installation on x86_32 architecture!' + ['error.unknownArch']='Unknown system architecture: {}' + ['error.unsupportS390x']='Please refer to RHEL distribution announcement for s390x support' + ['error.input']='Input error, {}!' + ['error.needRoot']='Insufficient privileges, please run this script as root. Switch command: {}' + ['error.sync']='{} failed. Please fix system software sources (package repositories) so the {} package manager is available!' + ['error.downloadGPG']='GPG key download failed, please check network or switch Docker CE mirror and retry!' + ['error.queryVersionFailed']='Failed to query Docker Engine version list!' + ['error.designatedVersion']='Specified Docker Engine version does not exist or is not supported for installation!' + ['error.invalidVersion']='Please enter a valid version number!' + ['error.reEnter']='Input error, please re-enter!' + ['error.installDockerEngineFailed']='Docker Engine installation failed!' + ['error.installPackageFailed']='Package {} installation failed, please install manually and rerun script!' + ['error.defaultBehavior.https']='Using HTTPS protocol by default' + ['error.defaultBehavior.noClose']='Not closing by default' + ['error.defaultBehavior.installLatest']='Installing latest version by default' + ['error.defaultBehavior.noOverwrite']='Not overwriting by default' + ['error.defaultBehavior.noUseIntranetSource']='Not using intranet address by default' + ['warn.usedIntranetSource']='Switched to intranet-only address, use only in specific environments!' + ['warn.needValidNumberIndex']='Please enter a valid number index!' + ['warn.needInputNumberIndex']='Please enter a number index!' + ['warn.needManuallyDeleteConfig']='Please manually delete {} configuration in {} and restart service {}' + ['tip.skipInstallDockerEngine']='Detected Docker Engine is already installed with latest version, skipping installation' + ['info.backuped.dockerConfig']='Original Docker config file has been backed up' + ['interaction.source.type.public']='Public' + ['interaction.source.type.intranet']='Intranet' + ['interaction.source.type.select']='Please select network address (access method) for Docker CE mirror:' + ['interaction.source.type.usePublicAddress']='Use public network address for Docker CE mirror by default, continue' + ['interaction.source.dockerCE.select']='Please select the Docker CE mirror you want to use:' + ['interaction.source.dockerCE.selectAndInput']='Please select and enter the Docker CE mirror you want to use' + ['interaction.source.dockerRegistry.select']='Please select the Docker Registry mirror you want to use:' + ['interaction.source.dockerRegistry.selectAndInput']='Please select and enter the Docker Registry mirror you want to use' + ['interaction.protocol.select']='Please select network protocol for Docker CE mirror:' + ['interaction.protocol.useHttp']='Use HTTP protocol for Docker CE mirror' + ['interaction.firewall.close']='Close system firewall and SELinux' + ['interaction.install.selectVersion']='Please select the version you want to install:' + ['interaction.install.selectedVersion']='Specified installation version:' + ['interaction.install.selectedTitle']='Please select the version to install, e.g.: {}' + ['interaction.install.inputVersion']='Based on the list above, please select and enter the specific version you want to install:' + ['interaction.install.latestVersion']='Install latest version of Docker Engine' + ['interaction.backup.skipOverwrite']='Detected existing backup of Docker config file, skip overwriting backup' + ['interaction.common.tip']='Tip' + ['interaction.common.operationCanceled']='Operation canceled' + ['interaction.common.yes']='Yes' + ['interaction.common.no']='No' + ['work.installDependents']='Install environment packages' + ['work.installDockerEngine']='Install Docker Engine' + ['source.sync.text1']='Update APT package index' + ['source.sync.text2']='Generate mirror cache' + ['result.install.failed']='Installation failed' + ['result.install.checkSourceFile']='Check source file:' + ['result.install.manuallyExecCmd']='Please try manually executing installation command: {}' + ['result.install.notRunning']='Detected Docker service startup error, try running this script again' + ['result.install.manuallyRun']='Please execute {} command to try starting or investigate error cause' + ['result.registry.success']='Registry mirror replaced successfully' + ['result.registry.dockerEngineNotExsit']='Docker Engine is not installed yet, please remove {} command option and rerun script!' + ['commands.help']='Command options(name/meaning/value): + + --source Specify Docker CE mirror address (domain or IP) address + --source-registry Specify Docker Registry mirror address (domain or IP) address + --branch Specify Docker CE mirror repository (path) repo name + --branch-version Specify Docker CE mirror repository version version + --designated-version Specify Docker Engine installation version version + --codename Specify Debian-based OS codename codename + --protocol Specify Web protocol for Docker CE mirror http or https + --use-intranet-source Prefer intranet Docker CE mirror address true or false + --install-latest Whether to install the latest Docker Engine true or false + --close-firewall Whether to disable the firewall true or false + --clean-screen Whether to clear the screen before running true or false + --lang Specify the language of the script output language + --only-registry Only switch registry mirror mode none + --ignore-backup-tips Ignore backup overwrite prompt (do not backup) none + --pure-mode Pure mode, minimal output none + --help Show help menu none + +Issue Report {}' + ['mirrors.dockerCE.0']='Alibaba Cloud' + ['mirrors.dockerCE.1']='Tencent Cloud' + ['mirrors.dockerCE.2']='Huawei Cloud' + ['mirrors.dockerCE.3']='China Mobile Cloud' + ['mirrors.dockerCE.4']='NetEase' + ['mirrors.dockerCE.5']='Volcengine' + ['mirrors.dockerCE.6']='Microsoft Azure China' + ['mirrors.dockerCE.7']='Tsinghua University' + ['mirrors.dockerCE.8']='Peking University' + ['mirrors.dockerCE.9']='Zhejiang University' + ['mirrors.dockerCE.10']='Nanjing University' + ['mirrors.dockerCE.11']='Shanghai Jiao Tong University' + ['mirrors.dockerCE.12']='Chongqing University of Posts and Telecommunications' + ['mirrors.dockerCE.13']='University of Science and Technology of China' + ['mirrors.dockerCE.14']='Institute of Software, Chinese Academy of Sciences' + ['mirrors.dockerCE.15']='Official Source' + ['mirrors.registry.0']='Millisecond Mirror (recommended)' + ['mirrors.registry.1']='Docker Proxy' + ['mirrors.registry.2']='DaoCloud' + ['mirrors.registry.3']='1Panel Mirror' + ['mirrors.registry.4']='Alibaba Cloud (Hangzhou)' + ['mirrors.registry.5']='Alibaba Cloud (Shanghai)' + ['mirrors.registry.6']='Alibaba Cloud (Qingdao)' + ['mirrors.registry.7']='Alibaba Cloud (Beijing)' + ['mirrors.registry.8']='Alibaba Cloud (Zhangjiakou)' + ['mirrors.registry.9']='Alibaba Cloud (Hohhot)' + ['mirrors.registry.10']='Alibaba Cloud (Ulanqab)' + ['mirrors.registry.11']='Alibaba Cloud (Shenzhen)' + ['mirrors.registry.12']='Alibaba Cloud (Heyuan)' + ['mirrors.registry.13']='Alibaba Cloud (Guangzhou)' + ['mirrors.registry.14']='Alibaba Cloud (Chengdu)' + ['mirrors.registry.15']='Alibaba Cloud (Hong Kong)' + ['mirrors.registry.16']='Alibaba Cloud (Japan - Tokyo)' + ['mirrors.registry.17']='Alibaba Cloud (Singapore)' + ['mirrors.registry.18']='Alibaba Cloud (Malaysia - Kuala Lumpur)' + ['mirrors.registry.19']='Alibaba Cloud (Indonesia - Jakarta)' + ['mirrors.registry.20']='Alibaba Cloud (Germany - Frankfurt)' + ['mirrors.registry.21']='Alibaba Cloud (UK - London)' + ['mirrors.registry.22']='Alibaba Cloud (US West - Silicon Valley)' + ['mirrors.registry.23']='Alibaba Cloud (US East - Virginia)' + ['mirrors.registry.24']='Alibaba Cloud (UAE - Dubai)' + ['mirrors.registry.25']='Tencent Cloud' + ['mirrors.registry.26']='Google Cloud (North America)' + ['mirrors.registry.27']='Google Cloud (Asia)' + ['mirrors.registry.28']='Google Cloud (Europe)' + ['mirrors.registry.29']='Official Docker Hub' + ) + SPONSOR_ADS=( + "1Panel · Top-Rated Web-based Linux Server Management Tool ➜ \033[3mhttps://1panel.cn\033[0m" + ) +} + +init_msg_pack +handle_command_options "$@" +main diff --git a/change-mirror/DockerInstallationLite.sh b/change-mirror/DockerInstallationLite.sh new file mode 100644 index 0000000..1e167c2 --- /dev/null +++ b/change-mirror/DockerInstallationLite.sh @@ -0,0 +1,1770 @@ +#!/bin/bash +## Author: SuperManito +## Modified: 2025-12-06 +## License: MIT +## GitHub: https://github.com/SuperManito/LinuxMirrors +## Website: https://linuxmirrors.cn + +SOURCE="download.docker.com" +SOURCE_REGISTRY="registry.hub.docker.com" +WEB_PROTOCOL="https" +INSTALL_LATESTED_DOCKER="true" +IGNORE_BACKUP_TIPS="true" +CLOSE_FIREWALL="true" + +############################################################################## + +## 定义系统判定变量 +SYSTEM_DEBIAN="Debian" +SYSTEM_UBUNTU="Ubuntu" +SYSTEM_KALI="Kali" +SYSTEM_DEEPIN="Deepin" +SYSTEM_LINUX_MINT="Linuxmint" +SYSTEM_ZORIN="Zorin" +SYSTEM_RASPBERRY_PI_OS="Raspberry Pi OS" +SYSTEM_REDHAT="RedHat" +SYSTEM_RHEL="Red Hat Enterprise Linux" +SYSTEM_CENTOS="CentOS" +SYSTEM_CENTOS_STREAM="CentOS Stream" +SYSTEM_ROCKY="Rocky" +SYSTEM_ALMALINUX="AlmaLinux" +SYSTEM_FEDORA="Fedora" +SYSTEM_ORACLE="Oracle Linux" +SYSTEM_OPENCLOUDOS="OpenCloudOS" +SYSTEM_OPENCLOUDOS_STREAM="OpenCloudOS Stream" +SYSTEM_TENCENTOS="TencentOS" +SYSTEM_OPENEULER="openEuler" +SYSTEM_ANOLISOS="Anolis" +SYSTEM_KYLIN_DESKTOP="Kylin Desktop" +SYSTEM_KYLIN_SERVER="Kylin Server" +SYSTEM_OPENKYLIN="openKylin" +SYSTEM_OPENSUSE="openSUSE" +SYSTEM_ARCH="Arch" +SYSTEM_MANJARO="Manjaro" +SYSTEM_ALPINE="Alpine" +SYSTEM_GENTOO="Gentoo" +SYSTEM_NIXOS="NixOS" + +## 定义系统版本文件 +File_LinuxRelease=/etc/os-release +File_RedHatRelease=/etc/redhat-release +File_DebianVersion=/etc/debian_version +File_ArmbianRelease=/etc/armbian-release +File_RaspberryPiOSRelease=/etc/rpi-issue +File_openEulerRelease=/etc/openEuler-release +File_HuaweiCloudEulerOSRelease=/etc/hce-release +File_OpenCloudOSRelease=/etc/opencloudos-release +File_TencentOSServerRelease=/etc/tlinux-release +File_AnolisOSRelease=/etc/anolis-release +File_AlibabaCloudLinuxRelease=/etc/alinux-release +File_OracleLinuxRelease=/etc/oracle-release +File_ArchLinuxRelease=/etc/arch-release +File_ManjaroRelease=/etc/manjaro-release +File_AlpineRelease=/etc/alpine-release +File_GentooRelease=/etc/gentoo-release +File_KylinRelease=/etc/kylin-release +File_kylinVersion=/etc/kylin-version/kylin-system-version.conf +File_ProxmoxVersion=/etc/pve/.version + +## 定义软件源相关文件或目录 +File_AptSourceList=/etc/apt/sources.list +Dir_AptAdditionalSources=/etc/apt/sources.list.d +Dir_YumRepos=/etc/yum.repos.d + +## 定义 Docker 相关变量 +Dir_Docker=/etc/docker +File_DockerConfig=$Dir_Docker/daemon.json +File_DockerConfigBackup=$Dir_Docker/daemon.json.bak +File_DockerVersionTmp=docker-version.txt +File_DockerCEVersionTmp=docker-ce-version.txt +File_DockerCECliVersionTmp=docker-ce-cli-version.txt +File_DockerSourceList=$Dir_AptAdditionalSources/docker.list +File_DockerRepo=$Dir_YumRepos/docker-ce.repo + +## 定义颜色和样式变量 +RED='\033[31m' +GREEN='\033[32m' +YELLOW='\033[33m' +BLUE='\033[34m' +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 WARN ${PLAIN}" +ERROR="\033[1;31m✘${PLAIN}" +FAIL="\033[1;31m✘${PLAIN}" +TIP="\033[1;44m TIP ${PLAIN}" +WORKING="\033[1;36m◉${PLAIN}" + +function main() { + permission_judgment + collect_system_info + run_start + choose_mirrors + if [[ "${ONLY_REGISTRY}" == "true" ]]; then + only_change_docker_registry_mirror + else + choose_protocol + close_firewall_service + install_dependency_packages + configure_docker_ce_mirror + install_docker_engine + change_docker_registry_mirror + check_installed_result + fi + run_end +} + +function handle_command_options() { + ## 判断参数 + while [ $# -gt 0 ]; do + case "$1" in + ## 指定 Docker CE 软件源地址 + --source) + if [ "$2" ]; then + echo "$2" | grep -Eq "\(|\)|\[|\]|\{|\}" + if [ $? -eq 0 ]; then + command_error "$2" "$(msg "error.cmd.options.validAddress")" + else + SOURCE="$(echo "$2" | sed -e 's,^http[s]\?://,,g' -e 's,/$,,')" + shift + fi + else + command_error "$1" "$(msg "error.cmd.options.sourceAddress")" + fi + ;; + ## 指定 Docker Registry 仓库地址 + --source-registry) + if [ "$2" ]; then + echo "$2" | grep -Eq "\(|\)|\[|\]|\{|\}" + if [ $? -eq 0 ]; then + command_error "$2" "$(msg "error.cmd.options.validAddress")" + else + SOURCE_REGISTRY="$(echo "$2" | sed -e 's,^http[s]\?://,,g' -e 's,/$,,')" + shift + fi + else + command_error "$1" "$(msg "error.cmd.options.registryAddress")" + fi + ;; + ## 指定 Docker CE 软件源仓库 + --branch) + if [ "$2" ]; then + SOURCE_BRANCH="$2" + shift + else + command_error "$1" "$(msg "error.cmd.options.sourceRepository")" + fi + ;; + ## 指定 Docker CE 软件源仓库版本 + --branch-version) + if [ "$2" ]; then + echo "$2" | grep -Eq "^[0-9]{1,2}$" + if [ $? -eq 0 ]; then + SOURCE_BRANCH_VERSION="$2" + shift + else + command_error "$2" "$(msg "error.cmd.options.validVersion")" + fi + else + command_error "$1" "$(msg "error.cmd.options.ceRepositoryVersion")" + fi + ;; + ## 指定 Docker Engine 安装版本 + --designated-version) + if [ "$2" ]; then + echo "$2" | grep -Eq "^[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}$" + if [ $? -eq 0 ]; then + DESIGNATED_DOCKER_VERSION="$2" + shift + else + command_error "$2" "$(msg "error.cmd.options.validVersion")" + fi + else + command_error "$1" "$(msg "error.cmd.options.version")" + fi + ;; + ## 指定 Debian 版本代号 + --codename) + if [ "$2" ]; then + DEBIAN_CODENAME="$2" + shift + else + command_error "$1" "$(msg "error.cmd.options.codename")" + fi + ;; + ## Web 协议(HTTP/HTTPS) + --protocol) + if [ "$2" ]; then + case "$2" in + http | https | HTTP | HTTPS) + WEB_PROTOCOL="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.protocol")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.needProtocol")" + fi + ;; + ## 安装最新版本 + --install-latest | --install-latested) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + INSTALL_LATESTED_DOCKER="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.needIntranetSource")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.needIntranetSource")" + fi + ;; + ## 关闭防火墙 + --close-firewall) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + CLOSE_FIREWALL="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.needIntranetSource")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.needIntranetSource")" + fi + ;; + ## 清除屏幕上的所有内容 + --clean-screen) + if [ "$2" ]; then + case "$2" in + [Tt]rue | [Ff]alse) + CLEAN_SCREEN="${2,,}" + shift + ;; + *) + command_error "$2" "$(msg "error.cmd.options.needIntranetSource")" + ;; + esac + else + command_error "$1" "$(msg "error.cmd.options.needIntranetSource")" + fi + ;; + ## 仅更换镜像仓库模式 + --only-registry) + ONLY_REGISTRY="true" + ;; + ## 纯净模式 + --pure-mode) + PURE_MODE="true" + ;; + ## 命令帮助 + --help) + echo -e "\n$(msg "commands.help" "https://github.com/SuperManito/LinuxMirrors/issues")\n" + exit + ;; + *) + command_error "$1" + ;; + esac + shift + done + ## 设置部分功能的默认值 + IGNORE_BACKUP_TIPS="${IGNORE_BACKUP_TIPS:-"false"}" + if [[ "${DESIGNATED_DOCKER_VERSION}" ]]; then + INSTALL_LATESTED_DOCKER="false" + fi + PURE_MODE="${PURE_MODE:-"false"}" +} + +function run_start() { :; } + +function run_end() { + if [[ "${PURE_MODE}" == "true" ]]; then + echo '' + return + fi + echo -e "\n\033[3;1mPowered by \033[34mLinuxMirrors\033[0m - \033[3mhttps://linuxmirrors.cn\033[0m\n" +} + +function output_error() { + [ "$1" ] && echo -e "\n$ERROR $1\n" + exit 1 +} + +function command_error() { + local tmp_text="$(msg "error.cmd.options.needConfirm")" + if [[ "${2}" ]]; then + tmp_text="$(msg "error.cmd.options.needSpecify" "${2}")" + fi + output_error "$(msg "error.cmd.options.invalid" "${BLUE}$1${PLAIN}" "${tmp_text}")" +} + +function unsupport_system_error() { + if [[ "${2}" ]]; then + output_error "$(msg "error.unsupportSystem2" "${1}")\n\n${BLUE}$2${PLAIN}" + else + output_error "$(msg "error.unsupportSystem1" "${1}")" + fi +} + +function input_error() { + echo -e "\n$WARN $(msg "error.input" "${1}")" +} + +function command_exists() { + command -v "$@" &>/dev/null +} + +function permission_judgment() { + if [ $UID -ne 0 ]; then + local change_cmd="su root" + if command_exists sudo; then + change_cmd="sudo -i" + fi + output_error "$(msg "error.needRoot" "${BLUE}${change_cmd}${PLAIN}")" + fi +} + +function get_os_release_value() { + grep -E "^${1}=" $File_LinuxRelease | cut -d= -f2- | sed "s/[\'\"]//g" +} + +function collect_system_info() { + if [ ! -s "${File_LinuxRelease}" ]; then + unsupport_system_error "$(msg "error.unknownSystem")" + fi + ## 定义系统名称 + SYSTEM_NAME="$(get_os_release_value NAME)" + SYSTEM_PRETTY_NAME="$(get_os_release_value PRETTY_NAME)" + ## 定义系统版本号 + SYSTEM_VERSION_ID="$(get_os_release_value VERSION_ID)" + SYSTEM_VERSION_ID_MAJOR="${SYSTEM_VERSION_ID%%.*}" + SYSTEM_VERSION_ID_MINOR="${SYSTEM_VERSION_ID#*.}" + ## 定义系统ID + SYSTEM_ID="$(get_os_release_value ID)" + ## 判定当前系统派系 + if [ -s "${File_DebianVersion}" ]; then + SYSTEM_FACTIONS="${SYSTEM_DEBIAN}" + if [ -s "${File_kylinVersion}" ]; then + [[ "${ONLY_REGISTRY}" != "true" ]] && unsupport_system_error "Kylin Desktop" "apt-get install -y docker\nsystemctl enable --now docker.io" + fi + elif [ -s "${File_RedHatRelease}" ]; then + SYSTEM_FACTIONS="${SYSTEM_REDHAT}" + elif [ -s "${File_openEulerRelease}" ] || [ -s "${File_HuaweiCloudEulerOSRelease}" ]; 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_TencentOSServerRelease}" ]; then + SYSTEM_FACTIONS="${SYSTEM_TENCENTOS}" # 自 4 版本起不再基于红帽 + elif [ -s "${File_kylinVersion}" ] || [ -s "${File_KylinRelease}" ]; then + if [[ "${SYSTEM_ID}" == *"openkylin"* ]]; then + SYSTEM_FACTIONS="${SYSTEM_OPENKYLIN}" + else + SYSTEM_FACTIONS="${SYSTEM_KYLIN_SERVER}" + fi + elif [ -f "${File_ArchLinuxRelease}" ]; then + [[ "${ONLY_REGISTRY}" != "true" ]] && unsupport_system_error "Arch Linux" "pacman -S docker\nsystemctl enable --now docker" + elif [ -f "${File_GentooRelease}" ]; then + [[ "${ONLY_REGISTRY}" != "true" ]] && unsupport_system_error "Gentoo" + elif [[ "${SYSTEM_NAME}" == *"openSUSE"* ]]; then + [[ "${ONLY_REGISTRY}" != "true" ]] && unsupport_system_error "openSUSE" "zypper install docker\nsystemctl enable --now docker" + elif [[ "${SYSTEM_NAME}" == *"NixOS"* ]]; then + [[ "${ONLY_REGISTRY}" != "true" ]] && unsupport_system_error "NixOS" + else + unsupport_system_error "$(msg "error.unknownSystem")" + fi + ## 判定系统类型、版本、版本号 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + if command_exists lsb_release; then + SYSTEM_JUDGMENT="$(lsb_release -is)" + SYSTEM_VERSION_CODENAME="${DEBIAN_CODENAME:-"$(lsb_release -cs)"}" + else + ## https://codeberg.org/gioele/lsb-release-minimal + SYSTEM_JUDGMENT="${SYSTEM_ID^}" + if [ "${SYSTEM_NAME}" ]; then + if [[ "${SYSTEM_ID,,}" == "${SYSTEM_NAME,,}" ]]; then + SYSTEM_JUDGMENT="${SYSTEM_NAME}" + fi + fi + SYSTEM_VERSION_CODENAME="${DEBIAN_CODENAME:-"$(get_os_release_value VERSION_CODENAME)"}" + fi + # Raspberry Pi OS + if [ -s "${File_RaspberryPiOSRelease}" ]; then + SYSTEM_JUDGMENT="${SYSTEM_RASPBERRY_PI_OS}" + SYSTEM_PRETTY_NAME="${SYSTEM_RASPBERRY_PI_OS}" + fi + ;; + "${SYSTEM_REDHAT}") + SYSTEM_JUDGMENT="$(awk '{printf $1}' $File_RedHatRelease)" + ## 特殊系统判断 + # Red Hat Enterprise Linux + grep -q "${SYSTEM_RHEL}" $File_RedHatRelease && SYSTEM_JUDGMENT="${SYSTEM_RHEL}" + # CentOS Stream + grep -q "${SYSTEM_CENTOS_STREAM}" $File_RedHatRelease && SYSTEM_JUDGMENT="${SYSTEM_CENTOS_STREAM}" + # Oracle Linux + [ -s "${File_OracleLinuxRelease}" ] && SYSTEM_JUDGMENT="${SYSTEM_ORACLE}" + ;; + *) + SYSTEM_JUDGMENT="${SYSTEM_FACTIONS}" + ;; + esac + ## 判定系统处理器架构 + DEVICE_ARCH_RAW="$(uname -m)" + case "${DEVICE_ARCH_RAW}" in + x86_64) + DEVICE_ARCH="x86_64" + ;; + aarch64) + DEVICE_ARCH="ARM64" + ;; + armv8l) + DEVICE_ARCH="ARMv8_32" + ;; + armv7l) + DEVICE_ARCH="ARMv7" + ;; + armv6l) + DEVICE_ARCH="ARMv6" + ;; + armv5tel) + DEVICE_ARCH="ARMv5" + ;; + ppc64le) + DEVICE_ARCH="ppc64le" + ;; + s390x) + DEVICE_ARCH="s390x" + ;; + i386 | i686) + output_error "$(msg "error.unsupportX86_32")" + ;; + *) + output_error "$(msg "error.unknownArch" "${DEVICE_ARCH_RAW}")" + ;; + esac + ## 定义软件源仓库名称 + if [[ -z "${SOURCE_BRANCH}" ]]; then + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + local debian_codename_latest="trixie" + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_DEBIAN}") + SOURCE_BRANCH="debian" + ;; + "${SYSTEM_UBUNTU}" | "${SYSTEM_ZORIN}") + SOURCE_BRANCH="ubuntu" + ;; + "${SYSTEM_KALI}") + SOURCE_BRANCH="debian" + SOURCE_BRANCH_CODENAME="${debian_codename_latest}" + ;; + "${SYSTEM_LINUX_MINT}") + if [[ "${SYSTEM_NAME}" == *"LMDE"* ]]; then + SOURCE_BRANCH="debian" + SOURCE_BRANCH_CODENAME="$(get_os_release_value DEBIAN_CODENAME)" + else + SOURCE_BRANCH="ubuntu" + SOURCE_BRANCH_CODENAME="$(get_os_release_value UBUNTU_CODENAME)" + fi + if [[ -z "${SOURCE_BRANCH_CODENAME}" ]]; then + SOURCE_BRANCH="debian" + SOURCE_BRANCH_CODENAME="bookworm" + fi + ;; + "${SYSTEM_RASPBERRY_PI_OS}") + case "${DEVICE_ARCH_RAW}" in + x86_64 | aarch64) + SOURCE_BRANCH="debian" + ;; + *) + # 注:自 Docker 29 版本起将不再提供此分支仓库 + SOURCE_BRANCH="raspbian" + ;; + esac + ;; + # "${SYSTEM_KYLIN_DESKTOP}") + # SOURCE_BRANCH="ubuntu" + # case "${SYSTEM_VERSION_ID_MAJOR}" in + # "v10") + # SOURCE_BRANCH_CODENAME="focal" + # ;; + # "v11") + # SOURCE_BRANCH_CODENAME="noble" + # ;; + # *) + # SOURCE_BRANCH_CODENAME="noble" + # ;; + # esac + # ;; + "${SYSTEM_OPENKYLIN}") + SOURCE_BRANCH="debian" + SOURCE_BRANCH_CODENAME="${debian_codename_latest}" + ;; + *) + # 其余 Debian 系衍生操作系统 + SOURCE_BRANCH="debian" + SOURCE_BRANCH_CODENAME="bookworm" + ;; + esac + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_FEDORA}") + SOURCE_BRANCH="fedora" + ;; + "${SYSTEM_RHEL}") + SOURCE_BRANCH="rhel" + ;; + *) + SOURCE_BRANCH="centos" + ;; + esac + if [[ "${DEVICE_ARCH_RAW}" == "s390x" ]]; then + output_error "$(msg "error.unsupportS390x")" + fi + ;; + esac + fi + ## 定义软件源更新文字 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + SYNC_MIRROR_TEXT="$(msg "source.sync.text1")" + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + SYNC_MIRROR_TEXT="$(msg "source.sync.text2")" + ;; + esac + ## 判断是否可以使用高级交互式选择器 + CAN_USE_ADVANCED_INTERACTIVE_SELECTION="false" + if command_exists tput; then + CAN_USE_ADVANCED_INTERACTIVE_SELECTION="true" + fi +} + +function choose_display_language() { :; } + +function choose_mirrors() { :; } + +function choose_protocol() { :; } + +## 关闭防火墙和SELinux +function close_firewall_service() { + if ! command_exists systemctl; then + return + fi + if [[ "$(systemctl is-active firewalld)" == "active" ]]; then + if [[ -z "${CLOSE_FIREWALL}" ]]; then + local ask_text="$(msg "interaction.firewall.close")?" + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}${ask_text}${PLAIN}" + if [[ "${_SELECT_RESULT}" == "true" ]]; then + CLOSE_FIREWALL="true" + fi + else + local CHOICE="$(echo -e "\n${BOLD}└─ ${ask_text} [Y/n] ${PLAIN}")" + read -rp "${CHOICE}" INPUT + [[ -z "${INPUT}" ]] && INPUT=Y + case "${INPUT}" in + [Yy] | [Yy][Ee][Ss]) + CLOSE_FIREWALL="true" + ;; + [Nn] | [Nn][Oo]) ;; + *) + input_error "$(msg "error.defaultBehavior.noClose")" + ;; + esac + fi + fi + if [[ "${CLOSE_FIREWALL}" == "true" ]]; then + local SelinuxConfig=/etc/selinux/config + systemctl disable --now firewalld >/dev/null 2>&1 + [ -s "${SelinuxConfig}" ] && sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" $SelinuxConfig && setenforce 0 >/dev/null 2>&1 + fi + fi +} + +## 安装环境包 +function install_dependency_packages() { + local commands package_manager + ## 删除原有源 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + sed -i '/docker-ce/d' $File_AptSourceList + rm -rf $File_DockerSourceList + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + rm -rf $Dir_YumRepos/*docker*.repo + ;; + esac + ## 更新软件源 + commands=() + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + package_manager="apt-get" + commands+=("${package_manager} update") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + package_manager="$(get_package_manager)" + commands+=("${package_manager} makecache") + ;; + esac + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + echo '' + animate_exec "${exec_cmd}" "${SYNC_MIRROR_TEXT}" + else + echo '' + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + fi + if [ $? -ne 0 ]; then + output_error "$(msg "error.sync" "${SYNC_MIRROR_TEXT}" "${BLUE}${package_manager}${PLAIN}")" + fi + + commands=() + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + commands+=("${package_manager} install -y ca-certificates curl") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 7) + commands+=("${package_manager} install -y yum-utils device-mapper-persistent-data lvm2") + ;; + *) + if [[ "${package_manager}" == "dnf" ]]; then + commands+=("${package_manager} install -y dnf-plugins-core") + else + commands+=("${package_manager} install -y yum-utils device-mapper-persistent-data lvm2") + fi + ;; + esac + ;; + esac + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + echo '' + animate_exec "${exec_cmd}" "$(msg "work.installDependents")" + else + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + fi +} + +## 配置 Docker CE 源 +function configure_docker_ce_mirror() { + local -a commands=() + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + ## 处理 GPG 密钥 + local file_keyring="/etc/apt/keyrings/docker.asc" + apt-key del 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 >/dev/null 2>&1 # 删除旧的密钥 + [ -f "${file_keyring}" ] && rm -rf $file_keyring + install -m 0755 -d /etc/apt/keyrings + curl -fsSL "${WEB_PROTOCOL}://${SOURCE}/linux/${SOURCE_BRANCH}/gpg" -o $file_keyring >/dev/null + if [ $? -ne 0 ]; then + output_error "$(msg "error.downloadGPG")" + fi + chmod a+r $file_keyring + ## 添加源 + [ -d "${Dir_AptAdditionalSources}" ] || mkdir -p $Dir_AptAdditionalSources + local apt_source_content="deb [arch=$(dpkg --print-architecture) signed-by=${file_keyring}] ${WEB_PROTOCOL}://${SOURCE}/linux/${SOURCE_BRANCH} ${DEBIAN_CODENAME:-${SOURCE_BRANCH_CODENAME:-${SYSTEM_VERSION_CODENAME}}} stable" + echo "${apt_source_content}" | tee $File_DockerSourceList >/dev/null 2>&1 + commands+=("apt-get update") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + local repo_file_url="${WEB_PROTOCOL}://${SOURCE}/linux/${SOURCE_BRANCH}/docker-ce.repo" + local package_manager="$(get_package_manager)" + case "${SYSTEM_VERSION_ID_MAJOR}" in + 7) + yum-config-manager -y --add-repo "${repo_file_url}" + ;; + *) + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_FEDORA}" ]]; then + dnf-3 config-manager -y --add-repo "${repo_file_url}" + else + if [[ "${package_manager}" == "dnf" ]]; then + dnf config-manager -y --add-repo "${repo_file_url}" + else + yum-config-manager -y --add-repo "${repo_file_url}" + fi + fi + ;; + esac + sed -e "s|https://download.docker.com|${WEB_PROTOCOL}://${SOURCE}|g" \ + -e "s|http[s]\?://.*/linux/${SOURCE_BRANCH}/|${WEB_PROTOCOL}://${SOURCE}/linux/${SOURCE_BRANCH}/|g" \ + -i \ + $File_DockerRepo + ## 处理版本号 + if [[ "${SOURCE_BRANCH_VERSION}" ]]; then + # 指定版本 + sed -e "s|\$releasever|${SOURCE_BRANCH_VERSION}|g" \ + -i \ + $File_DockerRepo + commands+=("${package_manager} makecache") + elif [[ "${SYSTEM_JUDGMENT}" != "${SYSTEM_FEDORA}" ]]; then + # 兼容处理 + local target_version + case "${SYSTEM_VERSION_ID_MAJOR}" in + 7 | 8 | 9 | 10) + target_version="${SYSTEM_VERSION_ID_MAJOR}" + ;; + *) + target_version="8" # 注:部分系统使用9版本分支会有兼容性问题 + ## 适配国产操作系统 + # OpenCloudOS、Anolis OS 的 23 版本 + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_OPENCLOUDOS}" || "${SYSTEM_JUDGMENT}" == "${SYSTEM_ANOLISOS}" ]]; then + if [[ "${SYSTEM_VERSION_ID_MAJOR}" == 23 ]]; then + target_version="9" + fi + fi + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_OPENEULER}" ]]; then + if [ -s "${File_HuaweiCloudEulerOSRelease}" ]; then + # Huawei Cloud EulerOS + case "${SYSTEM_VERSION_ID_MAJOR}" in + 1) + target_version="8" # openEuler 20 + ;; + 2) + target_version="9" # openEuler 22 + ;; + esac + else + # openEuler + if [[ "${SYSTEM_VERSION_ID_MAJOR}" -ge 22 ]]; then + target_version="9" + fi + fi + fi + # TencentOS Server + if [ -s "${File_TencentOSServerRelease}" ]; then + case "${SYSTEM_VERSION_ID_MAJOR}" in + 4) + target_version="9" + ;; + 3) + target_version="8" + ;; + 2) + target_version="7" + ;; + esac + fi + # Alibaba Cloud Linux + if [ -s "${File_AnolisOSRelease}" ] && [ -s "${File_AlibabaCloudLinuxRelease}" ]; then + case "${SYSTEM_VERSION_ID_MAJOR}" in + 3) + target_version="8" + ;; + 2) + target_version="7" + ;; + esac + fi + if [[ "${SYSTEM_JUDGMENT}" == "${SYSTEM_KYLIN_SERVER}" ]]; then + case "${SYSTEM_VERSION_ID_MAJOR}" in + "V10") + target_version="8" + ;; + "V11") + target_version="10" + ;; + *) + target_version="10" + ;; + esac + fi + ;; + esac + sed -e "s|\$releasever|${target_version}|g" \ + -i \ + $File_DockerRepo + commands+=("${package_manager} makecache") + fi + ;; + esac + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + echo '' + animate_exec "${exec_cmd}" "${SYNC_MIRROR_TEXT}" + else + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + fi +} + +## 安装 Docker Engine +function install_docker_engine() { + ## 导出可安装的版本列表 + function export_version_list() { + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + apt-cache madison docker-ce | awk '{print $3}' | grep -Eo "[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}" >$File_DockerCEVersionTmp + apt-cache madison docker-ce-cli | awk '{print $3}' | grep -Eo "[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}" >$File_DockerCECliVersionTmp + grep -wf $File_DockerCEVersionTmp $File_DockerCECliVersionTmp >$File_DockerVersionTmp + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + local package_manager="$(get_package_manager)" + $package_manager list docker-ce --showduplicates | sort -r | awk '{print $2}' | grep -Eo "[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}" >$File_DockerCEVersionTmp + $package_manager list docker-ce-cli --showduplicates | sort -r | awk '{print $2}' | grep -Eo "[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}" >$File_DockerCECliVersionTmp + grep -wf $File_DockerCEVersionTmp $File_DockerCECliVersionTmp >$File_DockerVersionTmp + ;; + esac + rm -rf $File_DockerCEVersionTmp $File_DockerCECliVersionTmp + } + + ## 卸载 Docker Engine 原有版本软件包 + function uninstall_original_version() { + if command_exists docker; then + # 先停止并禁用 Docker 服务 + systemctl disable --now docker >/dev/null 2>&1 + sleep 2s + fi + # 确定需要卸载的软件包 + local package_list + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + package_list='docker* podman podman-docker containerd runc' + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + package_list='docker* podman podman-docker runc' + ;; + esac + # 卸载软件包并清理残留 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + apt-get remove -y $package_list >/dev/null 2>&1 + apt-get autoremove -y >/dev/null 2>&1 + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + local package_manager="$(get_package_manager)" + $package_manager remove -y $package_list >/dev/null 2>&1 + $package_manager autoremove -y >/dev/null 2>&1 + ;; + esac + } + + ## 安装 + function install_main() { + local target_docker_version + local pkgs="" + local -a commands=() + if [[ "${INSTALL_LATESTED_DOCKER}" == "true" ]]; then + pkgs="docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin" + else + export_version_list + if [ ! -s "${File_DockerVersionTmp}" ]; then + rm -rf $File_DockerVersionTmp + output_error "$(msg "error.queryVersionFailed")" + fi + if [[ "${DESIGNATED_DOCKER_VERSION}" ]]; then + cat $File_DockerVersionTmp | grep -Eq "^${DESIGNATED_DOCKER_VERSION}$" + if [ $? -ne 0 ]; then + rm -rf $File_DockerVersionTmp + output_error "$(msg "error.designatedVersion")" + fi + target_docker_version="${DESIGNATED_DOCKER_VERSION}" + else + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + local -a version_list=( + $(cat $File_DockerVersionTmp | sort -t '.' -k1,1nr -k2,2nr -k3,3nr | tr '\n' ' ' | sed 's/ $//') + ) + local mirror_list_name="version_list" + interactive_select_list "${mirror_list_name}" "\n ${BOLD}$(msg "interaction.install.selectVersion")${PLAIN}\n" + target_docker_version="${_SELECT_RESULT}" + echo -e "\n${GREEN}➜${PLAIN} ${BOLD}$(msg "interaction.install.selectedVersion")${target_docker_version}${PLAIN}\n" + else + echo -e "\n${GREEN} --------- $(msg "interaction.install.selectedTitle" "28.3.0") ---------- ${PLAIN}\n" + cat $File_DockerVersionTmp + while true; do + local CHOICE="$(echo -e "\n${BOLD}└─ $(msg "interaction.install.inputVersion")${PLAIN}\n")" + read -rp "${CHOICE}" target_docker_version + echo '' + cat $File_DockerVersionTmp | grep -Eqw "${target_docker_version}" + if [ $? -eq 0 ]; then + echo "${target_docker_version}" | grep -Eqw '[0-9][0-9].[0-9]{1,2}.[0-9]{1,2}' + if [ $? -eq 0 ]; then + break + else + echo -e "$ERROR $(msg "error.invalidVersion")" + fi + else + echo -e "$ERROR $(msg "error.reEnter")" + fi + done + fi + fi + rm -rf $File_DockerVersionTmp + local major_version="$(echo ${target_docker_version} | cut -d'.' -f1)" + local minor_version="$(echo ${target_docker_version} | cut -d'.' -f2)" + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + if [[ $major_version -gt 18 ]] || [[ $major_version -eq 18 && $minor_version -ge 9 ]]; then + local tmp_version="$(apt-cache madison docker-ce-cli | grep "${target_docker_version}" | head -1 | awk '{print $3}' | awk -F "${target_docker_version}" '{print$1}')" + pkgs="docker-ce=${tmp_version}${target_docker_version}* docker-ce-cli=${tmp_version}${target_docker_version}*" + else + pkgs="docker-ce=${target_docker_version}* docker-ce-cli=${target_docker_version}*" + fi + ;; + + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + pkgs="docker-ce-${target_docker_version}" + if [[ $major_version -gt 18 ]] || [[ $major_version -eq 18 && $minor_version -ge 9 ]]; then + pkgs="${pkgs} docker-ce-cli-${target_docker_version}" + fi + ;; + esac + pkgs="${pkgs} containerd.io" + if [[ $major_version -gt 20 ]] || [[ $major_version -eq 20 && $minor_version -ge 10 ]]; then + pkgs="${pkgs} docker-compose-plugin" + fi + if [[ $major_version -ge 23 ]]; then + pkgs="${pkgs} docker-buildx-plugin" + fi + fi + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + commands+=("apt-get install -y ${pkgs}") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + commands+=("$(get_package_manager) install -y ${pkgs}") + ;; + esac + echo '' + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + animate_exec "${exec_cmd}" "$(msg "work.installDockerEngine")" + else + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + fi + [ $? -ne 0 ] && output_error "$(msg "error.installDockerEngineFailed")" + } + + ## 判断是否手动选择安装版本 + if [[ -z "${INSTALL_LATESTED_DOCKER}" ]]; then + local ask_text="$(msg "interaction.install.latestVersion")?" + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}${ask_text}${PLAIN}" + if [[ "${_SELECT_RESULT}" == "true" ]]; then + INSTALL_LATESTED_DOCKER="true" + else + INSTALL_LATESTED_DOCKER="false" + fi + else + local CHOICE_A="$(echo -e "\n${BOLD}└─ ${ask_text} [Y/n] ${PLAIN}")" + read -rp "${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" + ;; + *) + INSTALL_LATESTED_DOCKER="true" + input_error "$(msg "error.defaultBehavior.installLatest")" + ;; + esac + fi + fi + + ## 判定是否已安装 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + dpkg -l | grep docker-ce-cli -q + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + rpm -qa | grep docker-ce-cli -q + ;; + esac + if [ $? -eq 0 ]; then + export_version_list + local current_docker_version="$(docker -v | grep -Eo "[0-9][0-9]\.[0-9]{1,2}\.[0-9]{1,2}")" + local latest_docker_version="$(cat $File_DockerVersionTmp | head -n 1)" + rm -rf $File_DockerVersionTmp + if [[ "${current_docker_version}" == "${latest_docker_version}" ]] && [[ "${INSTALL_LATESTED_DOCKER}" == "true" ]]; then + echo -e "\n$TIP $(msg "tip.skipInstallDockerEngine")" + else + uninstall_original_version + install_main + fi + else + uninstall_original_version + install_main + fi +} + +## 修改 Docker Registry 镜像仓库源 +function change_docker_registry_mirror() { + ## 使用官方 Docker Hub + if [[ "${REGISTRY_SOURCEL}" == "registry.hub.docker.com" ]]; then + if [ -s "${File_DockerConfig}" ]; then + ## 安装 jq + local package_manager="$(get_package_manager)" + $package_manager install -y jq + if command_exists jq; then + jq 'del(.["registry-mirrors"])' $File_DockerConfig >$File_DockerConfig.tmp && mv $File_DockerConfig.tmp $File_DockerConfig + # 重启服务 + systemctl daemon-reload + if [[ "$(systemctl is-active docker 2>/dev/null)" == "active" ]]; then + systemctl restart docker + fi + else + echo -e "\n${WARN} $(msg "warn.needManuallyDeleteConfig" "${File_DockerConfig}" "${BLUE}registry-mirrors${PLAIN}" "${BLUE}systemctl daemon-reload && systemctl restart docker${PLAIN}")\n" + fi + fi + return + fi + ## 备份原有配置文件 + if [ -d "${Dir_Docker}" ] && [ -e "${File_DockerConfig}" ]; then + if [ -e "${File_DockerConfigBackup}" ]; then + if [[ "${IGNORE_BACKUP_TIPS}" == "false" ]]; then + local ask_text="$(msg "interaction.backup.skipOverwrite")?" + if [[ "${CAN_USE_ADVANCED_INTERACTIVE_SELECTION}" == "true" ]]; then + echo '' + interactive_select_boolean "${BOLD}${ask_text}${PLAIN}" + if [[ "${_SELECT_RESULT}" == "false" ]]; then + echo '' + cp -rvf $File_DockerConfig $File_DockerConfigBackup 2>&1 + fi + else + local CHOICE_BACKUP="$(echo -e "\n${BOLD}└─ ${ask_text} [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 $File_DockerConfig $File_DockerConfigBackup 2>&1 + ;; + *) + input_error "$(msg "error.defaultBehavior.noOverwrite")" + ;; + esac + fi + fi + else + echo '' + cp -rvf $File_DockerConfig $File_DockerConfigBackup 2>&1 + echo -e "\n$COMPLETE $(msg "info.backuped.dockerConfig")" + fi + sleep 2s + else + mkdir -p $Dir_Docker >/dev/null 2>&1 + touch $File_DockerConfig + fi + + echo -e '{\n "registry-mirrors": '"$(handleRegistryMirrorsValue ${SOURCE_REGISTRY})"'\n}' >$File_DockerConfig + ## 重启服务 + systemctl daemon-reload + if [[ "$(systemctl is-active docker 2>/dev/null)" == "active" ]]; then + systemctl restart docker + fi +} + +## 仅修改 Docker Registry 镜像仓库源模式 +function only_change_docker_registry_mirror() { + ## 判定是否已安装 + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + dpkg -l | grep docker-ce-cli -q + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + rpm -qa | grep docker-ce-cli -q + ;; + esac + if [ $? -ne 0 ]; then + ## 仅镜像仓库换源模式 + if [[ "${ONLY_REGISTRY}" == "true" ]]; then + output_error "$(msg "result.registry.dockerEngineNotExsit" "${BLUE}--only-registry${PLAIN}")" + fi + fi + + [ -d "${Dir_Docker}" ] || mkdir -p "${Dir_Docker}" + if [ -s "${File_DockerConfig}" ]; then + ## 安装 jq + if ! command_exists jq; then + ## 更新软件源 + local package_manager + local -a commands=() + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + package_manager="apt-get" + commands+=("${package_manager} update") + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + package_manager="$(get_package_manager)" + commands+=("${package_manager} makecache") + ;; + esac + if [[ "${PURE_MODE}" == "true" ]]; then + local exec_cmd="" + for cmd in "${commands[@]}"; do + if [[ -z "${exec_cmd}" ]]; then + exec_cmd="${cmd}" + else + exec_cmd="${exec_cmd} ; ${cmd}" + fi + done + echo '' + animate_exec "${exec_cmd}" "${SYNC_MIRROR_TEXT}" + else + echo '' + for cmd in "${commands[@]}"; do + eval "${cmd}" + done + fi + if [ $? -ne 0 ]; then + output_error "$(msg "error.sync" "${SYNC_MIRROR_TEXT}" "${BLUE}${package_manager}${PLAIN}")" + fi + $package_manager install -y jq + if ! command_exists jq; then + output_error "$(msg "error.installPackageFailed" "${BLUE}jq${PLAIN}")" + fi + fi + [ -s "${File_DockerConfig}" ] || echo "{}" >$File_DockerConfig + jq '.["registry-mirrors"] = '"$(handleRegistryMirrorsValue ${SOURCE_REGISTRY})"'' $File_DockerConfig >$File_DockerConfig.tmp && mv $File_DockerConfig.tmp $File_DockerConfig + else + echo -e '{\n "registry-mirrors": '"$(handleRegistryMirrorsValue ${SOURCE_REGISTRY})"'\n}' >$File_DockerConfig + fi + ## 重启服务 + systemctl daemon-reload + if [[ "$(systemctl is-active docker 2>/dev/null)" == "active" ]]; then + systemctl restart docker + fi + + echo -e "\n${BLUE}\$${PLAIN} docker info --format '{{json .RegistryConfig.Mirrors}}'" + echo -e "\033[2m>${PLAIN} $(docker info --format '{{json .RegistryConfig.Mirrors}}')" + if [[ "${PURE_MODE}" != "true" ]]; then + echo -e "\n$COMPLETE $(msg "result.registry.success")" + fi +} + +function handleRegistryMirrorsValue() { + local content="$1" + local result="" + content="$(echo "${content}" | sed 's| ||g')" + local -a items=(${content//,/ }) + for item in "${items[@]}"; do + [[ -z "${item}" ]] && continue + if [[ -z "${result}" ]]; then + result='"https://'"${item}"'"' + else + result="${result},\"https://${item}\"" + fi + done + if [[ "${result}" ]]; then + echo "[${result}]" + else + echo "" + fi +} + +## 查看版本并验证安装结果 +function check_installed_result() { + if command_exists docker; then + systemctl enable --now docker >/dev/null 2>&1 + echo -en "\n$COMPLETE " + docker -v + if [ $? -eq 0 ]; then + echo -e " $(docker compose version 2>&1)" + # echo -e "\n$COMPLETE 安装完成" + else + echo -e "\n$FAIL $(msg "result.install.failed")" + local source_file package_manager + case "${SYSTEM_FACTIONS}" in + "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") + source_file="${File_DockerSourceList}" + package_manager="apt-get" + ;; + "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + source_file="${File_DockerRepo}" + package_manager="$(get_package_manager)" + ;; + esac + echo -e "\n$(msg "result.install.checkSourceFile" "cat ${source_file}")" + echo -e "$(msg "result.install.manuallyExecCmd" "${package_manager} install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin")\n" + exit 1 + fi + if [[ "$(systemctl is-active docker 2>/dev/null)" != "active" ]]; then + sleep 2 + systemctl disable --now docker >/dev/null 2>&1 + sleep 2 + systemctl enable --now docker >/dev/null 2>&1 + sleep 2 + if [[ "$(systemctl is-active docker)" != "active" ]]; then + echo -e "\n$WARN $(msg "result.install.notRunning")" + local start_cmd + if command_exists systemctl; then + start_cmd="systemctl start docker" + else + start_cmd="service docker start" + fi + echo -e "\n$TIP $(msg "result.install.manuallyRun" "${BLUE}${start_cmd}${PLAIN}")" + fi + fi + else + echo -e "\n$FAIL $(msg "result.install.failed")" + fi +} + +## 选择系统包管理器 +function get_package_manager() { + local command="yum" + case "${SYSTEM_JUDGMENT}" in + "${SYSTEM_RHEL}" | "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ROCKY}" | "${SYSTEM_ALMALINUX}" | "${SYSTEM_ORACLE}") + case "${SYSTEM_VERSION_ID_MAJOR}" in + 9 | 10) + command="dnf" + ;; + esac + ;; + "${SYSTEM_FEDORA}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}" | "${SYSTEM_TENCENTOS}" | "${SYSTEM_KYLIN_SERVER}") + command="dnf" + ;; + esac + echo "${command}" +} + +function interactive_select_list() { + _SELECT_RESULT="" + eval "local -a __values=(\"\${${1}[@]}\")" + local -a __labels=() + local message="${2}" + local selected=0 + local start=0 + local page_size=$(($(tput lines 2>/dev/null) - 3)) + if [[ "${3}" ]]; then + eval "__labels=(\"\${${3}[@]}\")" + fi + function clear_menu() { + tput rc 2>/dev/null + for ((i = 0; i < ${#__values[@]} + 1; i++)); do + echo -e "\r\033[K" + done + tput rc 2>/dev/null + } + function cleanup() { + clear_menu + tput rc 2>/dev/null + tput cnorm 2>/dev/null + tput rmcup 2>/dev/null + echo -e "\n\033[1;44m $(msg "interaction.common.tip") \033[0m \033[31m$(msg "interaction.common.operationCanceled")\033[0m\n" + exit 130 + } + function draw_menu() { + tput clear 2>/dev/null + tput cup 0 0 2>/dev/null + echo -e "${message}" + local end=$((start + page_size - 1)) + local label + if [ $end -ge ${#__values[@]} ]; then + end=${#__values[@]}-1 + fi + for ((i = start; i <= end; i++)); do + if [[ "${__labels[$i]}" ]]; then + label="${__labels[$i]}" + else + label="${__values[$i]}" + fi + if [ "$i" -eq "${selected}" ]; then + echo -e "\e[34;4m➤ ${label}\e[0m" + else + echo -e " ${label}" + fi + done + } + function read_key() { + IFS= read -rsn1 key + if [[ $key == $'\x1b' ]]; then + IFS= read -rsn2 key + key="$key" + fi + echo "$key" + } + tput smcup 2>/dev/null + tput sc 2>/dev/null + tput civis 2>/dev/null + trap "cleanup" INT TERM + draw_menu + while true; do + key=$(read_key) + case "$key" in + "[A" | "w" | "W") + if [ "${selected}" -gt 0 ]; then + selected=$((selected - 1)) + if [ "${selected}" -lt "$start" ]; then + start=$((start - 1)) + fi + fi + ;; + "[B" | "s" | "S") + if [ "${selected}" -lt $((${#__values[@]} - 1)) ]; then + selected=$((selected + 1)) + if [ "${selected}" -ge $((start + page_size)) ]; then + start=$((start + 1)) + fi + fi + ;; + "") + tput rmcup + break + ;; + *) ;; + esac + draw_menu + done + tput cnorm 2>/dev/null + tput rmcup 2>/dev/null + _SELECT_RESULT="${__values[${selected}]}" + if [ "${__labels[${selected}]}" ]; then + _SELECT_RESULT="${_SELECT_RESULT}@@${__labels[${selected}]}" + fi +} + +function interactive_select_boolean() { + _SELECT_RESULT="" + local selected=0 + local message="$1" + local positive_title="${2:-"$(msg "interaction.common.yes")"}" + local negative_title="${3:-"$(msg "interaction.common.no")"}" + local menu_height=3 + local original_line + function store_position() { + original_line=$(tput lines 2>/dev/null) + } + function clear_menu() { + for ((i = 0; i < $menu_height; i++)); do + tput cuu1 2>/dev/null + tput el 2>/dev/null + done + } + function cleanup() { + clear_menu + tput cnorm 2>/dev/null + echo -e "\n\033[1;44m $(msg "interaction.common.tip") \033[0m \033[31m$(msg "interaction.common.operationCanceled")\033[0m\n" + exit 130 + } + function draw_menu() { + echo -e "╭─ ${message}" + echo -e "│" + if [ "${selected}" -eq 0 ]; then + echo -e "╰─ \033[34m●\033[0m ${positive_title}\033[2m / ○ ${negative_title}\033[0m" + else + echo -e "╰─ \033[2m○ ${positive_title} / \033[0m\033[34m●\033[0m ${negative_title}" + fi + } + function read_key() { + IFS= read -rsn1 key + if [[ $key == $'\x1b' ]]; then + IFS= read -rsn2 key + key="$key" + fi + echo "$key" + } + tput civis 2>/dev/null + store_position + trap "cleanup" INT TERM + draw_menu + while true; do + key=$(read_key) + case "$key" in + "[D" | "a" | "A") + if [ "${selected}" -gt 0 ]; then + selected=$((selected - 1)) + clear_menu + draw_menu + fi + ;; + "[C" | "d" | "D") + if [ "${selected}" -lt 1 ]; then + selected=$((selected + 1)) + clear_menu + draw_menu + fi + ;; + "") + clear_menu + break + ;; + *) ;; + esac + done + echo -e "╭─ ${message}" + echo -e "│" + if [ "${selected}" -eq 0 ]; then + echo -e "╰─ \033[32m●\033[0m \033[1m${positive_title}\033[0m\033[2m / ○ ${negative_title}\033[0m" + _SELECT_RESULT="true" + else + echo -e "╰─ \033[2m○ ${positive_title} / \033[0m\033[32m●\033[0m \033[1m${negative_title}\033[0m" + _SELECT_RESULT="false" + fi + tput cnorm 2>/dev/null +} + +function animate_exec() { + local cmd="$1" + local title="$2" + local max_lines=${3:-5} + local spinner_style="${4:-dots}" + local refresh_rate="${5:-0.1}" + local scroll_mode="${6:-1}" + if [[ "${scroll_mode}" == "0" ]]; then + echo -e "◉ ${title} \n" + eval "${cmd}" + return $? + fi + local -A spinners=([dots]="⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏" [circle]="◐ ◓ ◑ ◒" [classic]="-\\ |/") + local -A recommended_rates=([dots]="0.08" [circle]="0.12" [classic]="0.12") + [[ -z "${spinners[$spinner_style]}" ]] && spinner_style="dots" + [[ "${refresh_rate}" == "0.1" ]] && refresh_rate="${recommended_rates[$spinner_style]}" + local term_width=$(tput cols 2>/dev/null || echo 80) + local display_width=$((term_width - 2)) + function simple_truncate() { + local line="$1" + local truncate_marker="..." + local max_length=$((display_width - 3)) + if [[ "${line}" =~ ^[[:ascii:]]*$ && ${#line} -le $display_width ]]; then + echo "${line}" + return + fi + local non_ascii_count=$(echo "${line}" | sed "s|[0-9a-zA-Z -~]||g; s| ||g" | wc -m) + local total_length=${#line} + local display_length=$((total_length + non_ascii_count)) + local quote_count=0 + [[ $(echo "${line}" | grep -c "“") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "“")")) + [[ $(echo "${line}" | grep -c "”") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "”")")) + [[ $(echo "${line}" | grep -c "‘") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "‘")")) + [[ $(echo "${line}" | grep -c "’") -gt 0 ]] && ((quote_count += "$(echo "${line}" | grep -c "’")")) + display_length=$((display_length - quote_count)) + if [[ $display_length -le $display_width ]]; then + echo "$line" + return + fi + local result="" + local current_width=0 + local i=0 + while [ $i -lt ${#line} ]; do + local char="${line:$i:1}" + local char_width=1 + if ! [[ "$char" =~ [0-9a-zA-Z\.\=\:\_\(\)\'\"\-\/\!\·] ]]; then + if [[ "$char" != "“" && "$char" != "”" && "$char" != "‘" && "$char" != "’" ]]; then + char_width=2 + fi + fi + if [[ $((current_width + char_width)) -gt $max_length ]]; then + echo "${result}${truncate_marker}" + return + fi + result+="${char}" + current_width=$((current_width + char_width)) + ((i++)) + done + echo "${line}" + } + function cleanup() { + [ -f "${temp_file}" ] && rm -f "${temp_file}" + tput cnorm 2>/dev/null + echo -e "\n\033[1;44m $(msg "interaction.common.tip") \033[0m \033[31m$(msg "interaction.common.operationCanceled")\033[0m\n" + exit 130 + } + function make_temp_file() { + local -a temp_dirs=("." "/tmp") + local tmp_file="" + for dir in "${temp_dirs[@]}"; do + [[ ! -d "${dir}" || ! -w "${dir}" ]] && continue + tmp_file="${dir}/animate_exec_$$_$(date +%s)" + touch "${tmp_file}" 2>/dev/null || continue + if [[ -f "${tmp_file}" && -w "${tmp_file}" ]]; then + echo "${tmp_file}" + return + fi + done + echo "${tmp_file}" + } + function update_display() { + local current_size=$(wc -c <"${temp_file}" 2>/dev/null || echo 0) + if [[ $current_size -le $last_size ]]; then + return 1 + fi + local -a lines=() + mapfile -t -n "${max_lines}" lines < <(tail -n "$max_lines" "${temp_file}") + local -a processed_lines=() + for ((i = 0; i < ${#lines[@]}; i++)); do + processed_lines[i]=$(simple_truncate "${lines[i]}") + done + tput cud1 2>/dev/null + echo -ne "\r\033[K" + tput cud1 2>/dev/null + for ((i = 0; i < $max_lines; i++)); do + echo -ne "\r\033[K" + [[ $i -lt ${#processed_lines[@]} ]] && echo -ne "\033[2m${processed_lines[$i]}\033[0m" + [[ $i -lt $((max_lines - 1)) ]] && tput cud1 2>/dev/null + done + for ((i = 0; i < $max_lines + 1; i++)); do + tput cuu1 2>/dev/null + done + last_size=$current_size + return 0 + } + local spinner_frames=(${spinners[$spinner_style]}) + local temp_file="$(make_temp_file)" + trap "cleanup" INT TERM + tput civis 2>/dev/null + echo '' + echo '' + for ((i = 0; i < $max_lines; i++)); do + echo '' + done + eval "${cmd}" >"${temp_file}" 2>&1 & + local cmd_pid=$! + local last_size=0 + local spin_idx=0 + tput cuu $((max_lines + 2)) 2>/dev/null + sleep 0.05 + echo -ne "\r\033[K◉ ${title} [\033[1m\033[34m${spinner_frames[$spin_idx]}\033[0m]" + spin_idx=$(((spin_idx + 1) % ${#spinner_frames[@]})) + update_display + local update_count=0 + local adaptive_rate=$refresh_rate + while kill -0 $cmd_pid 2>/dev/null; do + echo -ne "\r\033[K◉ ${title} [\033[1m\033[34m${spinner_frames[$spin_idx]}\033[0m]" + spin_idx=$(((spin_idx + 1) % ${#spinner_frames[@]})) + if update_display; then + update_count=$((update_count + 1)) + if [[ $update_count -gt 5 ]]; then + adaptive_rate=$(awk "BEGIN {print $adaptive_rate * 1.5; exit}") + [[ $(awk "BEGIN {print ($adaptive_rate > 0.5); exit}") -eq 1 ]] && adaptive_rate=0.5 + update_count=0 + fi + else + update_count=0 + adaptive_rate=$refresh_rate + fi + sleep $adaptive_rate + done + wait $cmd_pid + local exit_status=$? + update_display + if [ $exit_status -eq 0 ]; then + echo -ne "\r\033[K◉ ${title} [\033[1m\033[32m✓\033[0m]\n" + else + echo -ne "\r\033[K◉ ${title} [\033[1m\033[31m✗\033[0m]\n" + fi + echo -ne "\r\033[K\n" + local actual_lines=$(wc -l <"${temp_file}" 2>/dev/null || echo 0) + [[ $actual_lines -gt $max_lines ]] && actual_lines=$max_lines + if [[ $actual_lines -gt 0 ]]; then + local -a final_lines=() + mapfile -t -n "$actual_lines" final_lines < <(tail -n "$actual_lines" "${temp_file}") + + for ((i = 0; i < actual_lines; i++)); do + local line=$(simple_truncate "${final_lines[$i]}") + echo -ne "\r\033[K\033[2m${line}\033[0m\n" + done + fi + tput cnorm 2>/dev/null + rm -f "${temp_file}" + return $exit_status +} + +############################################################################## + +MESSAGE_LANG_DEFAULT='en' +MESSAGE_LANG_KEYS=( + "en" +) +declare -A MESSAGE_LANG_DISPLAY=( + ['en']='English' +) +declare -A MESSAGE_CONTENTS + +function msg() { + local key="$1" + shift + local text="${MESSAGE_CONTENTS[${key}]}" + if [[ -z "${text}" ]]; then + echo "${key}" + return + fi + while [[ $# -gt 0 ]]; do + if [[ "${text}" == *"{}"* ]]; then + text="${text/\{\}/$1}" + else + break + fi + shift + done + echo "${text}" +} + +function init_msg_pack() { + function load_pack() { + local func_name="${1}" + if declare -f "${func_name}" >/dev/null 2>&1; then + eval "${func_name}" + fi + } + local current_lang="${1:-${MESSAGE_LANG_DEFAULT}}" + current_lang="$(echo "${current_lang}" | sed 's/^-*//')" + current_lang="${current_lang,,}" + if [[ "${MESSAGE_LANG_DISPLAY[${current_lang}]}" ]]; then + current_lang="${current_lang//-/_}" + load_pack "msg_pack_${current_lang}" + fi +} + +function msg_pack_en() { + MESSAGE_CONTENTS=( + ['start.welcome']='Docker installation & mirror switcher' + ['start.runtimeEnv']='Runtime Env' + ['start.dateTime']='System Time' + ['end.moreInfo']='Script execution completed, visit our website for more tutorials' + ['end.sponsorAds']='[Sponsor Ads]' + ['error.cmd.options.needConfirm']='Please confirm and re-enter' + ['error.cmd.options.needSpecify']='Please specify {} after this option' + ['error.cmd.options.invalid']='Command option {} is invalid, {}!' + ['error.cmd.options.validAddress']='a valid address' + ['error.cmd.options.sourceAddress']='mirror address' + ['error.cmd.options.registryAddress']='registry mirror address' + ['error.cmd.options.sourceRepository']='mirror repository' + ['error.cmd.options.validVersion']='a valid version number' + ['error.cmd.options.ceRepositoryVersion']='Docker CE mirror repository version' + ['error.cmd.options.version']='version number' + ['error.cmd.options.codename']='version codename' + ['error.cmd.options.boolean']=' true or false ' + ['error.cmd.options.protocol']=' http or https ' + ['error.cmd.options.needProtocol']=' Web protocol(http/https)' + ['error.cmd.options.validLangKey']='A valid language ID ' + ['error.cmd.options.langKey']='language ID ' + ['error.unsupportSystem1']='Unsupported operating system ({})' + ['error.unsupportSystem2']='Unsupported operating system ({}), please install manually with commands:' + ['error.unknownSystem']='Unknown system' + ['error.unsupportX86_32']='Docker Engine does not support installation on x86_32 architecture!' + ['error.unknownArch']='Unknown system architecture: {}' + ['error.unsupportS390x']='Please refer to RHEL distribution announcement for s390x support' + ['error.input']='Input error, {}!' + ['error.needRoot']='Insufficient privileges, please run this script as root. Switch command: {}' + ['error.sync']='{} failed. Please fix system software sources (package repositories) so the {} package manager is available!' + ['error.downloadGPG']='GPG key download failed, please check network or switch Docker CE mirror and retry!' + ['error.queryVersionFailed']='Failed to query Docker Engine version list!' + ['error.designatedVersion']='Specified Docker Engine version does not exist or is not supported for installation!' + ['error.invalidVersion']='Please enter a valid version number!' + ['error.reEnter']='Input error, please re-enter!' + ['error.installDockerEngineFailed']='Docker Engine installation failed!' + ['error.installPackageFailed']='Package {} installation failed, please install manually and rerun script!' + ['error.defaultBehavior.https']='Using HTTPS protocol by default' + ['error.defaultBehavior.noClose']='Not closing by default' + ['error.defaultBehavior.installLatest']='Installing latest version by default' + ['error.defaultBehavior.noOverwrite']='Not overwriting by default' + ['error.defaultBehavior.noUseIntranetSource']='Not using intranet address by default' + ['warn.usedIntranetSource']='Switched to intranet-only address, use only in specific environments!' + ['warn.needValidNumberIndex']='Please enter a valid number index!' + ['warn.needInputNumberIndex']='Please enter a number index!' + ['warn.needManuallyDeleteConfig']='Please manually delete {} configuration in {} and restart service {}' + ['tip.skipInstallDockerEngine']='Detected Docker Engine is already installed with latest version, skipping installation' + ['info.backuped.dockerConfig']='Original Docker config file has been backed up' + ['interaction.source.type.public']='Public' + ['interaction.source.type.intranet']='Intranet' + ['interaction.source.type.select']='Please select network address (access method) for Docker CE mirror:' + ['interaction.source.type.usePublicAddress']='Use public network address for Docker CE mirror by default, continue' + ['interaction.source.dockerCE.select']='Please select the Docker CE mirror you want to use:' + ['interaction.source.dockerCE.selectAndInput']='Please select and enter the Docker CE mirror you want to use' + ['interaction.source.dockerRegistry.select']='Please select the Docker Registry mirror you want to use:' + ['interaction.source.dockerRegistry.selectAndInput']='Please select and enter the Docker Registry mirror you want to use' + ['interaction.protocol.select']='Please select network protocol for Docker CE mirror:' + ['interaction.protocol.useHttp']='Use HTTP protocol for Docker CE mirror' + ['interaction.firewall.close']='Close system firewall and SELinux' + ['interaction.install.selectVersion']='Please select the version you want to install:' + ['interaction.install.selectedVersion']='Specified installation version:' + ['interaction.install.selectedTitle']='Please select the version to install, e.g.: {}' + ['interaction.install.inputVersion']='Based on the list above, please select and enter the specific version you want to install:' + ['interaction.install.latestVersion']='Install latest version of Docker Engine' + ['interaction.backup.skipOverwrite']='Detected existing backup of Docker config file, skip overwriting backup' + ['interaction.common.tip']='Tip' + ['interaction.common.operationCanceled']='Operation canceled' + ['interaction.common.yes']='Yes' + ['interaction.common.no']='No' + ['work.installDependents']='Install environment packages' + ['work.installDockerEngine']='Install Docker Engine' + ['source.sync.text1']='Update APT package index' + ['source.sync.text2']='Generate mirror cache' + ['result.install.failed']='Installation failed' + ['result.install.checkSourceFile']='Check source file:' + ['result.install.manuallyExecCmd']='Please try manually executing installation command: {}' + ['result.install.notRunning']='Detected Docker service startup error, try running this script again' + ['result.install.manuallyRun']='Please execute {} command to try starting or investigate error cause' + ['result.registry.success']='Registry mirror replaced successfully' + ['result.registry.dockerEngineNotExsit']='Docker Engine is not installed yet, please remove {} command option and rerun script!' + ['commands.help']='Command options(name/meaning/value): + + --source Specify Docker CE mirror address (domain or IP) address + --source-registry Specify Docker Registry mirror address (domain or IP) address + --branch Specify Docker CE mirror repository (path) repo name + --branch-version Specify Docker CE mirror repository version version + --designated-version Specify Docker Engine installation version version + --codename Specify Debian-based OS codename codename + --protocol Specify Web protocol for Docker CE mirror http or https + --install-latest Whether to install the latest Docker Engine true or false + --close-firewall Whether to disable the firewall true or false + --clean-screen Whether to clear the screen before running true or false + --only-registry Only switch registry mirror mode none + --pure-mode Pure mode, minimal output none + --help Show help menu none + +Issue Report {}' + ) +} + +init_msg_pack +handle_command_options "$@" +main diff --git a/docker-info/AGENTS.md b/docker-info/AGENTS.md new file mode 100644 index 0000000..5558363 --- /dev/null +++ b/docker-info/AGENTS.md @@ -0,0 +1,179 @@ +# AGENTS.md - Agentic Coding Guidelines + +## Project Overview + +This is a Bash shell script project for collecting Docker and server information on Debian/Ubuntu systems. + +**Primary Language**: Bash +**Main File**: `docker-info.sh` + +--- + +## Build/Lint/Test Commands + +Since this is a Bash script project without a formal build system, use these commands: + +### Linting +```bash +# ShellCheck (static analysis for bash scripts) +shellcheck docker-info.sh + +# Check for syntax errors +bash -n docker-info.sh +``` + +### Testing +```bash +# Run the script (requires Docker to be installed for full functionality) +bash docker-info.sh + +# Or make executable and run directly +chmod +x docker-info.sh +./docker-info.sh +``` + +### Single Test Pattern +```bash +# Test specific functions by sourcing and calling them +source docker-info.sh && command_exists docker +source docker-info.sh && print_success "test message" +``` + +--- + +## Code Style Guidelines + +### General Bash Style + +- **Shebang**: Always use `#!/usr/bin/env bash` +- **Set options**: Use `set -euo pipefail` at the start of scripts + - `-e`: Exit on error + - `-u`: Exit on undefined variables + - `-o pipefail`: Pipeline fails if any command fails + +### Formatting + +- **Indentation**: 4 spaces (no tabs) +- **Line length**: Keep lines under 100 characters +- **Quotes**: Always quote variables: `"$variable"` not `$variable` +- **Functions**: Use `snake_case` for function names +- **Constants**: Use `UPPER_CASE` for constants and color codes + +### Naming Conventions + +```bash +# Functions - snake_case +print_header() { } +get_server_info() { } +check_root() { } + +# Variables - descriptive names +local container_output +local cpu_count +local total_mem + +# Constants - UPPER_CASE +readonly RED='\033[0;31m' +readonly HEADER_COLOR="${BRIGHT_CYAN}" +``` + +### Error Handling + +```bash +# Always check command existence before use +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Use proper exit codes +if ! command_exists docker; then + print_error "Docker未安装" + return 1 +fi + +# Redirect errors appropriately +docker ps 2>/dev/null || print_warning "无法列出容器" +``` + +### Function Structure + +```bash +# Document functions with comments +# 获取服务器信息 +get_server_info() { + print_header "服务器信息" + + # Use local for function-scoped variables + local cpu_count=$(grep -c '^processor' /proc/cpuinfo) + local cpu_model=$(grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs) + + # Call other functions for output + print_key_value "CPU核心数" "$cpu_count" +} +``` + +### Color/Styling Code + +- Define color codes as constants at the top of the file +- Group related colors together (basic, bright, background, styles) +- Use descriptive names: `HEADER_COLOR`, `SUCCESS_COLOR`, `ERROR_COLOR` +- Always reset colors with `${NC}` after colored output + +### Output Patterns + +```bash +# Use helper functions for consistent output +print_header() # Boxed titles +print_section() # Section headers with arrows +print_key_value() # Key: Value pairs +print_success() # Green checkmark +print_warning() # Yellow warning +print_error() # Red X +``` + +### Comments + +- Use Chinese comments to match existing codebase style +- Keep comments concise and meaningful +- Comment complex logic or non-obvious behavior + +--- + +## Testing Checklist + +Before submitting changes: + +- [ ] Run `shellcheck docker-info.sh` with no warnings +- [ ] Run `bash -n docker-info.sh` for syntax check +- [ ] Test on a system with Docker installed +- [ ] Test on a system without Docker (should handle gracefully) +- [ ] Verify all color output displays correctly +- [ ] Check that tables align properly + +--- + +## Dependencies + +**Required**: None (uses standard POSIX utilities) + +**Optional but recommended**: +- `jq` - For better JSON parsing of Docker info +- `shellcheck` - For linting + +--- + +## File Structure + +``` +/shumengya/project/bash/docker-info/ +└── docker-info.sh # Main script file +``` + +--- + +## Security Notes + +- This script may require root access for some Docker operations +- Always validate user input if added in the future +- Use proper quoting to prevent word splitting and globbing +- Sanitize any data passed to eval or similar dangerous operations diff --git a/docker-info/docker-info.sh b/docker-info/docker-info.sh new file mode 100755 index 0000000..83e2034 --- /dev/null +++ b/docker-info/docker-info.sh @@ -0,0 +1,253 @@ +#!/usr/bin/env bash + +# ============================================================================= +# Docker Info Collector - Single Column Edition +# ============================================================================= + +set -euo pipefail + +# ============================================================================= +# Colors +# ============================================================================= + +readonly NC='\033[0m' +readonly GRAY='\033[0;90m' +readonly CYAN='\033[0;36m' +readonly GREEN='\033[1;32m' +readonly YELLOW='\033[1;33m' +readonly WHITE='\033[1;37m' +readonly DIM='\033[2m' + +readonly C_HEADER="${CYAN}" +readonly C_SECTION="${YELLOW}" +readonly C_KEY="${WHITE}" +readonly C_VALUE="${CYAN}" +readonly C_OK="${GREEN}" +readonly C_WARN="${YELLOW}" +readonly C_ERR="\033[1;31m" +readonly C_DIM="${GRAY}" + +# Separator line (thick line style) +SEP_LINE="${C_DIM}══════════════════════════════════════════════════════════════════════════════${NC}" + +# ============================================================================= +# Utils +# ============================================================================= + +has_cmd() { command -v "$1" &>/dev/null; } + +print_header() { + local title="$1" + local len=${#title} + local pad=$(( (76 - len) / 2 )) + echo -e "\n${C_HEADER}╔══════════════════════════════════════════════════════════════════════════════╗" + printf "${C_HEADER}║%${pad}s${WHITE} %s %${pad}s║${NC}\n" "" "$title" "" + echo -e "${C_HEADER}╚══════════════════════════════════════════════════════════════════════════════╝${NC}" +} + +print_section() { + echo -e "\n${C_SECTION}▶ $1${NC}" + echo -e "$SEP_LINE" +} + +print_kv() { + printf " ${C_KEY}%-14s${NC} ${C_VALUE}%s${NC}\n" "$1:" "$2" +} + +print_ok() { echo -e " ${C_OK}●${NC} $1"; } +print_warn() { echo -e " ${C_WARN}●${NC} $1"; } +print_err() { echo -e " ${C_ERR}●${NC} $1"; } + +# ============================================================================= +# System Info +# ============================================================================= + +collect_server() { + print_header "服务器信息" + + # OS Information + print_section "操作系统" + local os_name kernel arch + os_name="$(. /etc/os-release 2>/dev/null && echo "$PRETTY_NAME" || uname -s)" + kernel="$(uname -r)" + arch="$(uname -m)" + + print_kv "系统" "$os_name" + print_kv "内核版本" "$kernel" + print_kv "系统架构" "$arch" + + # Host Info + print_section "主机信息" + local hostname uptime_str + hostname="$(hostname)" + uptime_str="$(uptime -p 2>/dev/null | sed 's/up //' || uptime | sed 's/.*up //; s/,.*//')" + + print_kv "主机名" "$hostname" + print_kv "运行时长" "$uptime_str" + print_kv "当前时间" "$(date '+%Y-%m-%d %H:%M:%S')" + + # CPU + if [[ -f /proc/cpuinfo ]]; then + print_section "处理器" + local cpus cpu_model + cpus=$(grep -c '^processor' /proc/cpuinfo) + cpu_model=$(grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs) + print_kv "核心数量" "${cpus} 核" + print_kv "型号" "$cpu_model" + fi + + # Memory + if has_cmd free; then + print_section "内存" + local mem_total mem_used mem_free mem_pct + mem_total=$(free -h | awk '/^Mem:/ {print $2}') + mem_used=$(free -h | awk '/^Mem:/ {print $3}') + mem_free=$(free -h | awk '/^Mem:/ {print $7}') + mem_pct=$(free | awk '/^Mem:/ {printf "%.1f", $3/$2 * 100}') + + print_kv "总容量" "$mem_total" + print_kv "已使用" "$mem_used (${mem_pct}%)" + print_kv "可用" "$mem_free" + fi + + # Disk + if has_cmd df; then + print_section "磁盘使用" + + df -h --output=source,fstype,size,used,pcent,target 2>/dev/null | tail -n +2 | while read -r fs type size used pct target; do + [[ "$fs" == "tmpfs" || "$fs" == "devtmpfs" || "$fs" == "overlay" ]] && continue + [[ -z "$fs" ]] && continue + # Escape % for printf + local pct_clean="${pct%%%}" + printf " ${C_DIM}[${NC}${C_VALUE}%-12s${NC}${C_DIM}]${NC} ${C_KEY}%-8s${NC} ${C_VALUE}%-7s${NC} ${C_DIM}used:${NC} ${C_VALUE}%-7s${NC} ${C_DIM}(%s%%)${NC}\n" \ + "$target" "$type" "$size" "$used" "$pct_clean" + done + fi + + # Network + if has_cmd ip; then + print_section "网络接口" + + ip -o addr show 2>/dev/null | awk '{print $2, $4}' | while read -r iface addr; do + [[ "$iface" == "lo" ]] && continue + print_kv "$iface" "$addr" + done + fi +} + +# ============================================================================= +# Docker Info +# ============================================================================= + +collect_docker() { + print_header "Docker 信息" + + if ! has_cmd docker; then + print_err "Docker 未安装" + return 1 + fi + + # Version + print_section "版本信息" + local client_ver server_ver + client_ver=$(docker version --format '{{.Client.Version}}' 2>/dev/null || echo "N/A") + server_ver=$(docker version --format '{{.Server.Version}}' 2>/dev/null || echo "N/A") + + print_kv "客户端" "$client_ver" + print_kv "服务端" "$server_ver" + if has_cmd docker-compose; then + print_kv "Docker Compose" "$(docker-compose version --short 2>/dev/null)" + fi + + # Status + if docker info &>/dev/null; then + print_ok "守护进程运行中" + else + print_warn "守护进程未运行" + return 1 + fi + + # Stats + print_section "资源统计" + local containers running images networks volumes + containers=$(docker ps -aq 2>/dev/null | wc -l) + running=$(docker ps -q 2>/dev/null | wc -l) + images=$(docker images -q 2>/dev/null | wc -l) + networks=$(docker network ls -q 2>/dev/null | wc -l) + volumes=$(docker volume ls -q 2>/dev/null | wc -l) + + print_kv "容器" "${running} 运行 / ${containers} 总计" + print_kv "镜像" "$images" + print_kv "网络" "$networks" + print_kv "存储卷" "$volumes" + + # Running containers + if [[ $running -gt 0 ]]; then + print_section "运行中的容器" + + docker ps --format "{{.Names}}|{{.Image}}|{{.Status}}" 2>/dev/null | while IFS='|' read -r name image status; do + printf " ${C_OK}●${NC} ${C_VALUE}%-20s${NC} ${C_DIM}%-30s${NC} %s\n" "$name" "${image:0:30}" "$status" + done + fi + + # All containers + if [[ $containers -gt 0 ]]; then + print_section "所有容器" + + docker ps -a --format "{{.Names}}|{{.Image}}|{{.Status}}" 2>/dev/null | head -20 | while IFS='|' read -r name image status; do + local icon="${C_DIM}○${NC}" + local color="$C_VALUE" + [[ "$status" == Up* ]] && icon="${C_OK}●${NC}" && color="$C_OK" + [[ "$status" == Exited* ]] && color="$C_DIM" + + printf " ${icon} ${color}%-20s${NC} ${C_DIM}%-25s${NC} %s\n" "$name" "${image:0:25}" "$status" + done + + [[ $containers -gt 20 ]] && echo -e " ${C_DIM}... 还有 $((containers - 20)) 个容器${NC}" + fi + + # Images + if [[ $images -gt 0 ]]; then + print_section "镜像列表" + + docker images --format "{{.Repository}}|{{.Tag}}|{{.Size}}|{{.CreatedAt}}" 2>/dev/null | grep -v "" | head -25 | while IFS='|' read -r repo tag size created; do + printf " ${C_DIM}◆${NC} ${C_VALUE}%-35s${NC} ${C_DIM}%-10s %s${NC}\n" "${repo}:${tag}" "$size" "$created" + done + + [[ $images -gt 25 ]] && echo -e " ${C_DIM}... 还有 $((images - 25)) 个镜像${NC}" + fi + + # Networks + if [[ $networks -gt 0 ]]; then + print_section "网络" + + docker network ls --format "{{.Name}}|{{.Driver}}|{{.Scope}}" 2>/dev/null | head -15 | while IFS='|' read -r name driver scope; do + printf " ${C_DIM}◎${NC} ${C_VALUE}%-20s${NC} ${C_DIM}[%s/%s]${NC}\n" "$name" "$driver" "$scope" + done + fi + + # Volumes + if [[ $volumes -gt 0 ]]; then + print_section "存储卷" + + docker volume ls --format "{{.Name}}|{{.Driver}}" 2>/dev/null | head -20 | while IFS='|' read -r name driver; do + printf " ${C_DIM}▪${NC} ${C_VALUE}%s${NC} ${C_DIM}(%s)${NC}\n" "$name" "$driver" + done + + [[ $volumes -gt 20 ]] && echo -e " ${C_DIM}... 还有 $((volumes - 20)) 个存储卷${NC}" + fi +} + +# ============================================================================= +# Main +# ============================================================================= + +main() { + collect_server + collect_docker + echo -e "\n${C_HEADER}╔══════════════════════════════════════════════════════════════════════════════╗" + echo -e "${C_HEADER}║${C_OK} ✓ 信息收集完成 ${C_HEADER}║${NC}" + echo -e "${C_HEADER}╚══════════════════════════════════════════════════════════════════════════════╝${NC}\n" +} + +main "$@" diff --git a/filebrowser/install_filebrowser.sh b/filebrowser/install_filebrowser.sh new file mode 100644 index 0000000..a89e524 --- /dev/null +++ b/filebrowser/install_filebrowser.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Filebrowser 一键安装脚本 +# 用法示例:curl -fsSL "https://pan.shumengya.top/d/scripts/filebrowser/install_filebrowser.sh" | sudo bash +# 目录结构假设: +# BASE_URL/linux-amd64/filebrowser +# BASE_URL/linux-arm64/filebrowser + +BASE_URL="https://pan.shumengya.top/d/scripts/filebrowser" +INSTALL_DIR="/shumengya/bin/filebrowser" +SERVICE_NAME="smy-filebrowser" +BINARY_NAME="filebrowser" + +log() { printf '[Filebrowser-安装] %s\n' "$*" >&2; } +fail() { log "错误: $*" >&2; exit 1; } + +# 进度条函数 +show_progress() { + local pid=$1 + local text=$2 + local delay=0.1 + local spin='-\|/' + + printf "[Filebrowser-安装] %s... " "$text" >&2 + + while ps -p "$pid" > /dev/null 2>&1; do + local temp=${spin#?} + printf "\b%c" "$spin" >&2 + local spin=$temp${spin%"$temp"} + sleep $delay + done + printf "\b完成\n" >&2 +} + +require_root() { + if [ "${EUID:-$(id -u)}" -ne 0 ]; then + fail "请使用 root 权限运行 (sudo bash install_filebrowser.sh)" + fi +} + +detect_arch() { + local machine + machine=$(uname -m) + case "$machine" in + x86_64|amd64) echo "linux-amd64" ;; + aarch64|arm64) echo "linux-arm64" ;; + *) fail "不支持的架构: $machine" ;; + esac +} + +download_and_install() { + local arch=$1 + local tmp_dir + tmp_dir=$(mktemp -d) + trap 'if [ -n "${tmp_dir:-}" ] && [ -d "$tmp_dir" ]; then rm -rf "$tmp_dir"; fi' EXIT + + mkdir -p "$INSTALL_DIR" + + local bin_url="${BASE_URL}/${arch}/${BINARY_NAME}" + + log "正在处理 ${BINARY_NAME} ..." + + # 停止旧服务 + systemctl stop "${SERVICE_NAME}.service" 2>/dev/null || true + + # 强制清理可能残留的进程 (避免 Text file busy) + pids=$(pgrep -f "$INSTALL_DIR/$BINARY_NAME" || true) + if [ -n "$pids" ]; then + log "清理残留进程..." + kill -9 $pids 2>/dev/null || true + fi + + # 优先检测当前目录下是否有二进制文件(本地安装模式) + if [ -f "./${BINARY_NAME}" ]; then + log "发现本地文件 ./${BINARY_NAME},跳过下载..." + cp "./${BINARY_NAME}" "$tmp_dir/$BINARY_NAME" + else + # 下载二进制 + curl -fsSL "$bin_url" -o "$tmp_dir/$BINARY_NAME" & + show_progress $! "下载二进制文件" + [ -f "$tmp_dir/$BINARY_NAME" ] || fail "下载失败" + fi + + # 安装文件 + cp "$tmp_dir/$BINARY_NAME" "$INSTALL_DIR/$BINARY_NAME" + chmod +x "$INSTALL_DIR/$BINARY_NAME" + + # 配置服务 + write_service + + # 启动服务 + systemctl daemon-reload + systemctl enable "${SERVICE_NAME}.service" + systemctl restart "${SERVICE_NAME}.service" + + sleep 2 + if systemctl is-active --quiet "${SERVICE_NAME}.service"; then + log "服务启动成功" + log "Filebrowser 监听端口: 2333" + log "配置文件和数据库将存储在: $INSTALL_DIR" + else + log "警告: 服务启动失败,查看日志:" + journalctl -u "${SERVICE_NAME}.service" --no-pager -n 10 + fi +} + +write_service() { + local service_file="/etc/systemd/system/${SERVICE_NAME}.service" + + cat > "$service_file" <&2; } +fail() { log "错误: $*" >&2; exit 1; } + +show_progress() { + local pid=$1 + local text=$2 + local delay=0.1 + local spin='-\|/' + + printf "[Filebrowser-卸载] %s... " "$text" >&2 + + while ps -p "$pid" > /dev/null 2>&1; do + local temp=${spin#?} + printf "\b%c" "$spin" >&2 + local spin=$temp${spin%"$temp"} + sleep $delay + done + printf "\b完成\n" >&2 +} + +require_root() { + if [ "${EUID:-$(id -u)}" -ne 0 ]; then + fail "请使用 root 权限运行 (sudo bash uninstall_filebrowser.sh)" + fi +} + +stop_and_disable_service() { + if systemctl is-active --quiet "${SERVICE_NAME}.service"; then + systemctl stop "${SERVICE_NAME}.service" + fi + + if systemctl is-enabled --quiet "${SERVICE_NAME}.service" 2>/dev/null; then + systemctl disable "${SERVICE_NAME}.service" + fi +} + +remove_service_file() { + local service_file="/etc/systemd/system/${SERVICE_NAME}.service" + + if [ -f "$service_file" ]; then + rm -f "$service_file" + systemctl daemon-reload + fi +} + +cleanup_process() { + # 查找并杀掉所有匹配的进程 + local pids + pids=$(pgrep -f "$INSTALL_DIR/$BINARY_NAME" || true) + if [ -n "$pids" ]; then + kill -9 $pids 2>/dev/null || true + fi +} + +uninstall_main() { + log "正在卸载 Filebrowser ..." + + (stop_and_disable_service) & + show_progress $! "停止服务" + + cleanup_process + + (remove_service_file) & + show_progress $! "删除服务文件" + + if [ -f "$INSTALL_DIR/$BINARY_NAME" ]; then + rm -f "$INSTALL_DIR/$BINARY_NAME" + fi + + # 清理日志文件(可选) + if [ -f "/var/log/filebrowser.log" ]; then + rm -f "/var/log/filebrowser.log" + log "已删除日志文件" + fi + + # 询问是否删除数据(数据库) + if [ -d "$INSTALL_DIR" ]; then + # 检查目录下是否有除了二进制文件以外的内容(主要是数据库) + if [ -n "$(ls -A "$INSTALL_DIR" 2>/dev/null)" ]; then + log "警告: 安装目录 $INSTALL_DIR 中可能包含用户数据 (如 filebrowser.db)" + # 默认不自动删除数据目录,防止误删,提示用户手动删除 + log "为了安全起见,脚本仅删除了二进制文件。若要彻底清除数据,请手动运行: rm -rf $INSTALL_DIR" + else + rm -rf "$INSTALL_DIR" + log "已删除空安装目录" + fi + fi + + log "==========================================" + log "卸载任务完成" + log "==========================================" +} + +main() { + require_root + uninstall_main +} + +main "$@" diff --git a/frp/frp/frpc.toml b/frp/frp/frpc.toml new file mode 100644 index 0000000..18fa8f7 --- /dev/null +++ b/frp/frp/frpc.toml @@ -0,0 +1,37 @@ +#=========================================== +#===================基础设置=================== +#=========================================== + + +serverAddr = "47.108.90.0" +serverPort = 7000 + + +auth.method = "token" +auth.token = "smy" + + +webServer.addr = "0.0.0.0" +webServer.port = 7400 +webServer.user = "shumengya" +webServer.password = "tyh@19900420" +webServer.pprofEnable = false + + +# 日志配置 +log.to = "console" +log.level = "info" + + +#=========================================== +#===================Http服务=================== +#=========================================== + + +#大萌芽frp客户端-frpc +[[proxies]] +name = "frpc" +type = "http" +localIP = "127.0.0.1" +localPort = 7400 +customDomains = ["frpc.shumengya.top"] diff --git a/frp/frp/frps.toml b/frp/frp/frps.toml new file mode 100644 index 0000000..562ad94 --- /dev/null +++ b/frp/frp/frps.toml @@ -0,0 +1,26 @@ +# frp服务端配置 - 作为nginx后端服务 +# 与nginx配合使用,提供HTTPS支持 + + +bindAddr = "0.0.0.0" +bindPort = 7000 + + +auth.method = "token" +auth.token = "smy" + + +# HTTP配置 - 作为后端服务(nginx代理) +vhostHTTPPort = 8080 # nginx代理到此端口 + + +# 日志配置 +log.to = "console" +log.level = "info" + + +# 管理界面 +webServer.addr = "0.0.0.0" +webServer.port = 7500 +webServer.user = "shumengya" +webServer.password = "tyh@19900420" diff --git a/frp/frp/linux_amd64/frpc b/frp/frp/linux_amd64/frpc new file mode 100644 index 0000000..57c7ba3 Binary files /dev/null and b/frp/frp/linux_amd64/frpc differ diff --git a/frp/frp/linux_amd64/frps b/frp/frp/linux_amd64/frps new file mode 100644 index 0000000..36772cc Binary files /dev/null and b/frp/frp/linux_amd64/frps differ diff --git a/frp/frp/linux_arm64/frpc b/frp/frp/linux_arm64/frpc new file mode 100644 index 0000000..cd93308 Binary files /dev/null and b/frp/frp/linux_arm64/frpc differ diff --git a/frp/frp/linux_arm64/frps b/frp/frp/linux_arm64/frps new file mode 100644 index 0000000..1328537 Binary files /dev/null and b/frp/frp/linux_arm64/frps differ diff --git a/frp/frp/smy-frpc.serivce b/frp/frp/smy-frpc.serivce new file mode 100644 index 0000000..e69de29 diff --git a/frp/frp/smy-frps.serivce b/frp/frp/smy-frps.serivce new file mode 100644 index 0000000..e69de29 diff --git a/frp/install_frp.sh b/frp/install_frp.sh new file mode 100644 index 0000000..b682992 --- /dev/null +++ b/frp/install_frp.sh @@ -0,0 +1,192 @@ +#!/usr/bin/env bash +set -euo pipefail + +# FRP 一键安装脚本 +# 用法示例:curl -fsSL "https://pan.shumengya.top/d/scripts/frp/install_frp.sh" | sudo bash +# 包含 frps (服务端) 和 frpc (客户端) 的安装 +# 目录结构假设: +# BASE_URL/linux_amd64/frps +# BASE_URL/linux_amd64/frpc +# BASE_URL/frps.toml +# BASE_URL/frpc.toml +# BASE_URL/smy-frps.service (模板) +# BASE_URL/smy-frpc.service (模板) + +BASE_URL="https://pan.shumengya.top/d/scripts/frp/frp" +INSTALL_DIR="/shumengya/bin/frp" +SERVICE_PREFIX="smy-frp" + +log() { printf '[frp-安装] %s\n' "$*" >&2; } +fail() { log "错误: $*" >&2; exit 1; } + +# 进度条函数 +show_progress() { + local pid=$1 + local text=$2 + local delay=0.1 + local spin='-\|/' + + printf "[frp-安装] %s... " "$text" >&2 + + while ps -p "$pid" > /dev/null 2>&1; do + local temp=${spin#?} + printf "\b%c" "$spin" >&2 + local spin=$temp${spin%"$temp"} + sleep $delay + done + printf "\b完成\n" >&2 +} + +require_root() { + if [ "${EUID:-$(id -u)}" -ne 0 ]; then + fail "请使用 root 权限运行 (sudo bash install_frp.sh)" + fi +} + +detect_arch() { + local machine + machine=$(uname -m) + case "$machine" in + x86_64|amd64) echo "linux_amd64" ;; + aarch64|arm64) echo "linux_arm64" ;; + *) fail "不支持的架构: $machine" ;; + esac +} + +select_mode() { + echo "请选择安装模式:" >&2 + echo "1) 安装客户端 (frpc)" >&2 + echo "2) 安装服务端 (frps)" >&2 + echo "3) 同时安装" >&2 + read -p "请输入选项 [1-3]: " choice < /dev/tty + case "$choice" in + 1) echo "client" ;; + 2) echo "server" ;; + 3) echo "both" ;; + *) fail "无效选项" ;; + esac +} + +download_and_install() { + local mode=$1 + local arch=$2 + local tmp_dir + tmp_dir=$(mktemp -d) + trap 'if [ -n "${tmp_dir:-}" ] && [ -d "$tmp_dir" ]; then rm -rf "$tmp_dir"; fi' EXIT + + mkdir -p "$INSTALL_DIR" + + if [ "$mode" = "client" ] || [ "$mode" = "both" ]; then + install_component "frpc" "$arch" "$tmp_dir" + fi + + if [ "$mode" = "server" ] || [ "$mode" = "both" ]; then + install_component "frps" "$arch" "$tmp_dir" + fi +} + +install_component() { + local name=$1 # frpc or frps + local arch=$2 + local tmp_dir=$3 + local bin_url="${BASE_URL}/${arch}/${name}" + local conf_url="${BASE_URL}/${name}.toml" + local service_name="${SERVICE_PREFIX}${name:3}" # smy-frpc or smy-frps + + log "正在处理 $name ..." + + # 停止旧服务 + systemctl stop "${service_name}.service" 2>/dev/null || true + + # 强制清理可能残留的进程 (避免 Text file busy) + pids=$(pgrep -x "$name" || true) + if [ -n "$pids" ]; then + log "清理 $name 残留进程..." + kill -9 $pids 2>/dev/null || true + fi + + # 下载二进制 + curl -fsSL "$bin_url" -o "$tmp_dir/$name" & + show_progress $! "下载 $name 二进制文件" + [ -f "$tmp_dir/$name" ] || fail "下载 $name 失败" + + # 下载配置 + curl -fsSL "$conf_url" -o "$tmp_dir/${name}.toml" & + show_progress $! "下载 $name 配置文件" + [ -f "$tmp_dir/${name}.toml" ] || fail "下载配置文件失败" + + # 安装文件 + cp "$tmp_dir/$name" "$INSTALL_DIR/$name" + chmod +x "$INSTALL_DIR/$name" + + if [ ! -f "$INSTALL_DIR/${name}.toml" ]; then + cp "$tmp_dir/${name}.toml" "$INSTALL_DIR/${name}.toml" + else + log "保留现有配置文件: $INSTALL_DIR/${name}.toml" + fi + + # 配置服务 + write_service "$name" + + # 启动服务 + systemctl daemon-reload + systemctl enable "${service_name}.service" + systemctl restart "${service_name}.service" + + sleep 2 + if systemctl is-active --quiet "${service_name}.service"; then + log "$name 服务启动成功" + else + log "警告: $name 服务启动失败,查看日志:" + journalctl -u "${service_name}.service" --no-pager -n 10 + fi +} + +write_service() { + local name=$1 + local service_name="${SERVICE_PREFIX}${name:3}" + local service_file="/etc/systemd/system/${service_name}.service" + + cat > "$service_file" <&2; } +fail() { log "错误: $*" >&2; exit 1; } + +# 检查 root 权限 +if [ "${EUID:-$(id -u)}" -ne 0 ]; then + fail "请使用 root 权限运行" +fi + +start_service() { + local svc=$1 + local service_file="/etc/systemd/system/${svc}.service" + + if [ -f "$service_file" ]; then + log "检测到已安装服务: $svc" + + # 重置失败状态 + systemctl reset-failed "$svc" 2>/dev/null || true + + log "正在启用并启动 $svc..." + systemctl enable --now "$svc" + + sleep 1 + + if systemctl is-active --quiet "$svc"; then + log "✔ $svc 启动成功 (状态: $(systemctl is-active "$svc"))" + else + log "✘ $svc 启动失败" + systemctl status "$svc" --no-pager -n 5 || true + fi + else + # 仅在调试时显示,避免干扰普通用户 + # log "未检测到 $svc,跳过" + : + fi +} + +log "正在扫描并恢复 frp 服务..." + +found_any=false +if [ -f "/etc/systemd/system/${SERVICE_FRPC}.service" ]; then + start_service "$SERVICE_FRPC" + found_any=true +fi + +if [ -f "/etc/systemd/system/${SERVICE_FRPS}.service" ]; then + start_service "$SERVICE_FRPS" + found_any=true +fi + +if [ "$found_any" = false ]; then + log "未检测到任何已安装的 frp 服务 (smy-frpc 或 smy-frps)。" + log "请先运行安装脚本进行安装。" + exit 1 +fi + +log "操作完成。" diff --git a/frp/stopkill_frp.sh b/frp/stopkill_frp.sh new file mode 100644 index 0000000..5821ccc --- /dev/null +++ b/frp/stopkill_frp.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +set -euo pipefail + +# 强制停止 frp 服务并清理进程 +# 用法:curl -fsSL "https://pan.shumengya.top/d/scripts/frp/stopkill_frp.sh" | sudo bash + +SERVICE_FRPC="smy-frpc" +SERVICE_FRPS="smy-frps" + +log() { printf '[frp-停止] %s\n' "$*" >&2; } + +if [ "${EUID:-$(id -u)}" -ne 0 ]; then + log "请使用 root 权限运行" + exit 1 +fi + +stop_service() { + local svc=$1 + if systemctl is-active --quiet "$svc"; then + log "正在停止服务 $svc..." + systemctl disable --now "$svc" 2>/dev/null || true + systemctl stop "$svc" 2>/dev/null || true + fi + # 即使服务不活跃,也要尝试 disable,防止开机自启 + systemctl disable "$svc" 2>/dev/null || true + + # 重置失败状态 + systemctl reset-failed "$svc" 2>/dev/null || true +} + +kill_process() { + local name=$1 + local pids + local current_pid=$$ + + # 尝试精确匹配 + pids=$(pgrep -x "$name" || true) + + # 如果没找到,尝试模糊匹配但排除当前脚本 + if [ -z "$pids" ]; then + pids=$(pgrep -f "$name" | grep -v "$current_pid" || true) + fi + + if [ -n "$pids" ]; then + log "发现 $name 残留进程 PID: $pids,正在强制终止..." + kill -9 $pids 2>/dev/null || true + fi +} + +log "开始清理 frp 相关服务..." + +# Stop Services +stop_service "$SERVICE_FRPC" +stop_service "$SERVICE_FRPS" + +# Kill Processes +kill_process "frpc" +kill_process "frps" + +log "正在验证服务状态..." +if pgrep -x "frpc" >/dev/null || pgrep -x "frps" >/dev/null; then + log "警告: 仍有 frp 进程在运行!" + ps -fp $(pgrep -x "frpc" "frps" 2>/dev/null) || true +else + log "frp 相关服务及进程已完全停止 (服务已禁用)。" +fi diff --git a/frp/uninstall_frp.sh b/frp/uninstall_frp.sh new file mode 100644 index 0000000..41aa7dc --- /dev/null +++ b/frp/uninstall_frp.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash +set -euo pipefail + +# FRP 一键卸载脚本 +# 用法:curl -fsSL "https://pan.shumengya.top/d/scripts/frp/uninstall_frp.sh" | sudo bash + +INSTALL_DIR="/shumengya/bin/frp" +SERVICE_PREFIX="smy-frp" + +log() { printf '[frp-卸载] %s\n' "$*" >&2; } +fail() { log "错误: $*" >&2; exit 1; } + +show_progress() { + local pid=$1 + local text=$2 + local delay=0.1 + local spin='-\|/' + + printf "[frp-卸载] %s... " "$text" >&2 + + while ps -p "$pid" > /dev/null 2>&1; do + local temp=${spin#?} + printf "\b%c" "$spin" >&2 + local spin=$temp${spin%"$temp"} + sleep $delay + done + printf "\b完成\n" >&2 +} + +require_root() { + if [ "${EUID:-$(id -u)}" -ne 0 ]; then + fail "请使用 root 权限运行 (sudo bash uninstall_frp.sh)" + fi +} + +select_mode() { + echo "请选择卸载模式:" >&2 + echo "1) 卸载客户端 (frpc)" >&2 + echo "2) 卸载服务端 (frps)" >&2 + echo "3) 全部卸载" >&2 + read -p "请输入选项 [1-3]: " choice < /dev/tty + case "$choice" in + 1) echo "client" ;; + 2) echo "server" ;; + 3) echo "both" ;; + *) fail "无效选项" ;; + esac +} + +stop_and_disable_service() { + local name=$1 + local service_name="${SERVICE_PREFIX}${name:3}" + + if systemctl is-active --quiet "${service_name}.service"; then + systemctl stop "${service_name}.service" + fi + + if systemctl is-enabled --quiet "${service_name}.service" 2>/dev/null; then + systemctl disable "${service_name}.service" + fi +} + +remove_service_file() { + local name=$1 + local service_name="${SERVICE_PREFIX}${name:3}" + local service_file="/etc/systemd/system/${service_name}.service" + + if [ -f "$service_file" ]; then + rm -f "$service_file" + systemctl daemon-reload + fi +} + +cleanup_process() { + local name=$1 + # 查找并杀掉所有匹配的进程 + local pids + pids=$(pgrep -f "$INSTALL_DIR/$name" || true) + if [ -n "$pids" ]; then + kill -9 $pids 2>/dev/null || true + fi +} + +uninstall_component() { + local name=$1 + + log "正在卸载 $name ..." + + (stop_and_disable_service "$name") & + show_progress $! "停止服务" + + cleanup_process "$name" + + (remove_service_file "$name") & + show_progress $! "删除服务文件" + + if [ -f "$INSTALL_DIR/$name" ]; then + rm -f "$INSTALL_DIR/$name" + fi + + # 注意:不自动删除配置文件,以免误删用户配置 + # if [ -f "$INSTALL_DIR/${name}.toml" ]; then + # rm -f "$INSTALL_DIR/${name}.toml" + # fi +} + +main() { + require_root + + local mode + if [ $# -gt 0 ]; then + case "$1" in + client|frpc) mode="client" ;; + server|frps) mode="server" ;; + both) mode="both" ;; + *) fail "无效参数: $1 (可用: client, server, both)" ;; + esac + else + mode=$(select_mode) + fi + + if [ "$mode" = "client" ] || [ "$mode" = "both" ]; then + uninstall_component "frpc" + fi + + if [ "$mode" = "server" ] || [ "$mode" = "both" ]; then + uninstall_component "frps" + fi + + # 如果目录为空,则删除目录 + if [ -d "$INSTALL_DIR" ]; then + if [ -z "$(ls -A "$INSTALL_DIR")" ]; then + rm -rf "$INSTALL_DIR" + log "已删除空安装目录" + else + log "保留安装目录 (包含配置文件): $INSTALL_DIR" + fi + fi + + log "==========================================" + log "卸载任务完成" + log "==========================================" +} + +main "$@" diff --git a/login-info/login-info.sh b/login-info/login-info.sh new file mode 100755 index 0000000..5c893eb --- /dev/null +++ b/login-info/login-info.sh @@ -0,0 +1,267 @@ +#!/bin/bash + +# 用法示例:curl -fsSL "https://pan.shumengya.top/d/scripts/login_info.sh" | bash + +# --- 精心选择的颜色定义 --- +NONE='\033[00m' +BOLD='\033[1m' + +# 主题色 (可根据喜好调整) +# 可以选择一个主色调,例如蓝色系或绿色系 +# 这里我们尝试用青色作为标题,黄色作为关键信息,白色作为次要信息 +TITLE_COLOR='\033[01;36m' # 亮青色 (Bold Cyan) +INFO_COLOR='\033[01;33m' # 亮黄色 (Bold Yellow) +VALUE_COLOR='\033[00;37m' # 白色 (White) +LABEL_COLOR='\033[00;32m' # 绿色 (Green) - 用于标签 +SUBTLE_COLOR='\033[01;30m' # 深灰色/亮黑色 (Bold Black / Dark Gray) - 用于分隔符或不重要信息 +BLUE_COLOR='\033[01;34m' # 亮蓝色 (Bold Blue) +ORANGE_COLOR='\033[01;33m' # 亮黄色 (在16色终端中常作为橙色) - 使用 INFO_COLOR 相同的代码 + + + + +# --- 设备名称和欢迎 --- +HOSTNAME_TEXT=$(hostname) # 如果不再需要显示hostname,可以注释掉或删除这行 + +# --- 系统概览 --- +OS_INFO=$(lsb_release -ds 2>/dev/null || echo "N/A") +KERNEL_VERSION=$(uname -sr 2>/dev/null || echo "N/A") +BOOT_TIME=$(uptime -s 2>/dev/null || who -b | awk '{print $3, $4}') +UPTIME=$(uptime -p 2>/dev/null | sed 's/up //') +LOAD_AVG=$(uptime 2>/dev/null | awk -F'load average: ' '{print $2}') + +echo -e "${SUBTLE_COLOR}───────────────────────────────────────────────────────────────────────────────${NONE}" +echo -e "${TITLE_COLOR}${BOLD}系统概览${NONE}" +echo -e " ${LABEL_COLOR}系统名称:${NONE} ${VALUE_COLOR}$(uname -a)${NONE}" +echo -e " ${LABEL_COLOR}操作系统:${NONE} ${VALUE_COLOR}$OS_INFO${NONE}" +echo -e " ${LABEL_COLOR}内核版本:${NONE} ${VALUE_COLOR}$KERNEL_VERSION${NONE}" +echo -e " ${LABEL_COLOR}启动时间:${NONE} ${VALUE_COLOR}$BOOT_TIME${NONE}" +echo -e " ${LABEL_COLOR}运行时间:${NONE} ${VALUE_COLOR}$UPTIME${NONE}" +echo -e " ${LABEL_COLOR}平均负载:${NONE} ${VALUE_COLOR}$LOAD_AVG${NONE}" +echo -e "${SUBTLE_COLOR}───────────────────────────────────────────────────────────────────────────────${NONE}" + + + +# --- 硬件资源 --- +# 获取 CPU 型号,处理可能的多行输出,只取第一行,并去除首尾空格 +CPU_MODEL=$(grep "model name" /proc/cpuinfo | head -n 1 | awk -F ':' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//' || echo "N/A") +CPU_CORES=$(grep -c "processor" /proc/cpuinfo 2>/dev/null || echo "N/A") +# CPU 温度 (尽可能兼容更多机型) +CPU_TEMP="" +# 定义获取CPU温度的函数 +get_cpu_temp() { + local temp_c="" + + # 1. 尝试使用 sensors 命令 (如果安装了 lm-sensors) + if command -v sensors &> /dev/null; then + # 尝试匹配常见的CPU温度标签 + # Package id 0: Intel/AMD 多核封装温度 + # Tctl/Tdie: AMD Ryzen + # Core 0: Intel Core + # cpu_thermal: 树莓派/通用 + # Composite: 部分嵌入式设备 + temp_c=$(sensors | grep -iE '^(package id 0|tctl|tdie|core 0|cpu_thermal|composite|temp1):' | head -n 1 | awk '{print $2}' | tr -d '+°C') + if [ -n "$temp_c" ]; then + echo "$temp_c" + return + fi + fi + + # 2. 尝试读取 /sys/class/thermal/thermal_zone* + # 优先查找 x86_pkg_temp (Intel) 或 k10temp (AMD) 或 cpu-thermal (ARM) 或 acpitz + for zone in /sys/class/thermal/thermal_zone*; do + [ -e "$zone/type" ] || continue + type=$(cat "$zone/type") + if [[ "$type" == "x86_pkg_temp" || "$type" == "k10temp" || "$type" == "cpu-thermal" || "$type" == "acpitz" ]]; then + if [ -r "$zone/temp" ]; then + temp_raw=$(cat "$zone/temp") + # 转换为摄氏度 (除以1000) + if [ "$temp_raw" -gt 0 ] 2>/dev/null; then + awk "BEGIN {printf \"%.1f\", $temp_raw/1000}" + return + fi + fi + fi + done + + # 3. 如果还没找到,尝试任何 thermal_zone0 (通常是主要的) + if [ -r "/sys/class/thermal/thermal_zone0/temp" ]; then + temp_raw=$(cat "/sys/class/thermal/thermal_zone0/temp") + if [ "$temp_raw" -gt 0 ] 2>/dev/null; then + awk "BEGIN {printf \"%.1f\", $temp_raw/1000}" + return + fi + fi +} + +CPU_TEMP_VAL=$(get_cpu_temp) +if [ -n "$CPU_TEMP_VAL" ]; then + CPU_TEMP="(${INFO_COLOR}${CPU_TEMP_VAL}°C${VALUE_COLOR})" +fi + +# 智能内存显示:小于 1GB 显示 MB,否则显示 GB (保留1位小数) +MEM_TOTAL_MB=$(free -m | awk 'NR==2{print $2}') +if [ "$MEM_TOTAL_MB" -ge 1000 ]; then + MEM_TOTAL_DISPLAY=$(awk -v val="$MEM_TOTAL_MB" 'BEGIN {printf "%.1fGB", val/1024}') +else + MEM_TOTAL_DISPLAY="${MEM_TOTAL_MB}MB" +fi + +MEM_USED_PERCENT=$(free -m | awk 'NR==2{printf "%.1f%%", $3*100/$2 }') +MEM_AVAILABLE_MB=$(free -m | awk 'NR==2{print $7"MB"}') # 'available' 通常比 'free' 更能代表实际可用内存 + +# --- GPU 检测 --- +# 优先使用 lspci 检测 VGA, 3D, Display 控制器 +GPU_INFO="" +if command -v lspci &> /dev/null; then + # 获取设备列表,去除前面的地址信息,只保留设备名称 + # 典型 lspci 输出: "00:02.0 VGA compatible controller: Intel Corporation ..." + # 我们需要截取 "Intel Corporation ..." + # 使用 sed 处理:匹配开头到第二个冒号之前的所有内容并删除 + GPU_INFO=$(lspci | grep -iE 'vga|3d|display' | sed 's/^.*: .*[:] //') +fi + +echo -e "${TITLE_COLOR}${BOLD}硬件资源${NONE}" +echo -e " ${LABEL_COLOR}中央处理器 (CPU):${NONE}" +echo -e " ${VALUE_COLOR}$CPU_MODEL - ${CPU_CORES} 核心 ${CPU_TEMP}${NONE}" +if [ -n "$GPU_INFO" ]; then + echo -e " ${LABEL_COLOR}图形处理器 (GPU):${NONE}" + # 处理多显卡情况,逐行显示 + echo "$GPU_INFO" | while read -r line; do + echo -e " ${VALUE_COLOR}$line${NONE}" + done +fi +echo -e " ${LABEL_COLOR}内存 (RAM):${NONE}" +echo -e " ${VALUE_COLOR}总计: ${INFO_COLOR}$MEM_TOTAL_DISPLAY${VALUE_COLOR} | 已用: ${INFO_COLOR}$MEM_USED_PERCENT${VALUE_COLOR} | 可用: ${INFO_COLOR}$MEM_AVAILABLE_MB${NONE}" +echo -e " ${LABEL_COLOR}存储空间:${NONE}" + +# --- 修改的存储部分 (删除进度条, 修改颜色) --- +# 使用 df -hT 获取信息,-x 排除不必要的类型 (保留 overlay) +# 使用 awk 跳过头部 (NR>1),并按列提取 (Filesystem, Type, Size, Used, Use%, Mounted on) +# 注意:已添加 -x overlay 以隐藏 Docker 挂载卷 +df -hT -x tmpfs -x devtmpfs -x devpts -x proc -x sysfs -x cgroup -x fusectl -x securityfs -x pstore -x efivarfs -x autofs -x overlay 2>/dev/null | awk 'NR>1 {print $1, $2, $3, $4, $6, $7}' | while read -r DEVICE TYPE SIZE USED PERCENT MOUNTPOINT; do + + # --- 已删除进度条的计算和绘制 --- + + echo -e " ${INFO_COLOR}${MOUNTPOINT}${NONE} (${VALUE_COLOR}${DEVICE} - ${TYPE}${NONE})" + # --- 核心改动:将 总 和 已用 后面的数值改为蓝色 --- + # LABEL_COLOR 用于标签文字 "总:" 和 "已用:" + # BLUE_COLOR 用于数值 SIZE 和 USED + # VALUE_COLOR 用于百分比 PERCENT 以及括号和逗号 + echo -e " ${LABEL_COLOR}总:${NONE} ${BLUE_COLOR}${SIZE}${NONE}, ${LABEL_COLOR}已用:${NONE} ${BLUE_COLOR}${USED}${NONE} (${VALUE_COLOR}${PERCENT}${NONE})" +done + +echo -e "${SUBTLE_COLOR}───────────────────────────────────────────────────────────────────────────────${NONE}" + + + +# --- 网络连接 --- +echo -e "${TITLE_COLOR}${BOLD}网络连接${NONE}" +INTERFACES_UP=$(ip -o link show up | awk -F': ' '{print $2}' | cut -d '@' -f 1) # 使用 cut 移除 @ifname 后缀 +HAS_IP=false +if [ -n "$INTERFACES_UP" ]; then + for IFACE in $INTERFACES_UP; do + if [[ "$IFACE" == "lo" ]]; then continue; fi # 跳过 lo 接口 + # 跳过 Docker 相关接口 + if [[ "$IFACE" == docker* || "$IFACE" == veth* || "$IFACE" == br-* ]]; then continue; fi + + IP_ADDRS=$(ip -4 addr show dev "$IFACE" 2>/dev/null | grep -oP 'inet \K[\d.]+' | tr '\n' ' ') + IP_ADDRS_V6=$(ip -6 addr show dev "$IFACE" 2>/dev/null | grep -oP 'inet6 \K[0-9a-fA-F:]+' | grep -ivE '^fe80::' | head -n1 | tr '\n' ' ') # 只显示一个全局 IPv6 + MAC_ADDR=$(ip link show dev "$IFACE" 2>/dev/null | awk '/ether/ {print $2}') + + if [ -n "$IP_ADDRS" ] || [ -n "$IP_ADDRS_V6" ]; then + HAS_IP=true + IFACE_TYPE_LABEL="" + if [[ "$IFACE" == wlan* || "$IFACE" == wlp* || "$IFACE" == ath* || "$IFACE" == ra* ]]; then + IFACE_TYPE_LABEL="(${LABEL_COLOR}WiFi${NONE}) " + elif [[ "$IFACE" == eth* || "$IFACE" == enp* || "$IFACE" == eno* ]]; then + IFACE_TYPE_LABEL="(${LABEL_COLOR}有线${NONE}) " + # 添加对虚拟接口类型的更全面判断 + elif [[ "$IFACE" == docker* || "$IFACE" == br-* || "$IFACE" == veth* || "$IFACE" == tun* || "$IFACE" == tap* || "$IFACE" == virbr* ]]; then + IFACE_TYPE_LABEL="(${LABEL_COLOR}虚拟${NONE}) " + # 考虑桥接接口 + elif ip link show "$IFACE" | grep -q "bridge"; then + IFACE_TYPE_LABEL="(${LABEL_COLOR}桥接${NONE}) " + fi + + + echo -e " ${INFO_COLOR}${BOLD}${IFACE}${NONE} ${IFACE_TYPE_LABEL}" + [ -n "$IP_ADDRS" ] && echo -e " ${LABEL_COLOR}IPv4:${NONE} ${VALUE_COLOR}${IP_ADDRS% }${NONE}" # % 移除末尾空格 + [ -n "$IP_ADDRS_V6" ] && echo -e " ${LABEL_COLOR}IPv6:${NONE} ${VALUE_COLOR}${IP_ADDRS_V6% }${NONE}" + [ -n "$MAC_ADDR" ] && echo -e " ${LABEL_COLOR}MAC:${NONE} ${VALUE_COLOR}${MAC_ADDR}${NONE}" + fi + done +fi +if ! $HAS_IP; then + echo -e " ${VALUE_COLOR}未检测到活动的网络连接或IP地址${NONE}" +fi +echo -e "${SUBTLE_COLOR}───────────────────────────────────────────────────────────────────────────────${NONE}" + + + +# --- Docker 容器 --- +# 检查 docker 命令是否存在且守护进程正在运行 +if command -v docker &> /dev/null && docker ps &> /dev/null; then + DOCKER_RUNNING_COUNT=$(docker ps -q | wc -l) + DOCKER_TOTAL_COUNT=$(docker ps -aq | wc -l) + + echo -e "${TITLE_COLOR}${BOLD}Docker 容器${NONE}" + echo -e " ${LABEL_COLOR}容器数量:${NONE} ${VALUE_COLOR}运行中: ${INFO_COLOR}${DOCKER_RUNNING_COUNT}${VALUE_COLOR} / 总计: ${INFO_COLOR}${DOCKER_TOTAL_COUNT}${NONE}" + + if [ "$DOCKER_RUNNING_COUNT" -gt 0 ]; then + # 获取名称列表,用逗号分隔 + DOCKER_NAMES=$(docker ps --format "{{.Names}}" | tr '\n' ',' | sed 's/,$//' | sed 's/,/, /g') + echo -e " ${LABEL_COLOR}运行列表:${NONE} ${VALUE_COLOR}${DOCKER_NAMES}${NONE}" + fi + echo -e "${SUBTLE_COLOR}───────────────────────────────────────────────────────────────────────────────${NONE}" +fi + + + +# --- 活动与统计 --- +LAST_LOGIN_INFO=$(last -n 1 -wFai 2>/dev/null | head -n 1) # -a 把hostname放最后, -i 显示IP +LAST_LOGIN_DISPLAY="" +if [[ "$LAST_LOGIN_INFO" == *"wtmp begins"* || -z "$LAST_LOGIN_INFO" || $(echo "$LAST_LOGIN_INFO" | wc -w) -lt 5 ]]; then # 增加字段数检查 + LAST_LOGIN_DISPLAY="${VALUE_COLOR}无先前登录记录或记录格式异常${NONE}" +else + # --- 修改的上次登录部分 --- + USER=$(echo "$LAST_LOGIN_INFO" | awk '{print $1}') + # 对于 -wFai, IP/hostname 通常是第三列 + FROM_IP_OR_HOST=$(echo "$LAST_LOGIN_INFO" | awk '{print $3}') + + # 精确提取日期和时间部分,跳过 'still' 和年份 (字段 4到7) + LOGIN_TIME_FIELDS=$(echo "$LAST_LOGIN_INFO" | awk '{print $4, $5, $6, $7}') + + # 尝试用date格式化,如果失败则显示原始字段 + LOGIN_TIME_FORMATTED=$(date -d "$LOGIN_TIME_FIELDS $(date +%Y)" +"%Y-%m-%d %H:%M:%S" 2>/dev/null) # 显式添加年份尝试格式化 + if [ -z "$LOGIN_TIME_FORMATTED" ]; then + LOGIN_TIME_FORMATTED="${VALUE_COLOR}${LOGIN_TIME_FIELDS}${NONE} (raw)" # 格式化失败,显示原始字段并标记 + fi + + LAST_LOGIN_DISPLAY="${LABEL_COLOR}用户:${NONE} ${INFO_COLOR}$USER${NONE}, ${LABEL_COLOR}来自:${NONE} ${INFO_COLOR}$FROM_IP_OR_HOST${NONE}, ${LABEL_COLOR}时间:${NONE} ${VALUE_COLOR}$LOGIN_TIME_FORMATTED${NONE}" +fi + + +PACKAGE_COUNT=$(dpkg-query -f '${Package}\n' -W 2>/dev/null | wc -l || echo "N/A") # Debian/APT + +echo -e "${TITLE_COLOR}${BOLD}活动与统计${NONE}" +echo -e " ${LABEL_COLOR}上次登录:${NONE} $LAST_LOGIN_DISPLAY" + +# 检查是否是 Debian/Ubuntu 系列系统,然后显示包数 +if command -v dpkg-query &> /dev/null; then + PACKAGE_COUNT=$(dpkg-query -f '${Package}\n' -W 2>/dev/null | wc -l || echo "N/A") + echo -e " ${LABEL_COLOR}软件包数:${NONE} ${VALUE_COLOR}$PACKAGE_COUNT (Debian/APT)${NONE}" +elif command -v rpm &> /dev/null; then + PACKAGE_COUNT=$(rpm -qa 2>/dev/null | wc -l || echo "N/A") + echo -e " ${LABEL_COLOR}软件包数:${NONE} ${VALUE_COLOR}$PACKAGE_COUNT (RPM/Yum/Dnf)${NONE}" +elif command -v pacman &> /dev/null; then + PACKAGE_COUNT=$(pacman -Qq 2>/dev/null | wc -l || echo "N/A") + echo -e " ${LABEL_COLOR}软件包数:${NONE} ${VALUE_COLOR}$PACKAGE_COUNT (Pacman)${NONE}" +else + echo -e " ${LABEL_COLOR}软件包数:${NONE} ${VALUE_COLOR}N/A (未知包管理器)${NONE}" +fi + +CURRENT_DATETIME=$(date +"%Y年%m月%d日 %A %H:%M:%S %Z") +echo -e " ${LABEL_COLOR}当前登录时间:${NONE} ${VALUE_COLOR}$CURRENT_DATETIME$" + +echo -e "${SUBTLE_COLOR}───────────────────────────────────────────────────────────────────────────────${NONE}" diff --git a/mengyamonitor/install_mengyamonitor.sh b/mengyamonitor/install_mengyamonitor.sh new file mode 100644 index 0000000..3f600c6 --- /dev/null +++ b/mengyamonitor/install_mengyamonitor.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash +set -euo pipefail + +# MengyaMonitor 一键安装脚本 +# 用法示例:curl -fsSL "https://pan.shumengya.top/d/scripts/mengyamonitor/install_mengyamonitor.sh" | sudo bash +# 目录结构假设: +# BASE_URL/linux_amd64/mengyamonitor-backend +# BASE_URL/linux_arm64/mengyamonitor-backend + +BASE_URL="https://pan.shumengya.top/d/scripts/mengyamonitor" +INSTALL_DIR="/shumengya/bin/mengyamonitor" +SERVICE_NAME="smy-mengyamonitor" +BINARY_NAME="mengyamonitor-backend" + +log() { printf '[MengyaMonitor-安装] %s\n' "$*" >&2; } +fail() { log "错误: $*" >&2; exit 1; } + +# 进度条函数 +show_progress() { + local pid=$1 + local text=$2 + local delay=0.1 + local spin='-\|/' + + printf "[MengyaMonitor-安装] %s... " "$text" >&2 + + while ps -p "$pid" > /dev/null 2>&1; do + local temp=${spin#?} + printf "\b%c" "$spin" >&2 + local spin=$temp${spin%"$temp"} + sleep $delay + done + printf "\b完成\n" >&2 +} + +require_root() { + if [ "${EUID:-$(id -u)}" -ne 0 ]; then + fail "请使用 root 权限运行 (sudo bash install_mengyamonitor.sh)" + fi +} + +detect_arch() { + local machine + machine=$(uname -m) + case "$machine" in + x86_64|amd64) echo "linux_amd64" ;; + aarch64|arm64) echo "linux_arm64" ;; + *) fail "不支持的架构: $machine" ;; + esac +} + +download_and_install() { + local arch=$1 + local tmp_dir + tmp_dir=$(mktemp -d) + trap 'if [ -n "${tmp_dir:-}" ] && [ -d "$tmp_dir" ]; then rm -rf "$tmp_dir"; fi' EXIT + + mkdir -p "$INSTALL_DIR" + + local bin_url="${BASE_URL}/${arch}/${BINARY_NAME}" + + log "正在处理 ${BINARY_NAME} ..." + + # 停止旧服务 + systemctl stop "${SERVICE_NAME}.service" 2>/dev/null || true + + # 强制清理可能残留的进程 (避免 Text file busy) + pids=$(pgrep -f "$BINARY_NAME" || true) + if [ -n "$pids" ]; then + log "清理残留进程..." + kill -9 $pids 2>/dev/null || true + fi + + # 优先检测当前目录下是否有二进制文件(本地安装模式) + if [ -f "./${BINARY_NAME}" ]; then + log "发现本地文件 ./${BINARY_NAME},跳过下载..." + cp "./${BINARY_NAME}" "$tmp_dir/$BINARY_NAME" + else + # 下载二进制 + curl -fsSL "$bin_url" -o "$tmp_dir/$BINARY_NAME" & + show_progress $! "下载二进制文件" + [ -f "$tmp_dir/$BINARY_NAME" ] || fail "下载失败" + fi + + # 安装文件 + cp "$tmp_dir/$BINARY_NAME" "$INSTALL_DIR/$BINARY_NAME" + chmod +x "$INSTALL_DIR/$BINARY_NAME" + + # 配置服务 + write_service + + # 启动服务 + systemctl daemon-reload + systemctl enable "${SERVICE_NAME}.service" + systemctl restart "${SERVICE_NAME}.service" + + sleep 2 + if systemctl is-active --quiet "${SERVICE_NAME}.service"; then + log "服务启动成功" + else + log "警告: 服务启动失败,查看日志:" + journalctl -u "${SERVICE_NAME}.service" --no-pager -n 10 + fi +} + +write_service() { + local service_file="/etc/systemd/system/${SERVICE_NAME}.service" + + cat > "$service_file" <&2; } +fail() { log "错误: $*" >&2; exit 1; } + +show_progress() { + local pid=$1 + local text=$2 + local delay=0.1 + local spin='-\|/' + + printf "[MengyaMonitor-卸载] %s... " "$text" >&2 + + while ps -p "$pid" > /dev/null 2>&1; do + local temp=${spin#?} + printf "\b%c" "$spin" >&2 + local spin=$temp${spin%"$temp"} + sleep $delay + done + printf "\b完成\n" >&2 +} + +require_root() { + if [ "${EUID:-$(id -u)}" -ne 0 ]; then + fail "请使用 root 权限运行 (sudo bash uninstall_mengyamonitor.sh)" + fi +} + +stop_and_disable_service() { + if systemctl is-active --quiet "${SERVICE_NAME}.service"; then + systemctl stop "${SERVICE_NAME}.service" + fi + + if systemctl is-enabled --quiet "${SERVICE_NAME}.service" 2>/dev/null; then + systemctl disable "${SERVICE_NAME}.service" + fi +} + +remove_service_file() { + local service_file="/etc/systemd/system/${SERVICE_NAME}.service" + + if [ -f "$service_file" ]; then + rm -f "$service_file" + systemctl daemon-reload + fi +} + +cleanup_process() { + # 查找并杀掉所有匹配的进程 + local pids + pids=$(pgrep -f "$BINARY_NAME" || true) + if [ -n "$pids" ]; then + kill -9 $pids 2>/dev/null || true + fi +} + +uninstall_main() { + log "正在卸载 MengyaMonitor ..." + + (stop_and_disable_service) & + show_progress $! "停止服务" + + cleanup_process + + (remove_service_file) & + show_progress $! "删除服务文件" + + if [ -f "$INSTALL_DIR/$BINARY_NAME" ]; then + rm -f "$INSTALL_DIR/$BINARY_NAME" + fi + + # 清理日志文件(可选,这里默认清理) + if [ -f "/var/log/mengyamonitor.log" ]; then + rm -f "/var/log/mengyamonitor.log" + log "已删除日志文件" + fi + + # 如果目录为空,则删除目录 + if [ -d "$INSTALL_DIR" ]; then + rm -rf "$INSTALL_DIR" + log "已删除安装目录" + fi + + log "==========================================" + log "卸载任务完成" + log "==========================================" +} + +main() { + require_root + uninstall_main +} + +main "$@" diff --git a/openlist/install_openlist.sh b/openlist/install_openlist.sh new file mode 100644 index 0000000..077e114 --- /dev/null +++ b/openlist/install_openlist.sh @@ -0,0 +1,182 @@ +#!/usr/bin/env bash +set -euo pipefail + +# openlist 一键安装脚本 +# 用法示例:curl -fsSL "https://pan.shumengya.top/d/scripts/openlist/install_openlist.sh" | bash + +BASE_URL="https://pan.shumengya.top/d/scripts/openlist/openlist" +INSTALL_DIR="/shumengya/bin/openlist" +SERVICE_NAME="smy-openlist" +SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" + +log() { printf '[openlist-安装] %s\n' "$*" >&2; } +fail() { log "错误: $*" >&2; exit 1; } + +# 进度条函数 +show_progress() { + local pid=$1 + local text=$2 + local delay=0.1 + local spin='-\|/' + + printf "[openlist-安装] %s... " "$text" >&2 + + while ps -p "$pid" > /dev/null 2>&1; do + local temp=${spin#?} + printf "\b%c" "$spin" >&2 + local spin=$temp${spin%"$temp"} + sleep $delay + done + printf "\b完成\n" >&2 +} + +check_port() { + # 检查端口占用并尝试清理 + local port=5244 + if lsof -i :$port >/dev/null 2>&1 || netstat -tunlp | grep -q ":$port "; then + log "检测到端口 $port 被占用,尝试清理..." + fuser -k -n tcp $port >/dev/null 2>&1 || true + sleep 1 + if lsof -i :$port >/dev/null 2>&1; then + # 尝试查找占用进程并强制杀掉 + local pid + pid=$(lsof -t -i:$port 2>/dev/null || true) + if [ -n "$pid" ]; then + kill -9 "$pid" 2>/dev/null || true + fi + fi + fi +} + +require_root() { + # 必须使用 root 权限执行 + if [ "${EUID:-$(id -u)}" -ne 0 ]; then + fail "请使用 root 权限运行 (sudo bash install_openlist.sh)" + fi +} + +detect_arch() { + # 自动检测 CPU 架构,选择对应二进制 + local machine + machine=$(uname -m) + case "$machine" in + x86_64|amd64) echo "amd64" ;; + aarch64|arm64) echo "arm64" ;; + *) fail "不支持的架构: $machine" ;; + esac +} + +download_files() { + # 下载对应架构的二进制包和 data 目录 + local arch tmp_dir binary_url data_url + arch="$1" + tmp_dir=$(mktemp -d) + # 只在 tmp_dir 存在时清理 + trap 'if [ -n "${tmp_dir:-}" ] && [ -d "$tmp_dir" ]; then rm -rf "$tmp_dir"; fi' EXIT + + binary_url="${BASE_URL}/linux-${arch}.tar.gz" + data_url="${BASE_URL}/data.tgz" + + # 后台下载并显示进度 + curl -fsSL "$binary_url" -o "$tmp_dir/openlist.tar.gz" & + show_progress $! "正在下载 ${arch} 架构的二进制文件" + [ -f "$tmp_dir/openlist.tar.gz" ] || fail "下载二进制文件失败" + + # 检查 data 目录是否已存在,如果存在则跳过下载 + if [ -d "$INSTALL_DIR/data" ]; then + log "检测到已存在 data 目录,跳过下载以保护现有数据" + else + curl -fsSL "$data_url" -o "$tmp_dir/data.tgz" & + show_progress $! "正在下载 data 配置文件" + [ -f "$tmp_dir/data.tgz" ] || fail "下载 data 文件失败" + fi + + echo "$tmp_dir" +} + +install_binary_and_data() { + # 解压并安装二进制文件和 data 目录 + local tmp_dir extracted_dir bin_path + tmp_dir="$1" + + log "正在安装 openlist 到 $INSTALL_DIR..." + + # 尝试停止服务 + systemctl stop "$SERVICE_NAME" 2>/dev/null || true + # 检查并清理端口 + check_port + + mkdir -p "$INSTALL_DIR" + + # 只在下载了 data.tgz 时才解压 + if [ -f "$tmp_dir/data.tgz" ]; then + tar -xzf "$tmp_dir/data.tgz" -C "$INSTALL_DIR/" || fail "解压 data 目录失败" + else + log "保留现有 data 目录,不进行覆盖" + fi + + # 解压二进制文件 + extracted_dir=$(mktemp -d) + trap 'if [ -n "${tmp_dir:-}" ] && [ -d "$tmp_dir" ]; then rm -rf "$tmp_dir"; fi; if [ -n "${extracted_dir:-}" ] && [ -d "$extracted_dir" ]; then rm -rf "$extracted_dir"; fi' EXIT + tar -xzf "$tmp_dir/openlist.tar.gz" -C "$extracted_dir" || fail "解压二进制文件失败" + bin_path=$(find "$extracted_dir" -maxdepth 2 -type f -name "openlist" -perm -111 | head -n 1) + [ -n "$bin_path" ] || fail "未找到 openlist 可执行文件" + cp "$bin_path" "$INSTALL_DIR/openlist" || fail "复制可执行文件失败" + chmod +x "$INSTALL_DIR/openlist" + log "文件安装完成" +} + +write_service() { + # 写入 systemd 服务文件,默认自启动并在失败时重启 + log "正在配置 systemd 服务..." + cat > "$SERVICE_FILE" <<'EOF' +[Unit] +Description=openlist +After=network.target + +[Service] +Type=simple +User=root +Group=root +WorkingDirectory=/shumengya/bin/openlist +ExecStart=/shumengya/bin/openlist/openlist server +Restart=on-failure + +[Install] +WantedBy=multi-user.target +EOF +} + +enable_service() { + # 重新加载 systemd,设置开机自启并立即启动 + log "正在启用并启动服务..." + systemctl daemon-reload + systemctl enable "$SERVICE_NAME" + systemctl restart "$SERVICE_NAME" + + # 等待几秒钟以捕获立即崩溃的情况 + sleep 3 +} + +main() { + require_root + local arch tmp_dir="" + arch=$(detect_arch) + log "检测到系统架构: $arch" + tmp_dir=$(download_files "$arch") + install_binary_and_data "$tmp_dir" + write_service + enable_service + log "==========================================" + log "安装完成! openlist 已安装到: $INSTALL_DIR" + log "服务已启动,查看状态: systemctl status $SERVICE_NAME" + + # 检查服务状态 + if ! systemctl is-active --quiet "$SERVICE_NAME"; then + log "警告: 服务未能正常启动" + journalctl -u "$SERVICE_NAME" --no-pager -n 20 + fi + log "==========================================" +} + +main "$@" diff --git a/openlist/openlist/data.tgz b/openlist/openlist/data.tgz new file mode 100644 index 0000000..894988e Binary files /dev/null and b/openlist/openlist/data.tgz differ diff --git a/openlist/openlist/data/config.json b/openlist/openlist/data/config.json new file mode 100644 index 0000000..b99316f --- /dev/null +++ b/openlist/openlist/data/config.json @@ -0,0 +1,145 @@ +{ + "force": false, + "site_url": "", + "cdn": "", + "jwt_secret": "J4l3vzgvqQPWy1yH", + "token_expires_in": 48, + "database": { + "type": "sqlite3", + "host": "", + "port": 0, + "user": "", + "password": "", + "name": "", + "db_file": "data/data.db", + "table_prefix": "x_", + "ssl_mode": "", + "dsn": "" + }, + "meilisearch": { + "host": "http://localhost:7700", + "api_key": "", + "index": "openlist" + }, + "scheme": { + "address": "0.0.0.0", + "http_port": 5244, + "https_port": -1, + "force_https": false, + "cert_file": "", + "key_file": "", + "unix_file": "", + "unix_file_perm": "", + "enable_h2c": false, + "enable_h3": false + }, + "temp_dir": "data/temp", + "bleve_dir": "data/bleve", + "dist_dir": "", + "log": { + "enable": true, + "name": "data/log/log.log", + "max_size": 50, + "max_backups": 30, + "max_age": 28, + "compress": false, + "filter": { + "enable": false, + "filters": [ + { + "cidr": "", + "path": "/ping", + "method": "" + }, + { + "cidr": "", + "path": "", + "method": "HEAD" + }, + { + "cidr": "", + "path": "/dav/", + "method": "PROPFIND" + } + ] + } + }, + "delayed_start": 0, + "max_buffer_limitMB": -1, + "mmap_thresholdMB": 4, + "max_connections": 0, + "max_concurrency": 64, + "tls_insecure_skip_verify": true, + "tasks": { + "download": { + "workers": 5, + "max_retry": 1, + "task_persistant": false + }, + "transfer": { + "workers": 5, + "max_retry": 2, + "task_persistant": false + }, + "upload": { + "workers": 5, + "max_retry": 0, + "task_persistant": false + }, + "copy": { + "workers": 5, + "max_retry": 2, + "task_persistant": false + }, + "move": { + "workers": 5, + "max_retry": 2, + "task_persistant": false + }, + "decompress": { + "workers": 5, + "max_retry": 2, + "task_persistant": false + }, + "decompress_upload": { + "workers": 5, + "max_retry": 2, + "task_persistant": false + }, + "allow_retry_canceled": false + }, + "cors": { + "allow_origins": [ + "*" + ], + "allow_methods": [ + "*" + ], + "allow_headers": [ + "*" + ] + }, + "s3": { + "enable": false, + "port": 5246, + "ssl": false + }, + "ftp": { + "enable": false, + "listen": ":5221", + "find_pasv_port_attempts": 50, + "active_transfer_port_non_20": false, + "idle_timeout": 900, + "connection_timeout": 30, + "disable_active_mode": false, + "default_transfer_binary": false, + "enable_active_conn_ip_check": true, + "enable_pasv_conn_ip_check": true + }, + "sftp": { + "enable": false, + "listen": ":5222" + }, + "last_launched_version": "refs/heads/main", + "proxy_address": "" +} \ No newline at end of file diff --git a/openlist/openlist/data/data.db-shm b/openlist/openlist/data/data.db-shm new file mode 100644 index 0000000..7cc0c64 Binary files /dev/null and b/openlist/openlist/data/data.db-shm differ diff --git a/openlist/openlist/data/data.db-wal b/openlist/openlist/data/data.db-wal new file mode 100644 index 0000000..08e2ed6 Binary files /dev/null and b/openlist/openlist/data/data.db-wal differ diff --git a/openlist/openlist/linux-amd64.tar.gz b/openlist/openlist/linux-amd64.tar.gz new file mode 100644 index 0000000..2b92d6b Binary files /dev/null and b/openlist/openlist/linux-amd64.tar.gz differ diff --git a/openlist/openlist/linux-arm64.tar.gz b/openlist/openlist/linux-arm64.tar.gz new file mode 100644 index 0000000..ef1ced8 Binary files /dev/null and b/openlist/openlist/linux-arm64.tar.gz differ diff --git a/openlist/openlist/smy-openlist.service b/openlist/openlist/smy-openlist.service new file mode 100644 index 0000000..3b6b5c5 --- /dev/null +++ b/openlist/openlist/smy-openlist.service @@ -0,0 +1,12 @@ +[Unit] +Description=openlist +After=network.target + +[Service] +Type=simple +WorkingDirectory=/shumengya/bin/openlist +ExecStart=/shumengya/bin/openlist/openlist server +Restart=on-failure + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/openlist/start_openlist.sh b/openlist/start_openlist.sh new file mode 100644 index 0000000..7fdb450 --- /dev/null +++ b/openlist/start_openlist.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +# 恢复并启动 openlist 服务 +# 该脚本用于在执行 stopkill 后恢复服务的正常运行和开机自启 +# 用法:curl -fsSL "https://pan.shumengya.top/d/scripts/openlist/start_openlist.sh" | sudo bash + +SERVICE_NAME="smy-openlist" + +log() { printf '[openlist-启动] %s\n' "$*" >&2; } +fail() { log "错误: $*" >&2; exit 1; } + +# 检查 root 权限 +if [ "${EUID:-$(id -u)}" -ne 0 ]; then + fail "请使用 root 权限运行" +fi + +log "正在检查服务状态..." + +# 检查服务文件是否存在 +if [ ! -f "/etc/systemd/system/${SERVICE_NAME}.service" ]; then + fail "未找到服务文件 /etc/systemd/system/${SERVICE_NAME}.service,请先运行安装脚本。" +fi + +log "正在恢复服务设置..." +# 重置可能的失败状态 +systemctl reset-failed "$SERVICE_NAME" 2>/dev/null || true + +log "正在启用并启动服务..." +# --now 选项会同时启用(enable)并启动(start)服务 +systemctl enable --now "$SERVICE_NAME" + +# 等待服务启动 +sleep 2 + +# 检查启动状态 +if systemctl is-active --quiet "$SERVICE_NAME"; then + log "服务启动成功!" + log "状态: $(systemctl is-active "$SERVICE_NAME")" + log "您可以访问 http://IP:5244 使用服务" +else + log "警告: 服务启动似乎遇到了问题" + log "以下是最后 10 行日志:" + systemctl status "$SERVICE_NAME" --no-pager -n 10 || true + exit 1 +fi diff --git a/openlist/stopkill_openlist.sh b/openlist/stopkill_openlist.sh new file mode 100644 index 0000000..6a69e73 --- /dev/null +++ b/openlist/stopkill_openlist.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -euo pipefail + +# 强制停止 openlist 服务并清理进程 +# 用法:curl -fsSL "https://pan.shumengya.top/d/scripts/openlist/stopkill_openlist.sh" | sudo bash + +SERVICE_NAME="smy-openlist" +BIN_NAME="openlist" +PORT=5244 + +log() { printf '[openlist-停止] %s\n' "$*" >&2; } + +if [ "${EUID:-$(id -u)}" -ne 0 ]; then + log "请使用 root 权限运行" + exit 1 +fi + +log "正在停止 systemd 服务..." +# systemctl stop 会将服务状态置为 inactive,systemd 不会自动重启它,除非手动 start/restart +# 即使服务被 disable,systemctl restart 仍然可以启动它 +systemctl disable --now "$SERVICE_NAME" 2>/dev/null || true +systemctl stop "$SERVICE_NAME" 2>/dev/null || true + +log "正在检查残留进程..." +# 排除当前脚本自身的 PID,防止误杀 +current_pid=$$ + +# 按进程名强制杀 (使用 -x 精确匹配进程名,避免匹配到脚本自身) +pids=$(pgrep -x "$BIN_NAME" || true) +# 如果 -x 没找到,尝试 -f 但过滤掉脚本自身 +if [ -z "$pids" ]; then + pids=$(pgrep -f "$BIN_NAME" | grep -v "$current_pid" || true) +fi + +if [ -n "$pids" ]; then + log "发现残留进程 PID: $pids,正在强制终止..." + kill -9 $pids 2>/dev/null || true +fi + +# 按端口强制杀 +pid_port="" +if command -v lsof >/dev/null 2>&1; then + pid_port=$(lsof -t -i:$PORT 2>/dev/null || true) +elif command -v ss >/dev/null 2>&1; then + # ss 输出格式处理,提取 pid + pid_port=$(ss -lptn "sport = :$PORT" | grep -oE 'pid=[0-9]+' | cut -d= -f2 | sort -u || true) +elif command -v netstat >/dev/null 2>&1; then + pid_port=$(netstat -nlp | grep ":$PORT " | awk '{print $7}' | cut -d/ -f1 || true) +fi + +if [ -n "$pid_port" ]; then + # 再次过滤掉当前 PID (虽然不太可能占用端口,但为了安全) + pid_port=$(echo "$pid_port" | grep -v "^$current_pid$") + if [ -n "$pid_port" ]; then + log "发现端口 $PORT 占用进程 PID: $pid_port,正在强制终止..." + kill -9 $pid_port 2>/dev/null || true + fi +fi + +# 重置服务失败状态,避免 systemd 认为服务处于错误状态 +systemctl reset-failed "$SERVICE_NAME" 2>/dev/null || true + +# 最终状态检查 +log "正在验证服务状态..." +if pgrep -x "$BIN_NAME" >/dev/null; then + log "警告: 进程仍在运行!" + ps -fp $(pgrep -x "$BIN_NAME") +else + log "openlist 已完全停止 (服务已禁用,进程已清理)。" +fi diff --git a/openlist/uninstall_openlist.sh b/openlist/uninstall_openlist.sh new file mode 100644 index 0000000..1fcf898 --- /dev/null +++ b/openlist/uninstall_openlist.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +set -euo pipefail + +# openlist 一键卸载脚本 +# 用法:sudo bash uninstall_openlist.sh + +INSTALL_DIR="/shumengya/bin/openlist" +SERVICE_NAME="smy-openlist" +SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" + +log() { printf '[openlist-卸载] %s\n' "$*" >&2; } +fail() { log "错误: $*" >&2; exit 1; } + +# 进度条函数 +show_progress() { + local pid=$1 + local text=$2 + local delay=0.1 + local spin='-\|/' + + printf "[openlist-卸载] %s... " "$text" >&2 + + while ps -p "$pid" > /dev/null 2>&1; do + local temp=${spin#?} + printf "\b%c" "$spin" >&2 + local spin=$temp${spin%"$temp"} + sleep $delay + done + printf "\b完成\n" >&2 +} + +require_root() { + # 必须使用 root 权限执行 + if [ "${EUID:-$(id -u)}" -ne 0 ]; then + fail "请使用 root 权限运行 (sudo bash uninstall_openlist.sh)" + fi +} + +stop_and_disable_service() { + # 停止并禁用 systemd 服务 + if systemctl is-active --quiet "$SERVICE_NAME"; then + log "正在停止服务 $SERVICE_NAME..." + systemctl stop "$SERVICE_NAME" + fi + + if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null; then + log "正在禁用服务 $SERVICE_NAME..." + systemctl disable "$SERVICE_NAME" + fi +} + +remove_service_file() { + # 删除 systemd 服务文件 + if [ -f "$SERVICE_FILE" ]; then + log "正在删除服务文件..." + rm -f "$SERVICE_FILE" + systemctl daemon-reload + fi +} + +remove_install_dir() { + # 删除安装目录 + if [ -d "$INSTALL_DIR" ]; then + log "正在删除安装目录 $INSTALL_DIR..." + rm -rf "$INSTALL_DIR" + fi +} + +check_and_kill_port() { + local port=5244 + if lsof -i :$port >/dev/null 2>&1 || netstat -tunlp | grep -q ":$port "; then + log "检测到端口 $port 仍被占用,尝试强制清理..." + fuser -k -n tcp $port >/dev/null 2>&1 || true + sleep 1 + # 二次检查 + local pid + pid=$(lsof -t -i:$port 2>/dev/null || true) + if [ -n "$pid" ]; then + kill -9 "$pid" 2>/dev/null || true + fi + fi +} + +main() { + require_root + + log "开始卸载 openlist..." + (stop_and_disable_service) & + show_progress $! "正在停止服务" + + (remove_service_file) & + show_progress $! "正在删除服务文件" + + check_and_kill_port + + (remove_install_dir) & + show_progress $! "正在删除安装目录" + + log "==========================================" + log "卸载完成! openlist 已从系统中移除" + log "==========================================" +} + +main "$@" diff --git a/port-info/AGENTS.md b/port-info/AGENTS.md new file mode 100644 index 0000000..171174d --- /dev/null +++ b/port-info/AGENTS.md @@ -0,0 +1,201 @@ +# AGENTS.md - Agent Coding Guidelines + +This document provides guidelines for agents working in this repository. + +## Project Overview + +This is a **Bash shell script** project for displaying Linux port information (TCP, UDP, HTTP services). The main file is `port_info.sh`. + +## Build / Lint / Test Commands + +### Running the Script +```bash +# Make executable and run +chmod +x port_info.sh +./port_info.sh + +# Or run directly with bash +bash port_info.sh +``` + +### Linting +Use **shellcheck** for static analysis: +```bash +# Install shellcheck (if not present) +apt-get install shellcheck # Debian/Ubuntu +yum install epel-release && yum install ShellCheck # RHEL/CentOS + +# Run shellcheck on the script +shellcheck port_info.sh + +# Run with specific severity levels +shellcheck -S error port_info.sh # Errors only +shellcheck -S warning port_info.sh # Warnings and errors +``` + +### Testing a Single Function +Bash doesn't have traditional unit tests, but you can test functions interactively: +```bash +# Source the script and test specific functions +source port_info.sh +get_service_name 80 # Test port-to-service lookup +check_commands # Test command detection +``` + +### Syntax Validation +```bash +# Check bash syntax without executing +bash -n port_info.sh +``` + +## Code Style Guidelines + +### File Organization +- Single script files for small utilities +- Use clear section separators: `#===============================================================================` +- Group related functions together +- Main execution at the bottom of the file + +### Formatting +- Indentation: 4 spaces +- Use `#!/bin/bash` shebang (not `#!/bin/sh` for bash-specific features) +- Maximum line length: ~100 characters (flexible for output formatting) +- Use uppercase for constants/variables, lowercase for function names + +### Variable Naming +- Constants (colors, separators): UPPERCASE with underscores, e.g., `RED`, `SEPARATOR` +- Global variables: UPPERCASE, e.g., `PORT_CMD` +- Local variables in functions: lowercase with underscores, e.g., `local port=$1` +- Function names: lowercase with underscores, e.g., `check_commands()` + +### Functions +```bash +# Good function definition +function_name() { + local arg1=$1 + local arg2=$2 + + # function body + + return 0 # Always return explicit status +} + +# Or with function keyword +check_commands() { + # ... +} +``` + +### Color Variables +Define colors at the top of the script using ANSI escape codes: +```bash +RED='\033[38;5;196m' +GREEN='\033[38;5;46m' +NC='\033[0m' # No Color - always reset at end +``` + +### Error Handling +- Use `command -v` to check command availability +- Redirect stderr with `2>/dev/null` for expected errors +- Exit with status 1 on fatal errors: `exit 1` +- Use descriptive error messages with colors + +### Input Handling +- Prefer arguments over interactive input +- Validate inputs before processing +- Use `local` for all function parameters +- Check for required arguments + +### String Comparisons +```bash +# String equality +if [ "$var" = "value" ]; then + # ... +fi + +# Numeric comparison +if [ "$num" -eq 0 ]; then + # ... +fi + +# Regex matching +if [[ "$port" =~ ^[0-9]+$ ]]; then + # ... +fi +``` + +### Output Formatting +- Use `printf` for formatted output (not `echo` for complex output) +- Use color codes with `${COLOR}...${NC}` pattern +- Consistent column widths in tables + +### Common Patterns + +#### Command Availability Check +```bash +if command -v ss &> /dev/null; then + PORT_CMD="ss" +elif command -v netstat &> /dev/null; then + PORT_CMD="netstat" +else + echo -e "${RED}Error: command not found${NC}" + exit 1 +fi +``` + +#### Reading Lines +```bash +while IFS= read -r line; do + # process line +done < <(command) +``` + +#### Safe Variable Usage +- Always quote variables: `"$var"` not `$var` +- Use `${var}` for clarity in complex expressions +- Initialize variables before use + +### Shellcheck Compliance +Run `shellcheck` and fix all warnings: +- SC2086: Quote variables to prevent word splitting +- SC2166: Use `&&` instead of `-a` in test expressions +- SC2027: Quote strings containing newlines +- SC2248: Prefer printf over echo + +## File Extensions +- Bash scripts: `.sh` +- No extension for executable scripts (optional) + +## Documentation +- Add Chinese comments for Chinese-language projects +- Use section headers: `#===============================================================================` +- Document function purpose before definition +- Include usage information in comments + +## Dependencies +This script requires: +- `ss` or `netstat net` (from-tools package) +- Standard Linux utilities: `awk`, `grep`, `sed`, `sort`, `uniq` + +## Common Tasks + +### Adding a New Port Service +Edit `get_service_name()` function in `port_info.sh`: +```bash +get_service_name() { + local port=$1 + case $port in + 80) echo "HTTP" ;; + 443) echo "HTTPS" ;; + 3306) echo "MySQL" ;; + # Add new port here + 9000) echo "PHP-FPM" ;; + *) echo "未知" ;; + esac +} +``` + +### Adding a New Display Section +1. Create a new function following existing patterns +2. Add function call in `main()` +3. Use consistent color scheme and formatting diff --git a/port-info/port_info.sh b/port-info/port_info.sh new file mode 100755 index 0000000..aa8094e --- /dev/null +++ b/port-info/port_info.sh @@ -0,0 +1,260 @@ +#!/bin/bash + +#=============================================================================== +# Linux 端口信息查看脚本 +# 兼容: Ubuntu / Debian 及衍生版 +# 功能: 显示 TCP、UDP、HTTP 端口服务信息 +#=============================================================================== + +## +RED='\033[38;5;196m' +GREEN='\033[38;5;46m' +YELLOW='\033[38;5;226m' +BLUE='\033[38;5;21m' +MAGENTA='\033[38;5;201m' +CYAN='\033[38;5;51m' +WHITE='\033[38;5;255m' +ORANGE='\033[38;5;208m' +PINK='\033[38;5;219m' +LIME='\033[38;5;154m' +PURPLE='\033[38;5;141m' +GOLD='\033[38;5;220m' +GRAY='\033[38;5;244m' +NC='\033[0m' + +SEPARATOR="━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + +#=============================================================================== +check_commands() { + # echo -e "${CYAN}▸ 检测命令...${NC}" + + if command -v ss &> /dev/null; then + PORT_CMD="ss" + elif command -v netstat &> /dev/null; then + PORT_CMD="netstat" + else + echo -e "${RED}✗ 错误: 未找到 ss 或 netstat 命令${NC}" + echo -e "${YELLOW} 请安装: apt-get install net-tools${NC}" + exit 1 + fi + + # echo -e "${GREEN}✓ 使用命令: ${PORT_CMD}${NC}" +} + +#=============================================================================== + +## +get_service_name() { + local port=$1 + case $port in + 20) echo "FTP-DATA" ;; + 21) echo "FTP" ;; + 22) echo "SSH" ;; + 23) echo "Telnet" ;; + 25) echo "SMTP" ;; + 53) echo "DNS" ;; + 67|68) echo "DHCP" ;; + 80) echo "HTTP" ;; + 110) echo "POP3" ;; + 123) echo "NTP" ;; + 443) echo "HTTPS" ;; + 3306) echo "MySQL" ;; + 3389) echo "RDP" ;; + 5432) echo "PostgreSQL" ;; + 6379) echo "Redis" ;; + 8080) echo "HTTP-Proxy" ;; + 8443) echo "HTTPS-Alt" ;; + 27017) echo "MongoDB" ;; + *) echo "未知" ;; + esac +} + +#=============================================================================== +show_tcp_ports() { + echo -e "\n${SEPARATOR}" + echo -e "${BLUE} 🔵 TCP 端口监听列表 ${NC}" + echo -e "${SEPARATOR}" + printf "${GREEN}%-6s %-10s %-14s %-10s %-20s${NC}\n" "协议" "端口" "服务(参考)" "PID" "进程名称" + echo -e "${GRAY}──────────────────────────────────────────────────────────────────────────────${NC}" + + if [ "$PORT_CMD" = "ss" ]; then + ss -tulnp 2>/dev/null | grep LISTEN | while IFS= read -r line; do + addr=$(echo "$line" | awk '{print $5}') + port="${addr##*:}" + [[ "$port" =~ ^[0-9]+$ ]] || continue + + prog_field=$(echo "$line" | awk '{print $NF}') + pid=$(echo "$prog_field" | grep -oP 'pid=\K[0-9]+' | head -1) + name=$(echo "$prog_field" | sed -n 's/.*("\([^"]*\)".*/\1/p' | head -1) + + [ -z "$pid" ] && pid="-" + [ -z "$name" ] && name="-" + + service=$(get_service_name "$port") + printf "TCP|%-10s|%-14s|%-10s|%-20s\n" "$port" "$service" "$pid" "$name" + done | sort -t'|' -k2 -n | uniq | while IFS='|' read -r p s rv pi n; do + printf "${LIME}%-6s${NC} %-10s${NC} %-14s${NC} %-10s${NC} %-20s${NC}\n" "$p" "$s" "$rv" "$pi" "$n" + done + else + netstat -tulnp 2>/dev/null | grep LISTEN | while read -r line; do + port=$(echo "$line" | awk '{split($4,a,":"); print a[length(a)]}') + [[ "$port" =~ ^[0-9]+$ ]] || continue + + prog=$(echo "$line" | awk '{print $NF}') + pid=$(echo "$prog" | cut -d'/' -f1) + name=$(echo "$prog" | cut -d'/' -f2 | cut -d' ' -f1) + + [ -z "$pid" ] && pid="-" + [ -z "$name" ] && name="-" + + service=$(get_service_name "$port") + printf "TCP|%-10s|%-14s|%-10s|%-20s\n" "$port" "$service" "$pid" "$name" + done | sort -t'|' -k2 -n | uniq | while IFS='|' read -r p s rv pi n; do + printf "${LIME}%-6s${NC} %-10s${NC} %-14s${NC} %-10s${NC} %-20s${NC}\n" "TCP" "$p" "$s" "$pi" "$n" + done + fi + + echo -e "${GRAY}──────────────────────────────────────────────────────────────────────────────${NC}" +} + +#=============================================================================== +show_udp_ports() { + echo -e "\n${SEPARATOR}" + echo -e "${MAGENTA} 🟣 UDP 端口监听列表 ${NC}" + echo -e "${SEPARATOR}" + printf "${PINK}%-6s %-10s %-14s %-10s %-20s${NC}\n" "协议" "端口" "服务(参考)" "PID" "进程名称" + echo -e "${GRAY}──────────────────────────────────────────────────────────────────────────────${NC}" + + if [ "$PORT_CMD" = "ss" ]; then + ss -ulnp 2>/dev/null | awk 'NR>1 && $1!="State"' | while IFS= read -r line; do + addr=$(echo "$line" | awk '{print $4}') + port="${addr##*:}" + [[ "$port" =~ ^[0-9]+$ ]] || continue + + prog_field=$(echo "$line" | awk '{print $NF}') + pid=$(echo "$prog_field" | grep -oP 'pid=\K[0-9]+' | head -1) + name=$(echo "$prog_field" | sed -n 's/.*("\([^"]*\)".*/\1/p' | head -1) + + [ -z "$pid" ] && pid="-" + [ -z "$name" ] && name="-" + + service=$(get_service_name "$port") + printf "UDP|%-10s|%-14s|%-10s|%-20s\n" "$port" "$service" "$pid" "$name" + done | sort -t'|' -k2 -n | uniq | while IFS='|' read -r p s rv pi n; do + printf "${LIME}%-6s${NC} %-10s${NC} %-14s${NC} %-10s${NC} %-20s${NC}\n" "$p" "$s" "$rv" "$pi" "$n" + done + else + netstat -ulnp 2>/dev/null | awk 'NR>1' | while read -r line; do + port=$(echo "$line" | awk '{split($4,a,":"); print a[length(a)]}') + [[ "$port" =~ ^[0-9]+$ ]] || continue + + prog=$(echo "$line" | awk '{print $NF}') + pid=$(echo "$prog" | cut -d'/' -f1) + name=$(echo "$prog" | cut -d'/' -f2 | cut -d' ' -f1) + + [ -z "$pid" ] && pid="-" + [ -z "$name" ] && name="-" + + service=$(get_service_name "$port") + printf "UDP|%-10s|%-14s|%-10s|%-20s\n" "$port" "$service" "$pid" "$name" + done | sort -t'|' -k2 -n | uniq | while IFS='|' read -r p s rv pi n; do + printf "${LIME}%-6s${NC} %-10s${NC} %-14s${NC} %-10s${NC} %-20s${NC}\n" "$p" "$s" "$rv" "$pi" "$n" + done + fi + + echo -e "${GRAY}──────────────────────────────────────────────────────────────────────────────${NC}" +} + +#=============================================================================== +show_http_ports() { + echo -e "\n${SEPARATOR}" + echo -e "${YELLOW} 🟡 HTTP/HTTPS 常用端口 ${NC}" + echo -e "${SEPARATOR}" + printf "${ORANGE}%-6s %-10s %-14s %-10s %-10s %-20s${NC}\n" "协议" "端口" "服务(参考)" "状态" "PID" "进程名称" + echo -e "${GRAY}────────────────────────────────────────────────────────────────────────────────────────${NC}" + + http_ports="80 443 8080 8443 8000 8888 3000 5000" + + for port in $http_ports; do + if [ "$PORT_CMD" = "ss" ]; then + result=$(ss -tulnp 2>/dev/null | grep ":$port " | grep -v grep) + if [ -n "$result" ]; then + proto=$(echo "$result" | awk '{print $1}' | head -1 | tr '[:upper:]' '[:lower:]') + prog_field=$(echo "$result" | awk '{print $NF}') + pid=$(echo "$prog_field" | grep -oP 'pid=\K[0-9]+' | head -1) + name=$(echo "$prog_field" | sed -n 's/.*("\([^"]*\)".*/\1/p' | head -1) + + [ -z "$pid" ] && pid="-" + [ -z "$name" ] && name="-" + + service=$(get_service_name "$port") + + printf "${LIME}%-6s${NC} %-10s${NC} %-14s${NC} %-10s${NC} %-10s${NC} %-20s${NC}\n" "$proto" "$port" "$service" "监听中" "$pid" "$name" + fi + else + result=$(netstat -tulnp 2>/dev/null | grep ":$port " | grep -v grep) + if [ -n "$result" ]; then + proto=$(echo "$result" | awk '{print $6}' | head -1 | tr '[:upper:]' '[:lower:]') + prog=$(echo "$result" | awk '{print $7}') + pid=$(echo "$prog" | cut -d'/' -f1) + name=$(echo "$prog" | cut -d'/' -f2 | cut -d' ' -f1) + + [ -z "$pid" ] && pid="-" + [ -z "$name" ] && name="-" + + service=$(get_service_name "$port") + + printf "${LIME}%-6s${NC} %-10s${NC} %-14s${NC} %-10s${NC} %-10s${NC} %-20s${NC}\n" "$proto" "$port" "$service" "监听中" "$pid" "$name" + fi + fi + done + + echo -e "${GRAY}────────────────────────────────────────────────────────────────────────────────────────${NC}" + echo -e "${GRAY}※ 服务(参考) 列为常用端口的默认服务名称,仅供参考,实际占用程序以进程名称列为准${NC}" +} + +#=============================================================================== +show_statistics() { + echo -e "\n${SEPARATOR}" + echo -e "${CYAN} 📊 端口统计信息 ${NC}" + echo -e "${SEPARATOR}" + + if [ "$PORT_CMD" = "ss" ]; then + tcp_count=$(ss -tuln 2>/dev/null | grep -c LISTEN) + udp_count=$(ss -uln 2>/dev/null | awk 'NR>1 && $1 != "State" && /:[0-9]+/ {print}' | wc -l) + else + tcp_count=$(netstat -tuln 2>/dev/null | grep -c LISTEN) + udp_count=$(netstat -uln 2>/dev/null | awk 'NR>1 && /:[0-9]+/ {print}' | wc -l) + fi + + total=$((tcp_count + udp_count)) + + printf " ${BLUE}TCP 监听端口:${NC} ${GREEN}%d${NC}\n" "$tcp_count" + printf " ${MAGENTA}UDP 监听端口:${NC} ${GREEN}%d${NC}\n" "$udp_count" + printf " ${YELLOW}总 计:${NC} ${ORANGE}%d${NC}\n" "$total" +} + +#=============================================================================== +show_header() { + clear + echo -e "" + echo -e "${SEPARATOR}" + echo -e "${PURPLE} ║ Linux 系统端口信息查看工具${NC}" + echo -e "${SEPARATOR}" + echo -e " ${GOLD}▸ 兼容系统:${NC} ${WHITE}Ubuntu / Debian 及衍生版本${NC}" + echo -e " ${GOLD}▸ 生成时间:${NC} ${WHITE}$(date '+%Y-%m-%d %H:%M:%S')${NC}" + echo -e "${SEPARATOR}" +} + +#=============================================================================== +main() { + show_header + check_commands + show_tcp_ports + show_udp_ports + show_http_ports + show_statistics + +} + +main diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/ssh/alycd.sh b/ssh/alycd.sh new file mode 100644 index 0000000..1f9fee2 --- /dev/null +++ b/ssh/alycd.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# ssh_connect_embedded.sh +# 在脚本内直接写明密码(仅在你确认在安全内网且风险可接受时使用) +# Usage: ./bigmengya.sh [user] [host] [port] +# Example: ./bigmengya.sh alice 10.0.0.5 22 + +set -euo pipefail + +# ------------------------- +# << 在这里修改密码等配置 >> +# ------------------------- +USER="root" # 可通过第一个参数覆盖 +HOST="47.108.90.0" # 可通过第二个参数覆盖 +PORT="22" # 可通过第三个参数覆盖 +PASSWORD="tyh@19900420" +# ------------------------- +# 结束配置 +# ------------------------- + +# 小安全缓解措施 +umask 077 # 新创建文件仅对当前用户可读写 +trap 'unset PASSWORD' EXIT INT TERM # 退出时尝试清除变量 + +# 可选:如果想在调用时强制使用脚本内的 USER/HOST 而不允许参数覆盖, +# 请把上面 USER/HOST 赋值方式改为固定字面量。 + +# 检查 sshpass 是否存在 +if ! command -v sshpass >/dev/null 2>&1; then + echo "错误:找不到 sshpass。请安装后重试。例如 Debian/Ubuntu: sudo apt install sshpass" + exit 2 +fi + +# 连接(禁用第一次主机密钥交互以便脚本自动连接) +# 如果你希望每次确认主机密钥,可以去掉 -o StrictHostKeyChecking=no +# 添加以下选项: +# -o PreferredAuthentications=password 强制使用密码认证 +# -o PubkeyAuthentication=no 禁用公钥认证 +# -o PasswordAuthentication=yes 启用密码认证 +# -t 强制分配伪终端(解决curl|bash问题) +sshpass -p "$PASSWORD" ssh -t \ + -o StrictHostKeyChecking=no \ + -o PreferredAuthentications=password \ + -o PubkeyAuthentication=no \ + -o PasswordAuthentication=yes \ + -p "$PORT" "$USER@$HOST" + +# 在脚本尾尝试清理(再次) +unset PASSWORD \ No newline at end of file diff --git a/ssh/alyxg.sh b/ssh/alyxg.sh new file mode 100644 index 0000000..262e9a4 --- /dev/null +++ b/ssh/alyxg.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# ssh_connect_embedded.sh +# 在脚本内直接写明密码(仅在你确认在安全内网且风险可接受时使用) +# Usage: ./bigmengya.sh [user] [host] [port] +# Example: ./bigmengya.sh alice 10.0.0.5 22 + +set -euo pipefail + +# ------------------------- +# << 在这里修改密码等配置 >> +# ------------------------- +USER="root" # 可通过第一个参数覆盖 +HOST="47.76.191.104" # 可通过第二个参数覆盖 +PORT="22" # 可通过第三个参数覆盖 +PASSWORD="tyh@19900420" +# ------------------------- +# 结束配置 +# ------------------------- + +# 小安全缓解措施 +umask 077 # 新创建文件仅对当前用户可读写 +trap 'unset PASSWORD' EXIT INT TERM # 退出时尝试清除变量 + +# 可选:如果想在调用时强制使用脚本内的 USER/HOST 而不允许参数覆盖, +# 请把上面 USER/HOST 赋值方式改为固定字面量。 + +# 检查 sshpass 是否存在 +if ! command -v sshpass >/dev/null 2>&1; then + echo "错误:找不到 sshpass。请安装后重试。例如 Debian/Ubuntu: sudo apt install sshpass" + exit 2 +fi + +# 连接(禁用第一次主机密钥交互以便脚本自动连接) +# 如果你希望每次确认主机密钥,可以去掉 -o StrictHostKeyChecking=no +# 添加以下选项: +# -o PreferredAuthentications=password 强制使用密码认证 +# -o PubkeyAuthentication=no 禁用公钥认证 +# -o PasswordAuthentication=yes 启用密码认证 +# -t 强制分配伪终端(解决curl|bash问题) +sshpass -p "$PASSWORD" ssh -t \ + -o StrictHostKeyChecking=no \ + -o PreferredAuthentications=password \ + -o PubkeyAuthentication=no \ + -o PasswordAuthentication=yes \ + -p "$PORT" "$USER@$HOST" + +# 在脚本尾尝试清理(再次) +unset PASSWORD \ No newline at end of file diff --git a/ssh/bigmengya.sh b/ssh/bigmengya.sh new file mode 100644 index 0000000..77b8333 --- /dev/null +++ b/ssh/bigmengya.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# ssh_connect_embedded.sh +# 在脚本内直接写明密码(仅在你确认在安全内网且风险可接受时使用) +# Usage: ./bigmengya.sh [user] [host] [port] +# Example: ./bigmengya.sh alice 10.0.0.5 22 + +set -euo pipefail + +# ------------------------- +# << 在这里修改密码等配置 >> +# ------------------------- +USER="root" # 可通过第一个参数覆盖 +HOST="10.0.0.233" # 可通过第二个参数覆盖 +PORT="22" # 可通过第三个参数覆盖 +PASSWORD="tyh@19900420" +# ------------------------- +# 结束配置 +# ------------------------- + +# 小安全缓解措施 +umask 077 # 新创建文件仅对当前用户可读写 +trap 'unset PASSWORD' EXIT INT TERM # 退出时尝试清除变量 + +# 可选:如果想在调用时强制使用脚本内的 USER/HOST 而不允许参数覆盖, +# 请把上面 USER/HOST 赋值方式改为固定字面量。 + +# 检查 sshpass 是否存在 +if ! command -v sshpass >/dev/null 2>&1; then + echo "错误:找不到 sshpass。请安装后重试。例如 Debian/Ubuntu: sudo apt install sshpass" + exit 2 +fi + +# 连接(禁用第一次主机密钥交互以便脚本自动连接) +# 如果你希望每次确认主机密钥,可以去掉 -o StrictHostKeyChecking=no +# 添加以下选项: +# -o PreferredAuthentications=password 强制使用密码认证 +# -o PubkeyAuthentication=no 禁用公钥认证 +# -o PasswordAuthentication=yes 启用密码认证 +# -t 强制分配伪终端(解决curl|bash问题) +sshpass -p "$PASSWORD" ssh -t \ + -o StrictHostKeyChecking=no \ + -o PreferredAuthentications=password \ + -o PubkeyAuthentication=no \ + -o PasswordAuthentication=yes \ + -p "$PORT" "$USER@$HOST" + +# 在脚本尾尝试清理(再次) +unset PASSWORD \ No newline at end of file diff --git a/ssh/mengyathree.sh b/ssh/mengyathree.sh new file mode 100644 index 0000000..b918bb8 --- /dev/null +++ b/ssh/mengyathree.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# ssh_connect_embedded.sh +# 在脚本内直接写明密码(仅在你确认在安全内网且风险可接受时使用) +# Usage: ./bigmengya.sh [user] [host] [port] +# Example: ./bigmengya.sh alice 10.0.0.5 22 + +set -euo pipefail + +# ------------------------- +# << 在这里修改密码等配置 >> +# ------------------------- +USER="root" # 可通过第一个参数覆盖 +HOST="10.0.0.33" # 可通过第二个参数覆盖 +PORT="22" # 可通过第三个参数覆盖 +PASSWORD="tyh@19900420" +# ------------------------- +# 结束配置 +# ------------------------- + +# 小安全缓解措施 +umask 077 # 新创建文件仅对当前用户可读写 +trap 'unset PASSWORD' EXIT INT TERM # 退出时尝试清除变量 + +# 可选:如果想在调用时强制使用脚本内的 USER/HOST 而不允许参数覆盖, +# 请把上面 USER/HOST 赋值方式改为固定字面量。 + +# 检查 sshpass 是否存在 +if ! command -v sshpass >/dev/null 2>&1; then + echo "错误:找不到 sshpass。请安装后重试。例如 Debian/Ubuntu: sudo apt install sshpass" + exit 2 +fi + +# 连接(禁用第一次主机密钥交互以便脚本自动连接) +# 如果你希望每次确认主机密钥,可以去掉 -o StrictHostKeyChecking=no +# 添加以下选项: +# -o PreferredAuthentications=password 强制使用密码认证 +# -o PubkeyAuthentication=no 禁用公钥认证 +# -o PasswordAuthentication=yes 启用密码认证 +# -t 强制分配伪终端(解决curl|bash问题) +sshpass -p "$PASSWORD" ssh -t \ + -o StrictHostKeyChecking=no \ + -o PreferredAuthentications=password \ + -o PubkeyAuthentication=no \ + -o PasswordAuthentication=yes \ + -p "$PORT" "$USER@$HOST" + +# 在脚本尾尝试清理(再次) +unset PASSWORD \ No newline at end of file diff --git a/ssh/redmi.sh b/ssh/redmi.sh new file mode 100644 index 0000000..84c4b9e --- /dev/null +++ b/ssh/redmi.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# ssh_connect_embedded.sh +# 在脚本内直接写明密码(仅在你确认在安全内网且风险可接受时使用) +# Usage: ./bigmengya.sh [user] [host] [port] +# Example: ./bigmengya.sh alice 10.0.0.5 22 + +set -euo pipefail + +# ------------------------- +# << 在这里修改密码等配置 >> +# ------------------------- +USER="root" # 可通过第一个参数覆盖 +HOST="10.0.0.10" # 可通过第二个参数覆盖 +PORT="22" # 可通过第三个参数覆盖 +PASSWORD="tyh@19900420" +# ------------------------- +# 结束配置 +# ------------------------- + +# 小安全缓解措施 +umask 077 # 新创建文件仅对当前用户可读写 +trap 'unset PASSWORD' EXIT INT TERM # 退出时尝试清除变量 + +# 可选:如果想在调用时强制使用脚本内的 USER/HOST 而不允许参数覆盖, +# 请把上面 USER/HOST 赋值方式改为固定字面量。 + +# 检查 sshpass 是否存在 +if ! command -v sshpass >/dev/null 2>&1; then + echo "错误:找不到 sshpass。请安装后重试。例如 Debian/Ubuntu: sudo apt install sshpass" + exit 2 +fi + +# 连接(禁用第一次主机密钥交互以便脚本自动连接) +# 如果你希望每次确认主机密钥,可以去掉 -o StrictHostKeyChecking=no +# 添加以下选项: +# -o PreferredAuthentications=password 强制使用密码认证 +# -o PubkeyAuthentication=no 禁用公钥认证 +# -o PasswordAuthentication=yes 启用密码认证 +# -t 强制分配伪终端(解决curl|bash问题) +sshpass -p "$PASSWORD" ssh -t \ + -o StrictHostKeyChecking=no \ + -o PreferredAuthentications=password \ + -o PubkeyAuthentication=no \ + -o PasswordAuthentication=yes \ + -p "$PORT" "$USER@$HOST" + +# 在脚本尾尝试清理(再次) +unset PASSWORD \ No newline at end of file diff --git a/ssh/smallmengya.sh b/ssh/smallmengya.sh new file mode 100644 index 0000000..43149f6 --- /dev/null +++ b/ssh/smallmengya.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# ssh_connect_embedded.sh +# 在脚本内直接写明密码(仅在你确认在安全内网且风险可接受时使用) +# Usage: ./bigmengya.sh [user] [host] [port] +# Example: ./bigmengya.sh alice 10.0.0.5 22 + +set -euo pipefail + +# ------------------------- +# << 在这里修改密码等配置 >> +# ------------------------- +USER="root" # 可通过第一个参数覆盖 +HOST="10.0.0.100" # 可通过第二个参数覆盖 +PORT="22" # 可通过第三个参数覆盖 +PASSWORD="tyh@19900420" +# ------------------------- +# 结束配置 +# ------------------------- + +# 小安全缓解措施 +umask 077 # 新创建文件仅对当前用户可读写 +trap 'unset PASSWORD' EXIT INT TERM # 退出时尝试清除变量 + +# 可选:如果想在调用时强制使用脚本内的 USER/HOST 而不允许参数覆盖, +# 请把上面 USER/HOST 赋值方式改为固定字面量。 + +# 检查 sshpass 是否存在 +if ! command -v sshpass >/dev/null 2>&1; then + echo "错误:找不到 sshpass。请安装后重试。例如 Debian/Ubuntu: sudo apt install sshpass" + exit 2 +fi + +# 连接(禁用第一次主机密钥交互以便脚本自动连接) +# 如果你希望每次确认主机密钥,可以去掉 -o StrictHostKeyChecking=no +# 添加以下选项: +# -o PreferredAuthentications=password 强制使用密码认证 +# -o PubkeyAuthentication=no 禁用公钥认证 +# -o PasswordAuthentication=yes 启用密码认证 +# -t 强制分配伪终端(解决curl|bash问题) +sshpass -p "$PASSWORD" ssh -t \ + -o StrictHostKeyChecking=no \ + -o PreferredAuthentications=password \ + -o PubkeyAuthentication=no \ + -o PasswordAuthentication=yes \ + -p "$PORT" "$USER@$HOST" + +# 在脚本尾尝试清理(再次) +unset PASSWORD \ No newline at end of file diff --git a/systemctl-info/AGENTS.md b/systemctl-info/AGENTS.md new file mode 100644 index 0000000..8056b4a --- /dev/null +++ b/systemctl-info/AGENTS.md @@ -0,0 +1,67 @@ +# AGENTS.md - iFlow CLI 项目指南 + +## 项目概述 + +这是一个 **systemctl 详细信息查看脚本** (v2.0 模块化版本),用于在 Linux 系统中显示 Systemd 相关的全面信息。 + +### 项目类型 +- **语言**: Bash Shell 脚本 +- **平台**: Linux +- **版本**: 2.0 (模块化版本) +- **用途**: 系统管理、信息查看 + +### 模块化结构 + +脚本已重构为 22 个独立的功能模块,每个模块对应一个 `module_xxx()` 函数: + +| 模块编号 | 模块名称 | 功能描述 | +|---------|---------|---------| +| 1 | `module_systemd_version` | Systemd 版本信息 | +| 2 | `module_system_info` | 系统基础信息 (主机名、内核、OS等) | +| 3 | `module_systemd_status` | Systemd 系统状态 | +| 4 | `module_service_stats` | 服务统计信息 | +| 5 | `module_failed_services` | 失败的服务详情 | +| 6 | `module_masked_services` | 已屏蔽(Masked)的服务 | +| 7 | `module_running_services` | 运行中的服务列表 | +| 8 | `module_timer` | Timer 定时任务 | +| 9 | `module_socket` | Socket 监听单元 | +| 10 | `module_target` | Target 目标单元 | +| 11 | `module_mount` | Mount 和 Automount 挂载点 | +| 12 | `module_path` | Path 路径监控单元 (新增) | +| 13 | `module_device` | Device 设备单元 (新增) | +| 14 | `module_scope_slice` | Scope 和 Slice 资源控制单元 (新增) | +| 15 | `module_dependencies` | 系统依赖关系 (新增) | +| 16 | `module_journal` | Journal 日志摘要 | +| 17 | `module_environment` | Systemd 环境变量 | +| 18 | `module_cgroup` | Cgroup 信息 (新增) | +| 19 | `module_performance` | 系统性能信息 | +| 20 | `module_power_management` | 电源管理状态 (新增) | +| 21 | `module_critical_services` | 关键系统服务状态 | +| 22 | `module_help` | 常用命令提示 | + +### 新增功能 (相比 v1.0) + +- **Path 单元**: 路径监控单元的状态和监控路径 +- **Device 单元**: 设备单元的详细信息 +- **Scope 和 Slice**: 资源控制单元的统计和资源使用 +- **依赖关系**: 系统单元依赖树和依赖数量统计 +- **Cgroup 信息**: cgroup 版本、控制器、资源使用 +- **电源管理**: suspend/hibernate 状态和日志 +- **已屏蔽服务**: 单独列出所有被屏蔽的服务 + +## 运行方式 + +```bash +# 直接运行脚本 +./systemctl-info + +# 或使用 bash 执行 +bash systemctl-info +``` + +## 注意事项 + +- 需要 root 权限或适当的 systemd 访问权限 +- 依赖系统命令:`systemctl`, `journalctl`, `uptime`, `free`, `top`, `hostname`, `uname`, `numfmt` +- 脚本会使用 `journalctl` 查看错误日志,可能需要相应权限 +- 脚本输出使用 ANSI 颜色代码,建议在支持颜色的终端中运行 \ No newline at end of file diff --git a/systemctl-info/systemctl-info b/systemctl-info/systemctl-info new file mode 100755 index 0000000..b50dda0 --- /dev/null +++ b/systemctl-info/systemctl-info @@ -0,0 +1,802 @@ +#!/bin/bash + +# systemctl-info - 详细的systemctl信息查看脚本 +# 作者: iFlow CLI +# 日期: 2026-02-13 +# 版本: 2.0 (模块化版本) + +# ═══════════════════════════════════════════════════════════════════════════════ +# 颜色定义 +# ═══════════════════════════════════════════════════════════════════════════════ +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +MAGENTA='\033[0;35m' +CYAN='\033[0;36m' +WHITE='\033[0;37m' +BRIGHT_RED='\033[1;31m' +BRIGHT_GREEN='\033[1;32m' +BRIGHT_YELLOW='\033[1;33m' +BRIGHT_BLUE='\033[1;34m' +BRIGHT_MAGENTA='\033[1;35m' +BRIGHT_CYAN='\033[1;36m' +BRIGHT_WHITE='\033[1;37m' +ORANGE='\033[38;5;208m' +PINK='\033[38;5;205m' +PURPLE='\033[38;5;141m' +LIME='\033[38;5;154m' +RESET='\033[0m' + +# ═══════════════════════════════════════════════════════════════════════════════ +# 分割线样式 +# ═══════════════════════════════════════════════════════════════════════════════ +SEPARATOR="${BRIGHT_CYAN}═══════════════════════════════════════════════════════════════════════════════${RESET}" +THIN_SEPARATOR="${CYAN}──────────────────────────────────────────────────────────────────────────────────────${RESET}" +DASH_SEPARATOR="${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" +LINE="${BRIGHT_CYAN}═══════════════════════════════════════════════════════════════════════════════${RESET}" + +# ═══════════════════════════════════════════════════════════════════════════════ +# 通用工具函数 +# ═══════════════════════════════════════════════════════════════════════════════ + +# 打印标题 +print_header() { + echo -e "${BRIGHT_CYAN}[Systemctl Info Viewer v2.0]${RESET}" + echo -e "${BRIGHT_CYAN}模块化 Systemd 信息查看脚本${RESET}" + echo "" +} + +# 打印带颜色的小节标题 +print_section() { + echo -e "${THIN_SEPARATOR}" + echo -e "${BRIGHT_BLUE}[ $1 ]${RESET}" + echo -e "${THIN_SEPARATOR}" +} + +# 打印带图标的信息行 +print_info() { + local icon="$1" + local label="$2" + local value="$3" + local color="$4" + echo -e "${icon} ${BRIGHT_WHITE}${label}:${RESET} ${color}${value}${RESET}" +} + +# 打印子项 +print_subitem() { + local label="$1" + local value="$2" + local color="$3" + echo -e " ${BRIGHT_CYAN}▸${RESET} ${BRIGHT_WHITE}${label}:${RESET} ${color}${value}${RESET}" +} + +# 打印带颜色的列表项 +print_list_item() { + local icon="$1" + local name="$2" + local status="$3" + local status_color="$4" + local extra="$5" + printf "${icon} ${BRIGHT_WHITE}%-45s${RESET} ${status_color}%s${RESET}%s\n" "$name" "$status" "$extra" +} + +# 获取状态图标和颜色 +get_state_icon_color() { + local state="$1" + case "$state" in + active|running|listening) + echo -e "✅|${BRIGHT_GREEN}" + ;; + inactive) + echo -e "⭕|${BRIGHT_YELLOW}" + ;; + failed) + echo -e "❌|${BRIGHT_RED}" + ;; + activating|deactivating) + echo -e "🔄|${BRIGHT_CYAN}" + ;; + *) + echo -e "❓|${BRIGHT_WHITE}" + ;; + esac +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块1: Systemd 版本信息 +# ═══════════════════════════════════════════════════════════════════════════════ +module_systemd_version() { + print_section "📋 Systemd 版本信息" + + SYSTEMD_VERSION=$(systemctl --version | head -n 1 | awk '{print $2}') + FEATURE_COUNT=$(systemctl --version | grep -c "features") + + print_info "🔧" "Systemd 版本" "$SYSTEMD_VERSION" "${BRIGHT_GREEN}" + print_info "✨" "支持功能特性" "$FEATURE_COUNT 项" "${LIME}" + + echo -e "${BRIGHT_CYAN}详细版本信息:${RESET}" + systemctl --version | while IFS= read -r line; do + echo -e " ${CYAN}${line}${RESET}" + done +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块2: 系统基础信息 +# ═══════════════════════════════════════════════════════════════════════════════ +module_system_info() { + print_section "🖥️ 系统基础信息" + + HOSTNAME=$(hostname) + KERNEL_VERSION=$(uname -r) + OS_ID=$(grep '^ID=' /etc/os-release | cut -d'=' -f2 | tr -d '"') + OS_NAME=$(grep '^PRETTY_NAME=' /etc/os-release | cut -d'=' -f2 | tr -d '"') + ARCH=$(uname -m) + UPTIME=$(uptime -p) + + print_info "🖥️" "主机名" "$HOSTNAME" "${BRIGHT_YELLOW}" + print_info "🐧" "内核版本" "$KERNEL_VERSION" "${ORANGE}" + print_info "📦" "操作系统ID" "$OS_ID" "${PINK}" + print_info "💻" "系统名称" "$OS_NAME" "${PURPLE}" + print_info "🏗️" "系统架构" "$ARCH" "${BRIGHT_CYAN}" + print_info "⏱️" "系统运行时间" "$UPTIME" "${LIME}" +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块3: Systemd 系统状态 +# ═══════════════════════════════════════════════════════════════════════════════ +module_systemd_status() { + print_section "⚙️ Systemd 系统状态" + + SYSTEM_STATE=$(systemctl is-system-running) + DEFAULT_TARGET=$(systemctl get-default) + INIT_PID=$(systemctl show --property=MainPID --value) + BOOT_TIME=$(systemctl show --property=UserspaceTimestamp --value | cut -d' ' -f1) + + case $SYSTEM_STATE in + running) + STATE_COLOR="${BRIGHT_GREEN}" + STATE_ICON="✅" + ;; + degraded) + STATE_COLOR="${BRIGHT_YELLOW}" + STATE_ICON="⚠️" + ;; + maintenance) + STATE_COLOR="${BRIGHT_RED}" + STATE_ICON="🔧" + ;; + *) + STATE_COLOR="${BRIGHT_WHITE}" + STATE_ICON="❓" + ;; + esac + + print_info "$STATE_ICON" "系统状态" "$SYSTEM_STATE" "$STATE_COLOR" + print_info "🎯" "默认运行级别" "$DEFAULT_TARGET" "${BRIGHT_CYAN}" + print_info "🔄" "Init 进程 PID" "$INIT_PID" "${ORANGE}" + print_info "🚀" "启动时间" "$BOOT_TIME" "${PURPLE}" +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块4: 服务(Service)统计与状态 +# ═══════════════════════════════════════════════════════════════════════════════ +module_service_stats() { + print_section "🔌 服务(Service)统计与状态" + + TOTAL_UNITS=$(systemctl list-unit-files --type=service --no-legend | wc -l) + ENABLED_SERVICES=$(systemctl list-unit-files --type=service --state=enabled --no-legend | wc -l) + DISABLED_SERVICES=$(systemctl list-unit-files --type=service --state=disabled --no-legend | wc -l) + STATIC_SERVICES=$(systemctl list-unit-files --type=service --state=static --no-legend | wc -l) + MASKED_SERVICES=$(systemctl list-unit-files --type=service --state=masked --no-legend | wc -l) + + RUNNING_SERVICES=$(systemctl list-units --type=service --state=running --no-legend | wc -l) + FAILED_SERVICES=$(systemctl list-units --type=service --state=failed --no-legend | wc -l) + + echo -e "${BRIGHT_CYAN}服务文件统计:${RESET}" + print_subitem "总服务数" "$TOTAL_UNITS" "${BRIGHT_WHITE}" + print_subitem "已启用(enabled)" "$ENABLED_SERVICES" "${BRIGHT_GREEN}" + print_subitem "已禁用(disabled)" "$DISABLED_SERVICES" "${BRIGHT_RED}" + print_subitem "静态服务(static)" "$STATIC_SERVICES" "${BRIGHT_YELLOW}" + print_subitem "已屏蔽(masked)" "$MASKED_SERVICES" "${PURPLE}" + + echo -e "${BRIGHT_CYAN}服务运行状态:${RESET}" + print_subitem "运行中" "$RUNNING_SERVICES" "${LIME}" + print_subitem "失败" "$FAILED_SERVICES" "${BRIGHT_RED}" +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块5: 失败的服务详情 +# ═══════════════════════════════════════════════════════════════════════════════ +module_failed_services() { + FAILED_SERVICES=$(systemctl list-units --type=service --state=failed --no-legend | wc -l) + + if [ "$FAILED_SERVICES" -gt 0 ]; then + print_section "❌ 失败的服务详情 (共 $FAILED_SERVICES 个)" + systemctl list-units --type=service --state=failed --no-pager | sed '1,1d' | while IFS= read -r line; do + if [ -n "$line" ]; then + SERVICE_NAME=$(echo "$line" | awk '{print $1}') + LOAD_STATE=$(echo "$line" | awk '{print $2}') + ACTIVE_STATE=$(echo "$line" | awk '{print $3}') + SUB_STATE=$(echo "$line" | awk '{print $4}') + DESCRIPTION=$(echo "$line" | awk '{for(i=5;i<=NF;i++)print $i}' | tr '\n' ' ' | sed 's/ $//') + + echo -e "${BRIGHT_RED}✗${RESET} ${BRIGHT_WHITE}${SERVICE_NAME}${RESET}" + echo -e " ${CYAN}描述:${RESET} ${WHITE}${DESCRIPTION}${RESET}" + echo -e " ${CYAN}状态:${RESET} ${RED}${LOAD_STATE}${RESET}|${RED}${ACTIVE_STATE}${RESET}|${RED}${SUB_STATE}${RESET}" + fi + done + else + print_section "✅ 失败的服务详情" + echo -e "${BRIGHT_GREEN} 没有失败的服务${RESET}" + fi +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块6: 已屏蔽(Masked)的服务 +# ═══════════════════════════════════════════════════════════════════════════════ +module_masked_services() { + MASKED_COUNT=$(systemctl list-unit-files --type=service --state=masked --no-legend | wc -l) + + print_section "🚫 已屏蔽(Masked)的服务" + print_subitem "已屏蔽服务数" "$MASKED_COUNT" "${PURPLE}" + + if [ "$MASKED_COUNT" -gt 0 ]; then + echo -e "${BRIGHT_CYAN}已屏蔽的服务列表:${RESET}" + systemctl list-unit-files --type=service --state=masked --no-legend | while IFS= read -r line; do + if [ -n "$line" ]; then + echo -e " ${PURPLE}✗${RESET} ${BRIGHT_WHITE}${line}${RESET}" + fi + done + fi +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块7: 运行中的服务 +# ═══════════════════════════════════════════════════════════════════════════════ +module_running_services() { + print_section "🟢 运行中的服务 (Top 20)" + + RUNNING_COUNT=$(systemctl list-units --type=service --state=running --no-legend | wc -l) + print_subitem "运行中服务总数" "$RUNNING_COUNT" "${LIME}" + + echo -e "${BRIGHT_CYAN}运行中的服务列表:${RESET}" + systemctl list-units --type=service --state=running --no-pager --no-legend | head -20 | while IFS= read -r line; do + if [ -n "$line" ]; then + SERVICE_NAME=$(echo "$line" | awk '{print $1}') + LOAD_STATE=$(echo "$line" | awk '{print $2}') + ACTIVE_STATE=$(echo "$line" | awk '{print $3}') + SUB_STATE=$(echo "$line" | awk '{print $4}') + + printf " ${BRIGHT_GREEN}●${RESET} ${BRIGHT_WHITE}%-40s${RESET} ${CYAN}%-8s${RESET} ${BRIGHT_GREEN}%-10s${RESET} ${BRIGHT_CYAN}%s${RESET}\n" "$SERVICE_NAME" "$LOAD_STATE" "$ACTIVE_STATE" "$SUB_STATE" + fi + done +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块8: Timer 定时任务 +# ═══════════════════════════════════════════════════════════════════════════════ +module_timer() { + print_section "⏰ Timer 定时任务" + + TOTAL_TIMERS=$(systemctl list-units --type=timer --all --no-legend | wc -l) + ACTIVE_TIMERS=$(systemctl list-units --type=timer --state=active --no-legend | wc -l) + + print_subitem "总 Timer 数" "$TOTAL_TIMERS" "${BRIGHT_WHITE}" + print_subitem "活跃 Timer" "$ACTIVE_TIMERS" "${LIME}" + + if [ "$ACTIVE_TIMERS" -gt 0 ]; then + echo -e "${BRIGHT_CYAN}活跃的定时任务 (Top 15):${RESET}" + systemctl list-units --type=timer --state=active --no-pager --no-legend | head -15 | while IFS= read -r line; do + if [ -n "$line" ]; then + TIMER_NAME=$(echo "$line" | awk '{print $1}') + NEXT_RUN=$(systemctl show "$TIMER_NAME" --property=NextElapseUSec --value 2>/dev/null) + + printf " ${BRIGHT_YELLOW}⏱${RESET} ${BRIGHT_WHITE}%-40s${RESET} ${CYAN}下次执行:${RESET} ${LIME}%s${RESET}\n" "$TIMER_NAME" "$NEXT_RUN" + fi + done + fi +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块9: Socket 单元 +# ═══════════════════════════════════════════════════════════════════════════════ +module_socket() { + print_section "🔌 Socket 监听" + + TOTAL_SOCKETS=$(systemctl list-units --type=socket --all --no-legend | wc -l) + LISTENING_SOCKETS=$(systemctl list-units --type=socket --state=listening --no-legend | wc -l) + + print_subitem "总 Socket 数" "$TOTAL_SOCKETS" "${BRIGHT_WHITE}" + print_subitem "监听中" "$LISTENING_SOCKETS" "${LIME}" + + if [ "$LISTENING_SOCKETS" -gt 0 ]; then + echo -e "${BRIGHT_CYAN}正在监听的 Socket (Top 15):${RESET}" + systemctl list-units --type=socket --state=listening --no-pager --no-legend | head -15 | while IFS= read -r line; do + if [ -n "$line" ]; then + SOCKET_NAME=$(echo "$line" | awk '{print $1}') + SUB_STATE=$(echo "$line" | awk '{print $4}') + + printf " ${BRIGHT_MAGENTA}🔌${RESET} ${BRIGHT_WHITE}%-40s${RESET} ${CYAN}%s${RESET}\n" "$SOCKET_NAME" "$SUB_STATE" + fi + done + fi +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块10: Target 目标单元 +# ═══════════════════════════════════════════════════════════════════════════════ +module_target() { + print_section "🎯 Target 目标单元" + + ACTIVE_TARGETS=$(systemctl list-units --type=target --state=active --no-legend | wc -l) + print_subitem "当前激活的 Target" "$ACTIVE_TARGETS" "${LIME}" + + echo -e "${BRIGHT_CYAN}重要的 Target 单元:${RESET}" + IMPORTANT_TARGETS=("default.target" "multi-user.target" "graphical.target" "basic.target" "rescue.target" "emergency.target" "network.target" "sysinit.target") + + for target in "${IMPORTANT_TARGETS[@]}"; do + TARGET_STATE=$(systemctl is-active "$target" 2>/dev/null) + TARGET_ENABLED=$(systemctl is-enabled "$target" 2>/dev/null) + + if [ -n "$TARGET_STATE" ]; then + case $TARGET_STATE in + active) STATE_ICON="✅"; STATE_COLOR="${BRIGHT_GREEN}" ;; + inactive) STATE_ICON="⭕"; STATE_COLOR="${BRIGHT_YELLOW}" ;; + *) STATE_ICON="❓"; STATE_COLOR="${BRIGHT_WHITE}" ;; + esac + + printf " ${STATE_ICON} ${BRIGHT_WHITE}%-25s${RESET} ${STATE_COLOR}状态:%-10s${RESET} ${CYAN}启用:%s${RESET}\n" "$target" "$TARGET_STATE" "$TARGET_ENABLED" + fi + done +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块11: Mount 和 Automount 单元 +# ═══════════════════════════════════════════════════════════════════════════════ +module_mount() { + print_section "📁 挂载点(Mount)信息" + + TOTAL_MOUNTS=$(systemctl list-units --type=mount --all --no-legend | wc -l) + ACTIVE_MOUNTS=$(systemctl list-units --type=mount --state=active --no-legend | wc -l) + TOTAL_AUTOMOUNTS=$(systemctl list-units --type=automount --all --no-legend | wc -l) + ACTIVE_AUTOMOUNTS=$(systemctl list-units --type=automount --state=active --no-legend | wc -l) + + print_subitem "挂载点总数" "$TOTAL_MOUNTS" "${BRIGHT_WHITE}" + print_subitem "活跃挂载点" "$ACTIVE_MOUNTS" "${LIME}" + print_subitem "自动挂载总数" "$TOTAL_AUTOMOUNTS" "${BRIGHT_WHITE}" + print_subitem "活跃自动挂载" "$ACTIVE_AUTOMOUNTS" "${LIME}" + + if [ "$ACTIVE_MOUNTS" -gt 0 ]; then + echo -e "${BRIGHT_CYAN}挂载点详情 (Top 10):${RESET}" + systemctl list-units --type=mount --state=active --no-pager --no-legend | head -10 | while IFS= read -r line; do + if [ -n "$line" ]; then + MOUNT_NAME=$(echo "$line" | awk '{print $1}') + MOUNT_POINT=$(systemctl show "$MOUNT_NAME" --property=Where --value 2>/dev/null) + SUB_STATE=$(echo "$line" | awk '{print $4}') + + printf " ${BRIGHT_CYAN}📂${RESET} ${BRIGHT_WHITE}%-35s${RESET} ${PURPLE}%s${RESET}\n" "$MOUNT_POINT" "$SUB_STATE" + fi + done + fi +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块12: Path 单元 +# ═══════════════════════════════════════════════════════════════════════════════ +module_path() { + print_section "📍 Path 路径监控单元" + + TOTAL_PATHS=$(systemctl list-units --type=path --all --no-legend | wc -l) + ACTIVE_PATHS=$(systemctl list-units --type=path --state=active --no-legend | wc -l) + + print_subitem "总 Path 数" "$TOTAL_PATHS" "${BRIGHT_WHITE}" + print_subitem "活跃 Path" "$ACTIVE_PATHS" "${LIME}" + + if [ "$ACTIVE_PATHS" -gt 0 ]; then + echo -e "${BRIGHT_CYAN}活跃的 Path 监控 (Top 10):${RESET}" + systemctl list-units --type=path --state=active --no-pager --no-legend | head -10 | while IFS= read -r line; do + if [ -n "$line" ]; then + PATH_NAME=$(echo "$line" | awk '{print $1}') + SUB_STATE=$(echo "$line" | awk '{print $4}') + PATH_PATH=$(systemctl show "$PATH_NAME" --property=PathExists --value 2>/dev/null) + + printf " ${BRIGHT_CYAN}📍${RESET} ${BRIGHT_WHITE}%-40s${RESET} ${CYAN}监控:${RESET} ${LIME}%s${RESET} ${CYAN}状态:%s${RESET}\n" "$PATH_NAME" "$PATH_PATH" "$SUB_STATE" + fi + done + fi +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块13: Device 单元 +# ═══════════════════════════════════════════════════════════════════════════════ +module_device() { + print_section "🔧 Device 设备单元" + + TOTAL_DEVICES=$(systemctl list-units --type=device --all --no-legend | wc -l) + ACTIVE_DEVICES=$(systemctl list-units --type=device --state=active --no-legend | wc -l) + + print_subitem "总设备数" "$TOTAL_DEVICES" "${BRIGHT_WHITE}" + print_subitem "活跃设备" "$ACTIVE_DEVICES" "${LIME}" + + if [ "$ACTIVE_DEVICES" -gt 0 ]; then + echo -e "${BRIGHT_CYAN}活跃的设备 (Top 10):${RESET}" + systemctl list-units --type=device --state=active --no-pager --no-legend | head -10 | while IFS= read -r line; do + if [ -n "$line" ]; then + DEVICE_NAME=$(echo "$line" | awk '{print $1}') + SUB_STATE=$(echo "$line" | awk '{print $4}') + + printf " ${BRIGHT_YELLOW}🔧${RESET} ${BRIGHT_WHITE}%-45s${RESET} ${LIME}%s${RESET}\n" "$DEVICE_NAME" "$SUB_STATE" + fi + done + fi +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块14: Scope 和 Slice 单元 +# ═══════════════════════════════════════════════════════════════════════════════ +module_scope_slice() { + print_section "📊 Scope 和 Slice 资源控制单元" + + # Scope 单元 + TOTAL_SCOPES=$(systemctl list-units --type=scope --all --no-legend | wc -l) + ACTIVE_SCOPES=$(systemctl list-units --type=scope --state=running --no-legend | wc -l) + + print_subitem "Scope 总数" "$TOTAL_SCOPES" "${BRIGHT_WHITE}" + print_subitem "运行中 Scope" "$ACTIVE_SCOPES" "${LIME}" + + if [ "$ACTIVE_SCOPES" -gt 0 ]; then + echo -e "${BRIGHT_CYAN}运行中的 Scope (Top 10):${RESET}" + systemctl list-units --type=scope --state=running --no-pager --no-legend | head -10 | while IFS= read -r line; do + if [ -n "$line" ]; then + SCOPE_NAME=$(echo "$line" | awk '{print $1}') + SUB_STATE=$(echo "$line" | awk '{print $4}') + + printf " ${BRIGHT_CYAN}📊${RESET} ${BRIGHT_WHITE}%-45s${RESET} ${LIME}%s${RESET}\n" "$SCOPE_NAME" "$SUB_STATE" + fi + done + fi + + # Slice 单元 + echo "" + TOTAL_SLICES=$(systemctl list-units --type=slice --all --no-legend | wc -l) + ACTIVE_SLICES=$(systemctl list-units --type=slice --state=active --no-legend | wc -l) + + print_subitem "Slice 总数" "$TOTAL_SLICES" "${BRIGHT_WHITE}" + print_subitem "活跃 Slice" "$ACTIVE_SLICES" "${LIME}" + + if [ "$ACTIVE_SLICES" -gt 0 ]; then + echo -e "${BRIGHT_CYAN}活跃的 Slice:${RESET}" + systemctl list-units --type=slice --state=active --no-pager --no-legend | head -10 | while IFS= read -r line; do + if [ -n "$line" ]; then + SLICE_NAME=$(echo "$line" | awk '{print $1}') + SUB_STATE=$(echo "$line" | awk '{print $4}') + MEMORY=$(systemctl show "$SLICE_NAME" --property=MemoryCurrent --value 2>/dev/null) + if [ -n "$MEMORY" ] && [ "$MEMORY" != "[not set]" ]; then + MEMORY_DISPLAY="内存: $(numfmt --to=iec $MEMORY 2>/dev/null || echo $MEMORY)" + else + MEMORY_DISPLAY="" + fi + + printf " ${BRIGHT_MAGENTA}📦${RESET} ${BRIGHT_WHITE}%-30s${RESET} ${LIME}%s${RESET} %s\n" "$SLICE_NAME" "$SUB_STATE" "$MEMORY_DISPLAY" + fi + done + fi +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块15: 依赖关系 +# ═══════════════════════════════════════════════════════════════════════════════ +module_dependencies() { + print_section "🔗 系统依赖关系" + + # 显示默认.target的依赖树 + DEFAULT_TARGET=$(systemctl get-default) + + echo -e "${BRIGHT_CYAN}默认目标 '$DEFAULT_TARGET' 的依赖 (前15个):${RESET}" + systemctl list-dependencies "$DEFAULT_TARGET" --no-pager --no-legend | head -15 | while IFS= read -r line; do + if [ -n "$line" ]; then + UNIT_TYPE=$(echo "$line" | grep -o '\.[a-z]*$' | tr -d '.') + case "$UNIT_TYPE" in + service) ICON="🔌" ;; + target) ICON="🎯" ;; + timer) ICON="⏰" ;; + socket) ICON="🔌" ;; + mount) ICON="📁" ;; + path) ICON="📍" ;; + *) ICON="📄" ;; + esac + printf " ${ICON} ${BRIGHT_WHITE}%s${RESET}\n" "$line" + fi + done + + # 显示被依赖最多的服务 + echo "" + echo -e "${BRIGHT_CYAN}系统关键.target的依赖数量:${RESET}" + for target in "multi-user.target" "graphical.target" "basic.target" "network.target"; do + DEP_COUNT=$(systemctl list-dependencies "$target" --no-legend 2>/dev/null | wc -l) + if [ -n "$DEP_COUNT" ]; then + print_subitem "$target" "$DEP_COUNT 个依赖" "${BRIGHT_CYAN}" + fi + done +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块16: Systemd 日志信息 +# ═══════════════════════════════════════════════════════════════════════════════ +module_journal() { + print_section "📝 Systemd Journal 日志摘要" + + JOURNAL_SIZE=$(journalctl --disk-usage | grep "Journals use" | awk '{print $3,$4}') + JOURNAL_ENTRIES=$(journalctl --no-pager -n 0 2>/dev/null | wc -l) + + print_subitem "日志磁盘占用" "$JOURNAL_SIZE" "${ORANGE}" + print_subitem "日志总条目" "$JOURNAL_ENTRIES" "${BRIGHT_CYAN}" + + echo -e "${BRIGHT_CYAN}最近的错误日志 (最近5条):${RESET}" + journalctl -p err -n 5 --no-pager 2>/dev/null | while IFS= read -r line; do + if [ -n "$line" ]; then + echo -e " ${RED}✗${RESET} ${WHITE}${line}${RESET}" + fi + done + + echo -e "${BRIGHT_CYAN}最近的警告日志 (最近3条):${RESET}" + journalctl -p warning -n 3 --no-pager 2>/dev/null | while IFS= read -r line; do + if [ -n "$line" ]; then + echo -e " ${YELLOW}⚠${RESET} ${WHITE}${line}${RESET}" + fi + done +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块17: Systemd 环境变量 +# ═══════════════════════════════════════════════════════════════════════════════ +module_environment() { + print_section "🔧 Systemd 环境变量" + + ENV_COUNT=$(systemctl show-environment 2>/dev/null | wc -l) + print_subitem "环境变量数量" "$ENV_COUNT" "${BRIGHT_CYAN}" + + echo -e "${BRIGHT_CYAN}系统环境变量:${RESET}" + systemctl show-environment 2>/dev/null | head -15 | while IFS= read -r line; do + if [ -n "$line" ]; then + KEY=$(echo "$line" | cut -d'=' -f1) + VALUE=$(echo "$line" | cut -d'=' -f2-) + echo -e " ${BRIGHT_YELLOW}●${RESET} ${BRIGHT_CYAN}${KEY}${RESET}=${BRIGHT_WHITE}${VALUE}${RESET}" + fi + done +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块18: Cgroup 信息 +# ═══════════════════════════════════════════════════════════════════════════════ +module_cgroup() { + print_section "🧊 Cgroup 信息" + + # 获取 cgroup 版本 + if [ -f /sys/fs/cgroup/cgroup.controllers ]; then + CGROUP_VERSION="v2 (unified)" + else + CGROUP_VERSION="v1 (legacy)" + fi + + print_subitem "Cgroup 版本" "$CGROUP_VERSION" "${BRIGHT_CYAN}" + + # 获取控制器信息 + if [ -f /sys/fs/cgroup/cgroup.controllers ]; then + CONTROLLERS=$(cat /sys/fs/cgroup/cgroup.controllers 2>/dev/null | tr ' ' ', ') + else + CONTROLLERS=$(cat /sys/fs/cgroup/devices.list 2>/dev/null | head -1 | cut -d' ' -f1 || echo "N/A") + fi + print_subitem "可用控制器" "$CONTROLLERS" "${LIME}" + + # Slice 资源统计 + echo -e "${BRIGHT_CYAN}Slice 资源使用 (Top 5):${RESET}" + for slice in $(systemctl list-units --type=slice --state=active --no-legend | awk '{print $1}' | head -5); do + MEM_CURRENT=$(systemctl show "$slice" --property=MemoryCurrent --value 2>/dev/null) + MEM_MAX=$(systemctl show "$slice" --property=MemoryMax --value 2>/dev/null) + CPU_WEIGHT=$(systemctl show "$slice" --property=CPUWeight --value 2>/dev/null) + + MEM_DISP="" + if [ -n "$MEM_CURRENT" ] && [ "$MEM_CURRENT" != "[not set]" ]; then + MEM_DISP="内存: $(numfmt --to=iec $MEM_CURRENT 2>/dev/null || echo $MEM_CURRENT)" + fi + if [ -n "$CPU_WEIGHT" ] && [ "$CPU_WEIGHT" != "[not set]" ]; then + MEM_DISP="$MEM_DISP CPU权重: $CPU_WEIGHT" + fi + + if [ -n "$MEM_DISP" ]; then + printf " ${BRIGHT_MAGENTA}📦${RESET} ${BRIGHT_WHITE}%-25s${RESET} ${LIME}%s${RESET}\n" "$slice" "$MEM_DISP" + fi + done +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块19: 系统性能信息 +# ═══════════════════════════════════════════════════════════════════════════════ +module_performance() { + print_section "📊 系统性能信息" + + # 获取 CPU 使用率 + CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1) + + # 获取内存信息 + MEM_INFO=$(free -h | grep "Mem:") + MEM_TOTAL=$(echo "$MEM_INFO" | awk '{print $2}') + MEM_USED=$(echo "$MEM_INFO" | awk '{print $3}') + MEM_FREE=$(echo "$MEM_INFO" | awk '{print $4}') + MEM_PERCENT=$(free | grep "Mem:" | awk '{printf "%.1f", $3/$2*100}') + + # 获取启动时间 + BOOT_TIME_SEC=$(systemctl show --property=UserspaceTimestampMonotonic --value | cut -d' ' -f1) + BOOT_TIME_SEC=${BOOT_TIME_SEC:-0} + BOOT_TIME_SEC=$((BOOT_TIME_SEC / 1000000)) + + print_subitem "CPU 使用率" "${CPU_USAGE}%" "${BRIGHT_YELLOW}" + print_subitem "内存总量" "$MEM_TOTAL" "${BRIGHT_CYAN}" + print_subitem "已用内存" "$MEM_USED (${MEM_PERCENT}%)" "${ORANGE}" + print_subitem "可用内存" "$MEM_FREE" "${LIME}" + print_subitem "启动耗时" "${BOOT_TIME_SEC} 秒" "${PURPLE}" + + # Swap 信息 + SWAP_TOTAL=$(free -h | grep "Swap:" | awk '{print $2}') + SWAP_USED=$(free -h | grep "Swap:" | awk '{print $3}') + SWAP_FREE=$(free -h | grep "Swap:" | awk '{print $4}') + + if [ "$SWAP_TOTAL" != "0" ]; then + print_subitem "Swap总量" "$SWAP_TOTAL" "${PINK}" + print_subitem "Swap已用" "$SWAP_USED" "${PINK}" + print_subitem "Swap可用" "$SWAP_FREE" "${PINK}" + fi +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块20: 电源管理状态 +# ═══════════════════════════════════════════════════════════════════════════════ +module_power_management() { + print_section "🔋 电源管理状态" + + # 检查 systemd-suspend 服务 + if systemctl list-unit-files | grep -q "systemd-suspend.service"; then + SUSPEND_STATE=$(systemctl is-enabled systemd-suspend.service 2>/dev/null || echo "N/A") + print_subitem "Suspend 服务" "$SUSPEND_STATE" "${BRIGHT_CYAN}" + fi + + # 检查 systemd-hibernate 服务 + if systemctl list-unit-files | grep -q "systemd-hibernate.service"; then + HIBERNATE_STATE=$(systemctl is-enabled systemd-hibernate.service 2>/dev/null || echo "N/A") + print_subitem "Hibernate 服务" "$HIBERNATE_STATE" "${BRIGHT_CYAN}" + fi + + # 检查 logind 状态 + if systemctl list-unit-files | grep -q "systemd-logind.service"; then + LOGIND_STATE=$(systemctl is-active systemd-logind.service 2>/dev/null || echo "N/A") + print_subitem "Logind 状态" "$LOGIND_STATE" "${LIME}" + fi + + # 显示电源相关事件 + echo -e "${BRIGHT_CYAN}最近的电源相关日志:${RESET}" + journalctl -u systemd-logind -u upower -n 3 --no-pager 2>/dev/null | while IFS= read -r line; do + if [ -n "$line" ]; then + echo -e " ${CYAN}▸${RESET} ${WHITE}${line}${RESET}" + fi + done +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块21: 关键服务状态 +# ═══════════════════════════════════════════════════════════════════════════════ +module_critical_services() { + print_section "🔑 关键系统服务状态" + + KEY_SERVICES=( + "sshd.service" + "NetworkManager.service" + "cron.service" + "rsyslog.service" + "dbus.service" + "systemd-logind.service" + "systemd-journald.service" + "systemd-udevd.service" + "polkit.service" + ) + + for service in "${KEY_SERVICES[@]}"; do + if systemctl list-unit-files 2>/dev/null | grep -q "$service"; then + SERVICE_STATE=$(systemctl is-active "$service" 2>/dev/null) + SERVICE_ENABLED=$(systemctl is-enabled "$service" 2>/dev/null) + + case $SERVICE_STATE in + active) STATE_ICON="✅"; STATE_COLOR="${BRIGHT_GREEN}" ;; + inactive) STATE_ICON="⭕"; STATE_COLOR="${BRIGHT_YELLOW}" ;; + failed) STATE_ICON="❌"; STATE_COLOR="${BRIGHT_RED}" ;; + *) STATE_ICON="❓"; STATE_COLOR="${BRIGHT_WHITE}" ;; + esac + + printf " ${STATE_ICON} ${BRIGHT_WHITE}%-30s${RESET} ${STATE_COLOR}%-10s${RESET} ${CYAN}启用:%s${RESET}\n" "$service" "$SERVICE_STATE" "$SERVICE_ENABLED" + fi + done +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 模块22: 常用命令提示 +# ═══════════════════════════════════════════════════════════════════════════════ +module_help() { + print_section "💡 常用 Systemctl 命令" + + echo -e "${BRIGHT_YELLOW}=== 服务管理 ===${RESET}" + echo -e "${BRIGHT_WHITE}systemctl status ${RESET} - 查看服务状态" + echo -e "${BRIGHT_WHITE}systemctl start ${RESET} - 启动服务" + echo -e "${BRIGHT_WHITE}systemctl stop ${RESET} - 停止服务" + echo -e "${BRIGHT_WHITE}systemctl restart ${RESET} - 重启服务" + echo -e "${BRIGHT_WHITE}systemctl enable ${RESET} - 启用开机自启" + echo -e "${BRIGHT_WHITE}systemctl disable ${RESET} - 禁用开机自启" + echo -e "${BRIGHT_WHITE}systemctl mask ${RESET} - 屏蔽服务" + echo -e "${BRIGHT_WHITE}systemctl unmask ${RESET} - 取消屏蔽" + + echo -e "${BRIGHT_YELLOW}=== 状态查看 ===${RESET}" + echo -e "${BRIGHT_WHITE}systemctl is-active ${RESET} - 检查服务是否活跃" + echo -e "${BRIGHT_WHITE}systemctl is-enabled ${RESET} - 检查服务是否启用" + echo -e "${BRIGHT_WHITE}systemctl --failed${RESET} - 查看失败的服务" + echo -e "${BRIGHT_WHITE}systemctl list-dependencies ${RESET} - 查看依赖" + + echo -e "${BRIGHT_YELLOW}=== 日志查看 ===${RESET}" + echo -e "${BRIGHT_WHITE}journalctl -u ${RESET} - 查看服务日志" + echo -e "${BRIGHT_WHITE}journalctl -xe${RESET} - 查看最近日志" + echo -e "${BRIGHT_WHITE}journalctl -p err${RESET} - 查看错误日志" + + echo -e "${BRIGHT_YELLOW}=== 电源管理 ===${RESET}" + echo -e "${BRIGHT_WHITE}systemctl suspend${RESET} - 挂起" + echo -e "${BRIGHT_WHITE}systemctl hibernate${RESET} - 休眠" + echo -e "${BRIGHT_WHITE}systemctl reboot${RESET} - 重启" + echo -e "${BRIGHT_WHITE}systemctl poweroff${RESET} - 关机" +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# 主函数 - 模块调度 +# ═══════════════════════════════════════════════════════════════════════════════ +main() { + print_header + + # 基础信息模块 + module_systemd_version + module_system_info + module_systemd_status + + # 单元统计模块 + module_service_stats + module_running_services + module_failed_services + module_masked_services + + # 各类单元模块 + module_timer + module_socket + module_target + module_mount + module_path + module_device + module_scope_slice + + # 系统信息模块 + module_dependencies + module_journal + module_environment + module_cgroup + module_performance + module_power_management + + # 服务状态模块 + module_critical_services + + # 帮助信息 + module_help + + # 结束 + echo -e "${DASH_SEPARATOR}" + echo -e "${BRIGHT_MAGENTA}✨ 信息收集完成!时间: $(date '+%Y-%m-%d %H:%M:%S') ✨${RESET}" + echo -e "${DASH_SEPARATOR}" +} + +# 执行主函数 +main "@" \ No newline at end of file diff --git a/user-manager/user-manager.sh b/user-manager/user-manager.sh new file mode 100755 index 0000000..619848f --- /dev/null +++ b/user-manager/user-manager.sh @@ -0,0 +1,1219 @@ +#!/bin/bash +# ============================================================================ +# Linux 用户和组管理脚本 (增强版) +# 适用于: Debian/Ubuntu (amd64/arm64) +# 用法: curl -fsSL "https://pan.shumengya.top/d/scripts/user_manager.sh" | bash +# 或者: sudo bash user_manager.sh +# ============================================================================ + +set -euo pipefail + +# ============================================================================ +# 颜色定义 +# ============================================================================ +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[0;33m' +readonly BLUE='\033[0;34m' +readonly CYAN='\033[0;36m' +readonly MAGENTA='\033[0;35m' +readonly BOLD='\033[1m' +readonly NC='\033[0m' # 无颜色 + +# ============================================================================ +# 日志函数 +# ============================================================================ +log_info() { + echo -e "${GREEN}[信息]${NC} $*" +} + +log_warn() { + echo -e "${YELLOW}[警告]${NC} $*" +} + +log_error() { + echo -e "${RED}[错误]${NC} $*" >&2 +} + +log_success() { + echo -e "${GREEN}[成功]${NC} $*" +} + +log_title() { + echo -e "\n${CYAN}${BOLD}=== $* ===${NC}\n" +} + +# ============================================================================ +# 系统检测和初始化 +# ============================================================================ +init_system() { + # 检查root权限 + if [ "${EUID:-$(id -u)}" -ne 0 ]; then + log_error "需要root权限运行此脚本" + log_info "请使用: sudo bash $0" + exit 1 + fi + + # 检测操作系统 + if [ ! -f /etc/os-release ]; then + log_error "无法检测操作系统版本" + exit 1 + fi + + . /etc/os-release + OS_NAME="$NAME" + OS_VERSION="${VERSION_ID:-未知}" + + # 检测架构 + ARCH=$(uname -m) + case "$ARCH" in + x86_64|amd64) + ARCH_NAME="amd64" + ;; + aarch64|arm64) + ARCH_NAME="arm64" + ;; + *) + log_warn "未知架构: $ARCH" + ARCH_NAME="$ARCH" + ;; + esac + + # 检查是否为Debian/Ubuntu系统 + if [[ ! "$OS_NAME" =~ (Debian|Ubuntu) ]]; then + log_warn "此脚本主要为Debian/Ubuntu设计,当前系统: $OS_NAME" + read -p "是否继续? (y/n): " -n 1 -r < /dev/tty + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + exit 0 + fi + fi + + log_info "系统: $OS_NAME $OS_VERSION" + log_info "架构: $ARCH_NAME ($ARCH)" + + # 设置sudo组名 + SUDO_GROUP="sudo" +} + +# ============================================================================ +# 工具函数 +# ============================================================================ + +# 检查用户是否存在 +user_exists() { + id "$1" &>/dev/null +} + +# 检查组是否存在 +group_exists() { + getent group "$1" &>/dev/null +} + +# 获取用户的UID +get_user_uid() { + id -u "$1" 2>/dev/null +} + +# 获取用户的主组 +get_user_primary_group() { + id -gn "$1" 2>/dev/null +} + +# 获取用户的所有附加组 +get_user_groups() { + id -Gn "$1" 2>/dev/null | tr ' ' ',' +} + +# 检查用户是否在某个组中 +user_in_group() { + local username="$1" + local groupname="$2" + id -nG "$username" 2>/dev/null | grep -qw "$groupname" +} + +# 验证用户名格式 +validate_username() { + local username="$1" + if [[ ! "$username" =~ ^[a-z_][a-z0-9_-]*[$]?$ ]]; then + log_error "用户名格式无效: $username" + log_info "用户名必须以小写字母或下划线开头,只能包含小写字母、数字、下划线和连字符" + return 1 + fi + if [ ${#username} -gt 32 ]; then + log_error "用户名过长 (最大32字符): $username" + return 1 + fi + return 0 +} + +# 验证组名格式 +validate_groupname() { + local groupname="$1" + if [[ ! "$groupname" =~ ^[a-z_][a-z0-9_-]*[$]?$ ]]; then + log_error "组名格式无效: $groupname" + log_info "组名必须以小写字母或下划线开头,只能包含小写字母、数字、下划线和连字符" + return 1 + fi + if [ ${#groupname} -gt 32 ]; then + log_error "组名过长 (最大32字符): $groupname" + return 1 + fi + return 0 +} + +# 安全读取密码 +read_password() { + local password + local password_confirm + + while true; do + read -s -p "请输入密码: " password < /dev/tty + echo >&2 + + if [ ${#password} -lt 6 ]; then + log_error "密码长度至少6个字符" + continue + fi + + read -s -p "请再次输入密码: " password_confirm < /dev/tty + echo >&2 + + if [ "$password" != "$password_confirm" ]; then + log_error "两次输入的密码不一致" + continue + fi + + echo "$password" + return 0 + done +} + +# 确认操作 +confirm_action() { + local prompt="$1" + local response + read -p "${prompt} (y/n): " -n 1 -r response < /dev/tty + echo + [[ $response =~ ^[Yy]$ ]] +} + +# 短暂延迟以便用户查看结果(用于添加、删除、修改等操作) +show_result() { + sleep 1.5 +} + +# 等待用户按回车继续(用于查看、列出等操作) +pause_for_view() { + echo + read -p "按回车键返回菜单..." -r < /dev/tty +} + +# ============================================================================ +# 用户管理功能 +# ============================================================================ + +# 添加用户 +add_user() { + log_title "添加新用户" + + # 输入用户名 + local username + while true; do + read -p "请输入用户名: " username < /dev/tty + username=$(echo "$username" | xargs) # 去除首尾空格 + + if [ -z "$username" ]; then + log_error "用户名不能为空" + continue + fi + + if ! validate_username "$username"; then + continue + fi + + if user_exists "$username"; then + log_error "用户 '$username' 已存在" + continue + fi + + break + done + + # 输入主目录 + local homedir + read -p "主目录 (默认: /home/$username): " homedir < /dev/tty + homedir=${homedir:-/home/$username} + + # 输入Shell + local usershell + echo "可用的Shell:" + cat /etc/shells | grep -v "^#" | nl + read -p "Shell (默认: /bin/bash): " usershell < /dev/tty + usershell=${usershell:-/bin/bash} + + # 验证Shell是否存在 + if [ ! -f "$usershell" ]; then + log_warn "Shell '$usershell' 不存在,使用默认 /bin/bash" + usershell="/bin/bash" + fi + + # 输入密码 + log_info "设置用户密码 (最少6个字符)" + local password + password=$(read_password) + + # 创建用户 + log_info "正在创建用户 '$username'..." + if useradd -m -d "$homedir" -s "$usershell" "$username" 2>/dev/null; then + # 设置密码 + echo "$username:$password" | chpasswd + + log_success "用户 '$username' 创建成功" + log_info "UID: $(get_user_uid "$username")" + log_info "主目录: $homedir" + log_info "Shell: $usershell" + + # 询问是否添加sudo权限 + if confirm_action "是否授予sudo权限?"; then + add_user_to_sudo "$username" + fi + + # 询问是否添加到其他组 + if confirm_action "是否添加到其他组?"; then + add_user_to_groups_interactive "$username" + fi + else + log_error "创建用户失败" + return 1 + fi + + show_result +} + +# 删除用户 +delete_user() { + log_title "删除用户" + + # 列出普通用户 + list_normal_users_simple + + local username + read -p "请输入要删除的用户名: " username < /dev/tty + username=$(echo "$username" | xargs) + + if [ -z "$username" ]; then + log_error "用户名不能为空" + return 1 + fi + + if ! user_exists "$username"; then + log_error "用户 '$username' 不存在" + return 1 + fi + + # 获取用户信息 + local uid=$(get_user_uid "$username") + local homedir=$(getent passwd "$username" | cut -d: -f6) + + log_warn "即将删除用户: $username (UID: $uid)" + log_warn "主目录: $homedir" + + if ! confirm_action "确认删除此用户?"; then + log_info "已取消删除操作" + return 0 + fi + + # 询问是否删除主目录 + local delete_home="" + if confirm_action "是否同时删除主目录和邮件?"; then + delete_home="-r" + fi + + # 执行删除 + if userdel $delete_home "$username" 2>/dev/null; then + log_success "用户 '$username' 已删除" + else + log_error "删除用户失败" + fi + + show_result +} + +# 修改用户信息 +modify_user() { + log_title "修改用户信息" + + # 列出普通用户 + list_normal_users_simple + + local username + read -p "请输入要修改的用户名: " username < /dev/tty + username=$(echo "$username" | xargs) + + if [ -z "$username" ]; then + log_error "用户名不能为空" + return 1 + fi + + if ! user_exists "$username"; then + log_error "用户 '$username' 不存在" + return 1 + fi + + # 显示修改菜单 + while true; do + echo + log_info "当前用户: $username" + log_info "UID: $(get_user_uid "$username")" + log_info "主组: $(get_user_primary_group "$username")" + log_info "所有组: $(get_user_groups "$username")" + log_info "主目录: $(getent passwd "$username" | cut -d: -f6)" + log_info "Shell: $(getent passwd "$username" | cut -d: -f7)" + echo + echo "请选择要修改的项目:" + echo " 1) 修改主目录" + echo " 2) 修改Shell" + echo " 3) 修改主组" + echo " 4) 修改用户名" + echo " 5) 锁定/解锁用户" + echo " 0) 返回上级菜单" + echo + + local choice + read -p "请选择 [0-5]: " choice < /dev/tty + + case $choice in + 1) + modify_user_home "$username" + ;; + 2) + modify_user_shell "$username" + ;; + 3) + modify_user_primary_group "$username" + ;; + 4) + modify_username "$username" + return 0 + ;; + 5) + toggle_user_lock "$username" + ;; + 0) + return 0 + ;; + *) + log_error "无效的选择" + ;; + esac + done +} + +# 修改用户主目录 +modify_user_home() { + local username="$1" + local current_home=$(getent passwd "$username" | cut -d: -f6) + + log_info "当前主目录: $current_home" + local new_home + read -p "新主目录: " new_home < /dev/tty + + if [ -z "$new_home" ]; then + log_error "主目录不能为空" + return 1 + fi + + if usermod -d "$new_home" "$username" 2>/dev/null; then + log_success "主目录已修改为: $new_home" + + if confirm_action "是否移动现有文件到新目录?"; then + if [ -d "$current_home" ]; then + usermod -m -d "$new_home" "$username" 2>/dev/null + log_success "文件已移动" + fi + fi + else + log_error "修改主目录失败" + fi +} + +# 修改用户Shell +modify_user_shell() { + local username="$1" + local current_shell=$(getent passwd "$username" | cut -d: -f7) + + log_info "当前Shell: $current_shell" + echo "可用的Shell:" + cat /etc/shells | grep -v "^#" | nl + + local new_shell + read -p "新Shell: " new_shell < /dev/tty + + if [ -z "$new_shell" ]; then + log_error "Shell不能为空" + return 1 + fi + + if [ ! -f "$new_shell" ]; then + log_error "Shell '$new_shell' 不存在" + return 1 + fi + + if usermod -s "$new_shell" "$username" 2>/dev/null; then + log_success "Shell已修改为: $new_shell" + else + log_error "修改Shell失败" + fi +} + +# 修改用户主组 +modify_user_primary_group() { + local username="$1" + local current_group=$(get_user_primary_group "$username") + + log_info "当前主组: $current_group" + + # 列出所有组 + echo "系统中的组:" + getent group | cut -d: -f1 | column + + local new_group + read -p "新主组: " new_group < /dev/tty + + if [ -z "$new_group" ]; then + log_error "组名不能为空" + return 1 + fi + + if ! group_exists "$new_group"; then + log_error "组 '$new_group' 不存在" + if confirm_action "是否创建此组?"; then + if groupadd "$new_group" 2>/dev/null; then + log_success "组 '$new_group' 已创建" + else + log_error "创建组失败" + return 1 + fi + else + return 1 + fi + fi + + if usermod -g "$new_group" "$username" 2>/dev/null; then + log_success "主组已修改为: $new_group" + else + log_error "修改主组失败" + fi +} + +# 修改用户名 +modify_username() { + local old_username="$1" + + log_warn "修改用户名是一个敏感操作" + + local new_username + read -p "新用户名: " new_username < /dev/tty + new_username=$(echo "$new_username" | xargs) + + if [ -z "$new_username" ]; then + log_error "用户名不能为空" + return 1 + fi + + if ! validate_username "$new_username"; then + return 1 + fi + + if user_exists "$new_username"; then + log_error "用户 '$new_username' 已存在" + return 1 + fi + + if ! confirm_action "确认将 '$old_username' 改名为 '$new_username'?"; then + return 0 + fi + + if usermod -l "$new_username" "$old_username" 2>/dev/null; then + log_success "用户名已修改为: $new_username" + + # 询问是否同时修改主目录名 + if confirm_action "是否同时修改主目录名?"; then + local old_home=$(getent passwd "$new_username" | cut -d: -f6) + local new_home=$(dirname "$old_home")/"$new_username" + + if usermod -d "$new_home" -m "$new_username" 2>/dev/null; then + log_success "主目录已修改为: $new_home" + fi + fi + else + log_error "修改用户名失败" + fi +} + +# 锁定/解锁用户 +toggle_user_lock() { + local username="$1" + + # 检查用户是否被锁定 + if passwd -S "$username" 2>/dev/null | grep -q " L "; then + log_info "用户 '$username' 当前状态: 已锁定" + if confirm_action "是否解锁此用户?"; then + if passwd -u "$username" 2>/dev/null; then + log_success "用户已解锁" + else + log_error "解锁失败" + fi + fi + else + log_info "用户 '$username' 当前状态: 未锁定" + if confirm_action "是否锁定此用户?"; then + if passwd -l "$username" 2>/dev/null; then + log_success "用户已锁定" + else + log_error "锁定失败" + fi + fi + fi +} + +# 修改用户密码 +change_user_password() { + log_title "修改用户密码" + + list_normal_users_simple + + local username + read -p "请输入用户名: " username < /dev/tty + username=$(echo "$username" | xargs) + + if [ -z "$username" ]; then + log_error "用户名不能为空" + return 1 + fi + + if ! user_exists "$username"; then + log_error "用户 '$username' 不存在" + return 1 + fi + + log_info "为用户 '$username' 设置新密码" + local password + password=$(read_password) + + if echo "$username:$password" | chpasswd 2>/dev/null; then + log_success "密码修改成功" + else + log_error "密码修改失败" + fi + + show_result +} + +# 添加用户到sudo组 +add_user_to_sudo() { + local username="$1" + + if ! group_exists "$SUDO_GROUP"; then + log_warn "sudo组 ($SUDO_GROUP) 不存在,正在创建..." + if groupadd "$SUDO_GROUP" 2>/dev/null; then + log_success "sudo组已创建" + else + log_error "创建sudo组失败" + return 1 + fi + fi + + if user_in_group "$username" "$SUDO_GROUP"; then + log_info "用户 '$username' 已经拥有sudo权限" + return 0 + fi + + if usermod -aG "$SUDO_GROUP" "$username" 2>/dev/null; then + log_success "已授予用户 '$username' sudo权限" + else + log_error "授予sudo权限失败" + return 1 + fi +} + +# 交互式添加用户到多个组 +add_user_to_groups_interactive() { + local username="$1" + + echo "系统中的组:" + getent group | cut -d: -f1 | column + + local groups + read -p "请输入要添加的组 (用逗号或空格分隔): " groups < /dev/tty + + if [ -z "$groups" ]; then + return 0 + fi + + # 将逗号替换为空格 + groups=$(echo "$groups" | tr ',' ' ') + + for group in $groups; do + group=$(echo "$group" | xargs) + if [ -z "$group" ]; then + continue + fi + + if ! group_exists "$group"; then + log_warn "组 '$group' 不存在" + if confirm_action "是否创建组 '$group'?"; then + if groupadd "$group" 2>/dev/null; then + log_success "组 '$group' 已创建" + else + log_error "创建组 '$group' 失败" + continue + fi + else + continue + fi + fi + + if user_in_group "$username" "$group"; then + log_info "用户已在组 '$group' 中" + else + if usermod -aG "$group" "$username" 2>/dev/null; then + log_success "已将用户添加到组 '$group'" + else + log_error "添加到组 '$group' 失败" + fi + fi + done +} + +# ============================================================================ +# 组管理功能 +# ============================================================================ + +# 管理用户组成员 +manage_user_groups() { + log_title "管理用户组成员" + + list_normal_users_simple + + local username + read -p "请输入用户名: " username < /dev/tty + username=$(echo "$username" | xargs) + + if [ -z "$username" ]; then + log_error "用户名不能为空" + return 1 + fi + + if ! user_exists "$username"; then + log_error "用户 '$username' 不存在" + return 1 + fi + + while true; do + echo + log_info "用户: $username" + log_info "主组: $(get_user_primary_group "$username")" + log_info "所有组: $(get_user_groups "$username")" + echo + echo "请选择操作:" + echo " 1) 添加到组" + echo " 2) 从组中移除" + echo " 3) 添加/移除sudo权限" + echo " 0) 返回上级菜单" + echo + + local choice + read -p "请选择 [0-3]: " choice < /dev/tty + + case $choice in + 1) + add_user_to_groups_interactive "$username" + ;; + 2) + remove_user_from_group "$username" + ;; + 3) + toggle_sudo_permission "$username" + ;; + 0) + return 0 + ;; + *) + log_error "无效的选择" + ;; + esac + done +} + +# 从组中移除用户 +remove_user_from_group() { + local username="$1" + local current_groups=$(id -Gn "$username" | tr ' ' '\n' | grep -v "^$(get_user_primary_group "$username")$") + + if [ -z "$current_groups" ]; then + log_info "用户没有附加组" + return 0 + fi + + echo "用户 '$username' 的附加组:" + echo "$current_groups" | nl + + local groupname + read -p "请输入要移除的组名: " groupname < /dev/tty + groupname=$(echo "$groupname" | xargs) + + if [ -z "$groupname" ]; then + return 0 + fi + + if ! user_in_group "$username" "$groupname"; then + log_error "用户不在组 '$groupname' 中" + return 1 + fi + + if [ "$groupname" = "$(get_user_primary_group "$username")" ]; then + log_error "不能移除主组" + return 1 + fi + + if gpasswd -d "$username" "$groupname" 2>/dev/null; then + log_success "已将用户从组 '$groupname' 中移除" + else + log_error "移除失败" + fi +} + +# 切换sudo权限 +toggle_sudo_permission() { + local username="$1" + + if user_in_group "$username" "$SUDO_GROUP"; then + log_info "用户当前拥有sudo权限" + if confirm_action "是否移除sudo权限?"; then + if gpasswd -d "$username" "$SUDO_GROUP" 2>/dev/null; then + log_success "sudo权限已移除" + else + log_error "移除sudo权限失败" + fi + fi + else + log_info "用户当前没有sudo权限" + if confirm_action "是否授予sudo权限?"; then + add_user_to_sudo "$username" + fi + fi +} + +# 添加组 +add_group() { + log_title "添加新组" + + local groupname + while true; do + read -p "请输入组名: " groupname < /dev/tty + groupname=$(echo "$groupname" | xargs) + + if [ -z "$groupname" ]; then + log_error "组名不能为空" + continue + fi + + if ! validate_groupname "$groupname"; then + continue + fi + + if group_exists "$groupname"; then + log_error "组 '$groupname' 已存在" + continue + fi + + break + done + + # 询问是否指定GID + local gid_option="" + if confirm_action "是否指定GID?"; then + local gid + read -p "请输入GID: " gid < /dev/tty + if [[ "$gid" =~ ^[0-9]+$ ]]; then + gid_option="-g $gid" + else + log_warn "GID无效,将自动分配" + fi + fi + + if groupadd $gid_option "$groupname" 2>/dev/null; then + local new_gid=$(getent group "$groupname" | cut -d: -f3) + log_success "组 '$groupname' 创建成功 (GID: $new_gid)" + else + log_error "创建组失败" + fi + + show_result +} + +# 删除组 +delete_group() { + log_title "删除组" + + echo "系统中的组:" + getent group | awk -F: '$3 >= 1000 {print $1 " (GID: " $3 ")"}' | column + + local groupname + read -p "请输入要删除的组名: " groupname < /dev/tty + groupname=$(echo "$groupname" | xargs) + + if [ -z "$groupname" ]; then + log_error "组名不能为空" + return 1 + fi + + if ! group_exists "$groupname"; then + log_error "组 '$groupname' 不存在" + return 1 + fi + + # 检查是否有用户以此为主组 + local users_in_group=$(getent group "$groupname" | cut -d: -f4) + local primary_users=$(awk -F: -v gid="$(getent group "$groupname" | cut -d: -f3)" '$4 == gid {print $1}' /etc/passwd) + + if [ -n "$primary_users" ]; then + log_warn "以下用户以此组为主组:" + echo "$primary_users" + log_error "无法删除,请先修改这些用户的主组" + return 1 + fi + + if [ -n "$users_in_group" ]; then + log_warn "组中包含以下用户: $users_in_group" + fi + + if ! confirm_action "确认删除组 '$groupname'?"; then + log_info "已取消删除操作" + return 0 + fi + + if groupdel "$groupname" 2>/dev/null; then + log_success "组 '$groupname' 已删除" + else + log_error "删除组失败" + fi + + show_result +} + +# ============================================================================ +# 列表显示功能 +# ============================================================================ + +# 简单列出普通用户 +list_normal_users_simple() { + echo -e "${BLUE}系统普通用户:${NC}" + getent passwd | awk -F: '$3 >= 1000 && $3 < 65534 {printf " %s (UID: %s)\n", $1, $3}' + echo +} + +# 列出所有用户 +list_all_users() { + log_title "用户列表" + + echo -e "${CYAN}${BOLD}普通用户 (UID >= 1000):${NC}" + printf "%-20s %-8s %-15s %-20s %-30s\n" "用户名" "UID" "主组" "Shell" "主目录" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + getent passwd | awk -F: '$3 >= 1000 && $3 < 65534 {print $0}' | while IFS=: read -r username _ uid gid _ homedir shell; do + local primary_group=$(getent group "$gid" | cut -d: -f1) + printf "%-20s %-8s %-15s %-20s %-30s\n" "$username" "$uid" "$primary_group" "$shell" "$homedir" + done + + echo + local user_count=$(getent passwd | awk -F: '$3 >= 1000 && $3 < 65534 {count++} END {print count}') + log_info "普通用户总数: $user_count" + + pause_for_view +} + +# 列出所有用户详细信息 +list_all_users_detailed() { + log_title "所有用户详细信息" + + getent passwd | awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' | while read -r username; do + show_user_details "$username" + echo + done +} + +# 查看用户详细信息 +view_user_info() { + log_title "查看用户详细信息" + + local username + read -p "请输入用户名 (留空查看所有用户): " username < /dev/tty + username=$(echo "$username" | xargs) + + if [ -z "$username" ]; then + list_all_users_detailed + else + if ! user_exists "$username"; then + log_error "用户 '$username' 不存在" + return 1 + fi + + show_user_details "$username" + fi + + pause_for_view +} + +# 显示单个用户的详细信息 +show_user_details() { + local username="$1" + + echo + echo -e "${CYAN}${BOLD}用户详细信息: $username${NC}" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + local uid=$(get_user_uid "$username") + local gid=$(id -g "$username") + local primary_group=$(get_user_primary_group "$username") + local all_groups=$(get_user_groups "$username") + local homedir=$(getent passwd "$username" | cut -d: -f6) + local shell=$(getent passwd "$username" | cut -d: -f7) + local gecos=$(getent passwd "$username" | cut -d: -f5) + + echo -e "${GREEN}UID:${NC} $uid" + echo -e "${GREEN}GID:${NC} $gid" + echo -e "${GREEN}主组:${NC} $primary_group" + echo -e "${GREEN}所有组:${NC} $all_groups" + echo -e "${GREEN}主目录:${NC} $homedir" + echo -e "${GREEN}Shell:${NC} $shell" + [ -n "$gecos" ] && echo -e "${GREEN}备注:${NC} $gecos" + + # 检查主目录是否存在 + if [ -d "$homedir" ]; then + local home_size=$(du -sh "$homedir" 2>/dev/null | cut -f1) + echo -e "${GREEN}主目录大小:${NC} $home_size" + else + echo -e "${YELLOW}主目录不存在${NC}" + fi + + # 检查用户状态 + if passwd -S "$username" 2>/dev/null | grep -q " L "; then + echo -e "${GREEN}账户状态:${NC} ${RED}已锁定${NC}" + else + echo -e "${GREEN}账户状态:${NC} ${GREEN}正常${NC}" + fi + + # 显示最后登录时间 + local last_login=$(lastlog -u "$username" 2>/dev/null | tail -n 1) + if [ -n "$last_login" ]; then + echo -e "${GREEN}最后登录:${NC} $last_login" + fi + + # 检查sudo权限 + if user_in_group "$username" "$SUDO_GROUP"; then + echo -e "${GREEN}Sudo权限:${NC} ${GREEN}是${NC}" + else + echo -e "${GREEN}Sudo权限:${NC} 否" + fi + + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +} + +# 列出所有组 +list_all_groups() { + log_title "组列表" + + echo -e "${CYAN}${BOLD}系统组 (GID >= 1000):${NC}" + printf "%-25s %-8s %-50s\n" "组名" "GID" "成员" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + getent group | awk -F: '$3 >= 1000 {print $0}' | while IFS=: read -r groupname _ gid members; do + # 查找以此组为主组的用户 + local primary_users=$(awk -F: -v gid="$gid" '$4 == gid {printf "%s,", $1}' /etc/passwd | sed 's/,$//') + + # 合并主组用户和附加组成员 + local all_members="$members" + if [ -n "$primary_users" ]; then + if [ -n "$all_members" ]; then + all_members="$primary_users,$all_members" + else + all_members="$primary_users" + fi + fi + + printf "%-25s %-8s %-50s\n" "$groupname" "$gid" "$all_members" + done + + echo + local group_count=$(getent group | awk -F: '$3 >= 1000 {count++} END {print count}') + log_info "组总数: $group_count" + + pause_for_view +} + +# 查看组详细信息 +view_group_info() { + log_title "查看组详细信息" + + local groupname + read -p "请输入组名: " groupname < /dev/tty + groupname=$(echo "$groupname" | xargs) + + if [ -z "$groupname" ]; then + log_error "组名不能为空" + return 1 + fi + + if ! group_exists "$groupname"; then + log_error "组 '$groupname' 不存在" + return 1 + fi + + show_group_details "$groupname" + pause_for_view +} + +# 显示单个组的详细信息 +show_group_details() { + local groupname="$1" + + echo + echo -e "${CYAN}${BOLD}组详细信息: $groupname${NC}" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + local gid=$(getent group "$groupname" | cut -d: -f3) + local members=$(getent group "$groupname" | cut -d: -f4) + + echo -e "${GREEN}GID:${NC} $gid" + + # 查找以此组为主组的用户 + local primary_users=$(awk -F: -v gid="$gid" '$4 == gid {print $1}' /etc/passwd | tr '\n' ',' | sed 's/,$//') + + if [ -n "$primary_users" ]; then + echo -e "${GREEN}主组用户:${NC} $primary_users" + else + echo -e "${GREEN}主组用户:${NC} 无" + fi + + if [ -n "$members" ]; then + echo -e "${GREEN}附加成员:${NC} $members" + else + echo -e "${GREEN}附加成员:${NC} 无" + fi + + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +} + +# ============================================================================ +# 菜单系统 +# ============================================================================ + +# 显示主菜单 +show_main_menu() { + clear + echo -e "${CYAN}${BOLD}" + echo "╔════════════════════════════════════════════════════════════╗" + echo "║ Linux 用户和组管理工具 (增强版) ║" + echo "╚════════════════════════════════════════════════════════════╝" + echo -e "${NC}" + echo -e "${BLUE}系统信息:${NC} $OS_NAME $OS_VERSION ($ARCH_NAME)" + echo + echo -e "${YELLOW}${BOLD}用户管理:${NC}" + echo " 1) 添加用户" + echo " 2) 删除用户" + echo " 3) 修改用户信息" + echo " 4) 修改用户密码" + echo " 5) 查看用户详细信息" + echo " 6) 列出所有用户" + echo + echo -e "${YELLOW}${BOLD}组管理:${NC}" + echo " 7) 添加组" + echo " 8) 删除组" + echo " 9) 列出所有组" + echo " 10) 查看组详细信息" + echo + echo -e "${YELLOW}${BOLD}用户组关系:${NC}" + echo " 11) 管理用户组成员" + echo + echo -e "${YELLOW}${BOLD}其他:${NC}" + echo " 0) 退出" + echo +} + +# 主菜单循环 +main_menu() { + while true; do + show_main_menu + + local choice + read -p "请选择 [0-11]: " choice < /dev/tty + + case $choice in + 1) + add_user + ;; + 2) + delete_user + ;; + 3) + modify_user + ;; + 4) + change_user_password + ;; + 5) + view_user_info + ;; + 6) + list_all_users + ;; + 7) + add_group + ;; + 8) + delete_group + ;; + 9) + list_all_groups + ;; + 10) + view_group_info + ;; + 11) + manage_user_groups + ;; + 0) + echo + log_success "感谢使用,再见!" + exit 0 + ;; + *) + log_error "无效的选择,请重新输入" + sleep 1 + ;; + esac + done +} + +# ============================================================================ +# 主函数 +# ============================================================================ + +main() { + # 初始化系统 + init_system + + # 显示欢迎信息 + echo + log_success "系统初始化完成" + sleep 1 + + # 进入主菜单 + main_menu +} + +# 执行主函数 +main "$@"