From ffee41eabc636affc476539a9780431bf4b6a7db Mon Sep 17 00:00:00 2001 From: Olia Lisa Date: Fri, 26 Jun 2026 19:03:00 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0r2s=E5=9B=BA=E4=BB=B6?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- r2s.sh | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 r2s.sh diff --git a/r2s.sh b/r2s.sh new file mode 100644 index 0000000..136ef37 --- /dev/null +++ b/r2s.sh @@ -0,0 +1,209 @@ +#!/bin/bash +set -e + +# 安装 Image Builder 构建所需依赖 +install_dependencies() { + apt install -y build-essential libncurses-dev zlib1g-dev gawk git \ + gettext libssl-dev xsltproc rsync wget unzip python3 qemu-utils mkisofs zstd +} + +# 下载并解压 FriendlyARM NanoPi R2S 的 Image Builder +# 参数 1: ImmortalWrt 版本号,例如 25.12.0 +# 输出: 解压后的 Image Builder 目录绝对路径 +download_imagebuilder() { + local version="$1" + local target="rockchip-armv8" + local file="immortalwrt-imagebuilder-$version-$target.Linux-x86_64.tar.zst" + local url="https://downloads.immortalwrt.org/releases/$version/targets/rockchip/armv8/$file" + local folder="immortalwrt-imagebuilder-$version-$target.Linux-x86_64" + local marker="$folder/.ready" + + if [ -f "$marker" ]; then + echo "$(pwd)/$folder" + return 0 + fi + + # 如果目录存在但不完整,先清理 + if [ -d "$folder" ] && [ ! -f "$marker" ]; then + echo "[WARN] found incomplete folder, cleaning..." >&2 + rm -rf "$folder" + fi + + # 下载并覆盖同名压缩包 + wget -O "$file" "$url" >&2 + + # 解压 + tar -I zstd -xvf "$file" >&2 + + touch "$marker" + + echo "$(pwd)/$folder" +} + + +build(){ + # ============================================================= + # 设备 Profile + # 可在 Image Builder 目录运行 `make info` 查看所有可用 profile + # ============================================================= + PROFILE="friendlyarm_nanopi-r2s" + + # ============================================================= + # 自定义文件目录,映射到固件根文件系统 + # ============================================================= + FILES_DIR="files" + + SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + BUILDER_DIR="${1}" + + # ============================================================= + # 固件输出目录 + # ============================================================= + OUTPUT_DIR="$BUILDER_DIR/r2s_output" + PROJECT_OUTPUT_DIR="$SCRIPT_DIR/r2s_output" + + # ============================================================= + # 固件文件名附加标识,可留空 + # ============================================================= + EXTRA_IMAGE_NAME="r2s" + + # ============================================================= + # 根分区大小,单位 MB;留空则使用 imagebuilder 默认值 + # ============================================================= + ROOTFS_PARTSIZE="${2:-}" + + # ============================================================= + # 插件包列表 + # - 前面加 - 表示从固件中移除该包,例如 -dnsmasq + # - 每行一个,方便增删注释 + # ============================================================= + PKG_LIST=( + openssh-sftp-server + vim-full + nano-plus + bash + shadow-chsh + curl + luci-i18n-argon-config-zh-cn + luci-i18n-package-manager-zh-cn + luci-i18n-firewall-zh-cn + luci-i18n-arpbind-zh-cn + + # 现代终端工具 + ripgrep + diffutils + less + + # 分区扩容 + luci-i18n-diskman-zh-cn + cfdisk + resize2fs + e2fsprogs + losetup + + # 代理插件 + luci-i18n-daed-zh-cn + luci-i18n-homeproxy-zh-cn + sing-box + ) + + PACKAGES=$(printf "%s " "${PKG_LIST[@]}") + + GREEN="\033[0;32m" + YELLOW="\033[1;33m" + RED="\033[0;31m" + NC="\033[0m" + + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN} OpenWrt Image Builder 开始构建${NC}" + echo -e "${GREEN}========================================${NC}" + echo -e " Device : ${YELLOW}FriendlyARM NanoPi R2S${NC}" + echo -e " Target : ${YELLOW}rockchip/armv8${NC}" + echo -e " Profile : ${YELLOW}${PROFILE}${NC}" + echo -e " Files 目录 : ${YELLOW}${FILES_DIR}${NC}" + echo -e " 输出目录 : ${YELLOW}${OUTPUT_DIR}${NC}" + echo -e " 项目输出目录: ${YELLOW}${PROJECT_OUTPUT_DIR}${NC}" + echo -e " 镜像标识 : ${YELLOW}${EXTRA_IMAGE_NAME}${NC}" + echo "" + + cd "$BUILDER_DIR" + + mkdir -p "$FILES_DIR" + cp "${SCRIPT_DIR}"/files/* "$BUILDER_DIR/files/" -rf + + # 禁用 x86 Image Builder 中常见的额外镜像格式;rockchip 目标不存在时会自动跳过 + sed -i \ + -e 's/^CONFIG_ISO_IMAGES=y/# CONFIG_ISO_IMAGES is not set/' \ + -e 's/^CONFIG_QCOW2_IMAGES=y/# CONFIG_QCOW2_IMAGES is not set/' \ + -e 's/^CONFIG_VDI_IMAGES=y/# CONFIG_VDI_IMAGES is not set/' \ + -e 's/^CONFIG_VMDK_IMAGES=y/# CONFIG_VMDK_IMAGES is not set/' \ + -e 's/^CONFIG_VHDX_IMAGES=y/# CONFIG_VHDX_IMAGES is not set/' \ + .config + + if [ ! -f "Makefile" ]; then + echo -e "${RED}[错误] 未找到 Makefile,请在 imagebuilder 根目录下运行本脚本!${NC}" + exit 1 + fi + + mkdir -p "$OUTPUT_DIR" + + make image \ + PROFILE="$PROFILE" \ + PACKAGES="$PACKAGES" \ + FILES="$FILES_DIR" \ + BIN_DIR="$OUTPUT_DIR" \ + EXTRA_IMAGE_NAME="$EXTRA_IMAGE_NAME" \ + ${ROOTFS_PARTSIZE:+ROOTFS_PARTSIZE="$ROOTFS_PARTSIZE"} + + if [ $? -eq 0 ]; then + if [ "$OUTPUT_DIR" != "$PROJECT_OUTPUT_DIR" ]; then + if [ ! -d "$OUTPUT_DIR" ]; then + echo -e "${RED} 未找到构建输出目录: ${OUTPUT_DIR}${NC}" + exit 1 + fi + + if [ -e "$PROJECT_OUTPUT_DIR" ]; then + BACKUP_OUTPUT_DIR="${PROJECT_OUTPUT_DIR}.bak.$(date +%Y%m%d%H%M%S)" + if ! mv "$PROJECT_OUTPUT_DIR" "$BACKUP_OUTPUT_DIR"; then + echo -e "${RED} 备份已有输出目录失败: ${PROJECT_OUTPUT_DIR}${NC}" + exit 1 + fi + echo -e "${YELLOW} 已有输出目录,已备份到: ${BACKUP_OUTPUT_DIR}${NC}" + fi + + if ! mv "$OUTPUT_DIR" "$PROJECT_OUTPUT_DIR"; then + echo -e "${RED} 移动构建输出目录失败: ${OUTPUT_DIR} -> ${PROJECT_OUTPUT_DIR}${NC}" + exit 1 + fi + fi + + echo "" + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN} 构建成功!${NC}" + echo -e "${GREEN} 固件路径: ${PROJECT_OUTPUT_DIR}${NC}" + echo -e "${GREEN}========================================${NC}" + else + echo "" + echo -e "${RED}========================================${NC}" + echo -e "${RED} 构建失败,请检查上方错误日志${NC}" + echo -e "${RED}========================================${NC}" + exit 1 + fi +} + + +# 项目根目录,保证从任意位置执行 r2s.sh 都能找到其他资源 +project_dir="$(cd "$(dirname "$0")" && pwd)" +cd "$project_dir" + +# 要构建的 ImmortalWrt 版本 +version="25.12.0" + +# 根分区大小(单位: MB) +rootfs_partsize=500 + +install_dependencies + +builder_dir="$(download_imagebuilder "$version")" + +build $builder_dir $rootfs_partsize \ No newline at end of file