From b6bf96817e85cf819f9b64dbeb9346d05426d7ee Mon Sep 17 00:00:00 2001 From: shenmo Date: Fri, 28 Nov 2025 14:01:32 +0000 Subject: [PATCH 01/15] bump apm dummy version to 1.1.1 Signed-off-by: shenmo --- apm-dummy/DEBIAN/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm-dummy/DEBIAN/control b/apm-dummy/DEBIAN/control index f1502dd..d31e745 100755 --- a/apm-dummy/DEBIAN/control +++ b/apm-dummy/DEBIAN/control @@ -1,5 +1,5 @@ Package: apm -Version: 1.1 +Version: 1.1.1 Maintainer: shenmo Priority: optional Section: utils From 1865d994ce5641f13ce5c7d6825550e8456c2a36 Mon Sep 17 00:00:00 2001 From: shenmo Date: Wed, 3 Dec 2025 05:36:35 +0000 Subject: [PATCH 02/15] update src/usr/bin/amber-pm-convert. Signed-off-by: shenmo --- src/usr/bin/amber-pm-convert | 1 + 1 file changed, 1 insertion(+) diff --git a/src/usr/bin/amber-pm-convert b/src/usr/bin/amber-pm-convert index 0d30f89..0bed887 100755 --- a/src/usr/bin/amber-pm-convert +++ b/src/usr/bin/amber-pm-convert @@ -538,6 +538,7 @@ if [ -n "$DEB_PATH" ]; then exit 1 fi log.info "安装前检查通过,准备进行提取与修改..." + sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg mkdir -p /var/cache/apt/archives/partial # 提取 DEB 包内容并准备修改 log.info "提取并修改原DEB包..." From 306416d2e41777c97cf9faca5ad0d8fa37dc5b11 Mon Sep 17 00:00:00 2001 From: shenmo Date: Wed, 3 Dec 2025 08:27:54 +0000 Subject: [PATCH 03/15] update src/usr/bin/amber-pm-convert. Signed-off-by: shenmo --- src/usr/bin/amber-pm-convert | 967 ++++++++++++++++++----------------- 1 file changed, 484 insertions(+), 483 deletions(-) diff --git a/src/usr/bin/amber-pm-convert b/src/usr/bin/amber-pm-convert index 0bed887..6f7424f 100755 --- a/src/usr/bin/amber-pm-convert +++ b/src/usr/bin/amber-pm-convert @@ -1,41 +1,41 @@ #!/bin/bash # APM软件包转换器 - 将DEB包转换为APM格式 -log.warn() { echo -e "[\e[33mWARN\e[0m]: \e[1m$*\e[0m"; } +log.warn()  { echo -e "[\e[33mWARN\e[0m]:  \e[1m$*\e[0m"; } log.error() { echo -e "[\e[31mERROR\e[0m]: \e[1m$*\e[0m"; } -log.info() { echo -e "[\e[96mINFO\e[0m]: \e[1m$*\e[0m"; } +log.info()  { echo -e "[\e[96mINFO\e[0m]:  \e[1m$*\e[0m"; } log.debug() { echo -e "[\e[32mDEBUG\e[0m]: \e[1m$*\e[0m"; } SCRIPT_NAME=$(basename "$0") if ! command -v dpkg > /dev/null ; then - log.error "若想使用APM软件包转换器,您需先安装dpkg" - exit 1 +    log.error "若想使用APM软件包转换器,您需先安装dpkg" +    exit 1 fi # 显示用法信息 usage() { - echo "用法: $SCRIPT_NAME [--manual] --base [--base ...] " - echo " 或者在手动模式下不传入 DEB 文件: $SCRIPT_NAME --manual --base [--base ...]" - echo "" - echo "参数说明:" - echo " --manual 启用手动模式:融合挂载后打开交互 shell,退出 shell 后脚本继续" - echo " --basename 必填参数(非手动模式下),指定基础环境名称,可多次使用" - echo " deb文件路径 要转换的DEB文件路径(非手动且非空模式下必填)" - echo " --pkgname 可选参数,指定新包的包名(默认使用原DEB包名)" - echo " --version 可选参数,指定新包的版本号(默认在原版本后追加'-apm')" - echo "" - echo "示例:" - echo " $SCRIPT_NAME --base amber-pm-trixie /path/to/package.deb" - echo " $SCRIPT_NAME --manual --base amber-pm-trixie # 只融合挂载并进入手动 shell" - echo " $SCRIPT_NAME --manual --base amber-pm-trixie --pkgname newpkg --version 1.2.3 /path/to/package.deb" - echo "" - echo "说明: 最下层的base在最后面,从上到下写base" +    echo "用法: $SCRIPT_NAME [--manual] --base [--base ...] " +    echo "       或者在手动模式下不传入 DEB 文件: $SCRIPT_NAME --manual --base [--base ...]" +    echo "" +    echo "参数说明:" +    echo "  --manual     启用手动模式:融合挂载后打开交互 shell,退出 shell 后脚本继续" +    echo "  --basename   必填参数(非手动模式下),指定基础环境名称,可多次使用" +    echo "  deb文件路径  要转换的DEB文件路径(非手动且非空模式下必填)" +    echo "  --pkgname    可选参数,指定新包的包名(默认使用原DEB包名)" +    echo "  --version    可选参数,指定新包的版本号(默认在原版本后追加'-apm')" +    echo "" +    echo "示例:" +    echo "  $SCRIPT_NAME --base amber-pm-trixie /path/to/package.deb" +    echo "  $SCRIPT_NAME --manual --base amber-pm-trixie   # 只融合挂载并进入手动 shell" +    echo "  $SCRIPT_NAME --manual --base amber-pm-trixie --pkgname newpkg --version 1.2.3 /path/to/package.deb" +    echo "" +    echo "说明: 最下层的base在最后面,从上到下写base" } # 解析参数 -BASENAMES=() # 存放实际用于构建 overlay 的 base(可能会被递归添加) -BASENAMES_ORIG=() # 存放用户原始输入的 base 列表(用于 control 中 Depends 等) +BASENAMES=()        # 存放实际用于构建 overlay 的 base(可能会被递归添加) +BASENAMES_ORIG=()   # 存放用户原始输入的 base 列表(用于 control 中 Depends 等) DEB_PATH="" PKGNAME="" VERSION="" @@ -43,81 +43,81 @@ MANUAL_MODE=false # 简单参数解析(顺序敏感) while [ $# -gt 0 ]; do - case "$1" in - --base) - if [ -z "$2" ]; then - log.error "--base 后需要跟名称" - usage - exit 1 - fi - BASENAMES+=("$2") - BASENAMES_ORIG+=("$2") - shift 2 - ;; - --pkgname) - PKGNAME="$2" - shift 2 - ;; - --version) - VERSION="$2" - shift 2 - ;; - --manual) - MANUAL_MODE=true - shift - ;; - -*) - log.error "未知选项: $1" - usage - exit 1 - ;; - *) - # 非选项,视为 DEB 路径(只接受第一个非选项作为 DEB) - if [ -z "$DEB_PATH" ]; then - DEB_PATH="$1" - shift - else - log.error "未知参数或多余的参数: $1" - usage - exit 1 - fi - ;; - esac +    case "$1" in +        --base) +            if [ -z "$2" ]; then +                log.error "--base 后需要跟名称" +                usage +                exit 1 +            fi +            BASENAMES+=("$2") +            BASENAMES_ORIG+=("$2") +            shift 2 +            ;; +        --pkgname) +            PKGNAME="$2" +            shift 2 +            ;; +        --version) +            VERSION="$2" +            shift 2 +            ;; +        --manual) +            MANUAL_MODE=true +            shift +            ;; +        -*) +            log.error "未知选项: $1" +            usage +            exit 1 +            ;; +        *) +            # 非选项,视为 DEB 路径(只接受第一个非选项作为 DEB) +            if [ -z "$DEB_PATH" ]; then +                DEB_PATH="$1" +                shift +            else +                log.error "未知参数或多余的参数: $1" +                usage +                exit 1 +            fi +            ;; +    esac done # 基本参数验证: # 如果不是手动模式,则至少需要一个 --base 和一个 deb 文件 if [ "$MANUAL_MODE" = false ]; then - if [ ${#BASENAMES[@]} -eq 0 ] || [ -z "$DEB_PATH" ]; then - log.error "错误:非手动模式下至少需要一个 --base 参数 且 必须提供 DEB 文件路径" - usage - exit 1 - fi +    if [ ${#BASENAMES[@]} -eq 0 ] || [ -z "$DEB_PATH" ]; then +        log.error "错误:非手动模式下至少需要一个 --base 参数 且 必须提供 DEB 文件路径" +        usage +        exit 1 +    fi else - # 手动模式下允许没有 DEB_FILE,但仍然要有至少一个 base - if [ ${#BASENAMES[@]} -eq 0 ]; then - log.error "错误:手动模式下仍需提供至少一个 --base 参数" - usage - exit 1 - fi +    # 手动模式下允许没有 DEB_FILE,但仍然要有至少一个 base +    if [ ${#BASENAMES[@]} -eq 0 ]; then +        log.error "错误:手动模式下仍需提供至少一个 --base 参数" +        usage +        exit 1 +    fi fi # 如果传入了 DEB_PATH,检查文件是否存在 if [ -n "$DEB_PATH" ] && [ ! -f "$DEB_PATH" ]; then - log.error "错误:DEB文件不存在: $DEB_PATH" - exit 1 +    log.error "错误:DEB文件不存在: $DEB_PATH" +    exit 1 fi log.info "开始转换(手动模式: $MANUAL_MODE)" log.info "基础环境数量: ${#BASENAMES_ORIG[@]}" for i in "${!BASENAMES_ORIG[@]}"; do - log.info " 原始基础环境 $((i+1)): ${BASENAMES_ORIG[$i]}" +    log.info "  原始基础环境 $((i+1)): ${BASENAMES_ORIG[$i]}" done if [ -n "$DEB_PATH" ]; then - log.info "目标 DEB: $DEB_PATH" +    log.info "目标 DEB: $DEB_PATH" else - log.info "未提供 DEB 文件,处于纯手动模式(手动修改/安装/打包)" +    log.info "未提供 DEB 文件,处于纯手动模式(手动修改/安装/打包)" fi # 1. 创建临时工作目录 @@ -128,20 +128,20 @@ export CRAFT_DIR # 检查是否已挂载,避免重复挂载 cleanup_mount() { - if mountpoint -q "$CRAFT_DIR/mergedir"; then - log.info "解除挂载: $CRAFT_DIR/mergedir" - sudo umount "$CRAFT_DIR/mergedir" || true - fi +    if mountpoint -q "$CRAFT_DIR/mergedir"; then +        log.info "解除挂载: $CRAFT_DIR/mergedir" +        sudo umount "$CRAFT_DIR/mergedir" || true +    fi } # 清理函数 cleanup() { - log.info "开始清理..." - cleanup_mount - if [ -d "$CRAFT_DIR" ]; then - log.info "删除临时目录: $CRAFT_DIR" - sudo rm -rf "$CRAFT_DIR" - fi +    log.info "开始清理..." +    cleanup_mount +    if [ -d "$CRAFT_DIR" ]; then +        log.info "删除临时目录: $CRAFT_DIR" +        sudo rm -rf "$CRAFT_DIR" +    fi } # 设置退出时清理 @@ -149,52 +149,52 @@ trap cleanup EXIT # 递归获取info文件中的依赖 (会把新依赖追加到 BASENAMES 数组中) get_recursive_basenames() { - local basename="$1" - # 注意:根据之前脚本结构,info 存放在 /var/lib/apm/apm/files/ace-env/var/lib/apm//info - local base_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/$basename" - local info_file="$base_dir/info" +    local basename="$1" +    # 注意:根据之前脚本结构,info 存放在 /var/lib/apm/apm/files/ace-env/var/lib/apm//info +    local base_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/$basename" +    local info_file="$base_dir/info" - if [ -f "$info_file" ]; then - log.info "读取info文件: $info_file" - while IFS= read -r base; do - [[ -z "$base" ]] && continue - # 如果依赖的 base 没有被记录过,则递归添加 - local found=false - for existing in "${BASENAMES[@]}"; do - if [ "$existing" = "$base" ]; then - found=true - break - fi - done - if [ "$found" = false ]; then - BASENAMES+=("$base") - get_recursive_basenames "$base" - fi - done < "$info_file" - else - log.info "未找到info文件,跳过: $info_file" - fi +    if [ -f "$info_file" ]; then +        log.info "读取info文件: $info_file" +        while IFS= read -r base; do +            [[ -z "$base" ]] && continue +            # 如果依赖的 base 没有被记录过,则递归添加 +            local found=false +            for existing in "${BASENAMES[@]}"; do +                if [ "$existing" = "$base" ]; then +                    found=true +                    break +                fi +            done +            if [ "$found" = false ]; then +                BASENAMES+=("$base") +                get_recursive_basenames "$base" +            fi +        done < "$info_file" +    else +        log.info "未找到info文件,跳过: $info_file" +    fi } # 递归获取所有基础环境(从用户输入的 base 开始) for BASE in "${BASENAMES[@]}"; do - get_recursive_basenames "$BASE" +    get_recursive_basenames "$BASE" done # 如果用户传了 DEB,则读取原包信息(否则跳过) if [ -n "$DEB_PATH" ]; then - log.info "检查原DEB包信息..." - ORIG_PKGNAME=$(dpkg -f "$DEB_PATH" Package 2>/dev/null || echo "") - ORIG_VERSION=$(dpkg -f "$DEB_PATH" Version 2>/dev/null || echo "") - ORIG_ARCH=$(dpkg -f "$DEB_PATH" Architecture 2>/dev/null || echo "") +    log.info "检查原DEB包信息..." +    ORIG_PKGNAME=$(dpkg -f "$DEB_PATH" Package 2>/dev/null || echo "") +    ORIG_VERSION=$(dpkg -f "$DEB_PATH" Version 2>/dev/null || echo "") +    ORIG_ARCH=$(dpkg -f "$DEB_PATH" Architecture 2>/dev/null || echo "") - log.info "原包名: ${ORIG_PKGNAME:-未知}" - log.info "原版本: ${ORIG_VERSION:-未知}" - log.info "原架构: ${ORIG_ARCH:-unknown}" +    log.info "原包名: ${ORIG_PKGNAME:-未知}" +    log.info "原版本: ${ORIG_VERSION:-未知}" +    log.info "原架构: ${ORIG_ARCH:-unknown}" else - ORIG_PKGNAME="" - ORIG_VERSION="" - ORIG_ARCH="$(dpkg --print-architecture 2>/dev/null || echo "unknown")" +    ORIG_PKGNAME="" +    ORIG_VERSION="" +    ORIG_ARCH="$(dpkg --print-architecture 2>/dev/null || echo "unknown")" fi # 设置新包名和版本(若手动模式且未指定,则稍后询问) @@ -210,21 +210,21 @@ log.info "构建 overlay lowerdir 路径..." LOWERDIRS=() for BASENAME in "${BASENAMES[@]}"; do - ACE_ENV_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/ace-env" - CORE_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/core" +    ACE_ENV_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/ace-env" +    CORE_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/core" - if [ -d "$ACE_ENV_PATH" ]; then - log.info "使用 ace-env 路径: $ACE_ENV_PATH" - LOWERDIRS+=("$ACE_ENV_PATH") - elif [ -d "$CORE_PATH" ]; then - log.info "使用 core 路径: $CORE_PATH" - LOWERDIRS+=("$CORE_PATH") - else - log.error "错误:基础环境路径不存在: $BASENAME" - log.error " 检查的路径: $ACE_ENV_PATH" - log.error " 检查的路径: $CORE_PATH" - exit 1 - fi +    if [ -d "$ACE_ENV_PATH" ]; then +        log.info "使用 ace-env 路径: $ACE_ENV_PATH" +        LOWERDIRS+=("$ACE_ENV_PATH") +    elif [ -d "$CORE_PATH" ]; then +        log.info "使用 core 路径: $CORE_PATH" +        LOWERDIRS+=("$CORE_PATH") +    else +        log.error "错误:基础环境路径不存在: $BASENAME" +        log.error "  检查的路径: $ACE_ENV_PATH" +        log.error "  检查的路径: $CORE_PATH" +        exit 1 +    fi done # 将 lowerdirs 数组用冒号连接 @@ -234,12 +234,12 @@ log.debug "最终 lowerdir: $LOWERDIR" # 3. 进行融合挂载 log.info "正在进行融合挂载..." sudo mount -t overlay overlay \ - -o "lowerdir=$LOWERDIR,upperdir=$CRAFT_DIR/core/,workdir=$CRAFT_DIR/work/" \ - "$CRAFT_DIR/mergedir" +    -o "lowerdir=$LOWERDIR,upperdir=$CRAFT_DIR/core/,workdir=$CRAFT_DIR/work/" \ +    "$CRAFT_DIR/mergedir" if ! mountpoint -q "$CRAFT_DIR/mergedir"; then - log.error "错误:融合挂载失败" - exit 1 +    log.error "错误:融合挂载失败" +    exit 1 fi log.info "挂载完成: $CRAFT_DIR/mergedir" @@ -250,350 +250,351 @@ log.debug "已导出 chrootEnvPath=$chrootEnvPath" # 如果在手动模式下,立即打开交互 shell 并在退出后继续脚本 if [ "$MANUAL_MODE" = true ]; then - log.info "进入手动模式:将在融合挂载环境中打开交互 shell(使用 ace-run-pkg)。" - log.info "在 shell 中,您可以手动修改、测试安装或进行其他操作。退出 shell 后脚本将继续。" - # 启动交互 shell,保留环境变量(使用 sudo -E) - sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || { - log.warn "ace-run-pkg shell 退出或出现错误,继续脚本..." - } - log.info "用户已退出手动 shell,脚本将继续。" - # 如果没有 DEB,询问是否要进行后续打包(允许返回 shell) - if [ -z "$DEB_PATH" ]; then - while true; do - echo "" - read -r -p "未提供 DEB 文件。是否现在进行新 APM 包的自动打包? (y = 打包, r = 返回 shell, n = 跳过打包) [y/r/n]: " yn - case "$yn" in - y|Y) - # 如果缺少包名或版本,交互询问 - if [ -z "$NEW_PKGNAME" ]; then - read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME - fi - if [ -z "$NEW_VERSION" ] || [[ "$NEW_VERSION" == "-apm" ]]; then - read -r -p "请输入要创建的版本 (Version): " NEW_VERSION - fi - break - ;; - r|R) - log.info "返回交互 shell(使用 ace-run-pkg)。退出 shell 后再次询问。" - sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || true - ;; - n|N) - log.info "跳过自动打包。脚本结束。" - exit 0 - ;; - *) - echo "请输入 y, r, 或 n。" - ;; - esac - done - fi +    log.info "进入手动模式:将在融合挂载环境中打开交互 shell(使用 ace-run-pkg)。" +    log.info "在 shell 中,您可以手动修改、测试安装或进行其他操作。退出 shell 后脚本将继续。" +    # 启动交互 shell,保留环境变量(使用 sudo -E) +    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || { +        log.warn "ace-run-pkg shell 退出或出现错误,继续脚本..." +    } +    log.info "用户已退出手动 shell,脚本将继续。" +    # 如果没有 DEB,询问是否要进行后续打包(允许返回 shell) +    if [ -z "$DEB_PATH" ]; then +        while true; do +            echo "" +            read -r -p "未提供 DEB 文件。是否现在进行新 APM 包的自动打包? (y = 打包, r = 返回 shell, n = 跳过打包) [y/r/n]: " yn +            case "$yn" in +                y|Y) +                    # 如果缺少包名或版本,交互询问 +                    if [ -z "$NEW_PKGNAME" ]; then +                        read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME +                    fi +                    if [ -z "$NEW_VERSION" ] || [[ "$NEW_VERSION" == "-apm" ]]; then +                        read -r -p "请输入要创建的版本 (Version): " NEW_VERSION +                    fi +                    break +                    ;; +                r|R) +                    log.info "返回交互 shell(使用 ace-run-pkg)。退出 shell 后再次询问。" +                    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || true +                    ;; +                n|N) +                    log.info "跳过自动打包。脚本结束。" +                    exit 0 +                    ;; +                *) +                    echo "请输入 y, r, 或 n。" +                    ;; +            esac +        done +    fi fi # 到这里:非手动模式或手动模式退出后继续(如果是非手动并且有 DEB,继续原本流程) # 函数:查找并处理符号链接,返回实际文件路径 resolve_symlink() { - local file="$1" - local target_dir="$2" - - if [ -L "$file" ]; then - # 获取符号链接目标 - local target=$(readlink "$file") - - # 如果目标是绝对路径,则在目标目录中查找 - if [[ "$target" == /* ]]; then - local resolved_path="$target_dir${target}" - if [ -f "$resolved_path" ]; then - echo "$resolved_path" - return 0 - fi - else - # 相对路径,在符号链接所在目录解析 - local link_dir=$(dirname "$file") - local resolved_path="$link_dir/$target" - if [ -f "$resolved_path" ]; then - echo "$resolved_path" - return 0 - fi - fi - fi - - # 如果不是符号链接或解析失败,返回原文件 - echo "$file" +    local file="$1" +    local target_dir="$2" +     +    if [ -L "$file" ]; then +        # 获取符号链接目标 +        local target=$(readlink "$file") +         +        # 如果目标是绝对路径,则在目标目录中查找 +        if [[ "$target" == /* ]]; then +            local resolved_path="$target_dir${target}" +            if [ -f "$resolved_path" ]; then +                echo "$resolved_path" +                return 0 +            fi +        else +            # 相对路径,在符号链接所在目录解析 +            local link_dir=$(dirname "$file") +            local resolved_path="$link_dir/$target" +            if [ -f "$resolved_path" ]; then +                echo "$resolved_path" +                return 0 +            fi +        fi +    fi +     +    # 如果不是符号链接或解析失败,返回原文件 +    echo "$file" } # 函数:交互式选择文件复制到entries目录(用于手动模式无DEB情况) interactive_copy_entries() { - local core_dir="$CRAFT_DIR/core" - local entries_dir="$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries" - - log.info "开始交互式选择文件复制到 entries 目录..." - mkdir -p "$entries_dir/applications" "$entries_dir/icons" - - # 查找桌面文件 - local desktop_files=() - while IFS= read -r -d '' file; do - [[ -f "$file" ]] && desktop_files+=("$file") - done < <(find "$core_dir/usr/share" -name "*.desktop" -print0 2>/dev/null || true) - - # 查找图标文件 - local icon_files=() - while IFS= read -r -d '' file; do - [[ -f "$file" ]] && icon_files+=("$file") - done < <(find "$core_dir/usr/share" \( -name "*.png" -o -name "*.svg" -o -name "*.xpm" \) -print0 2>/dev/null || true) - - # 处理桌面文件 - if [ ${#desktop_files[@]} -gt 0 ]; then - log.info "找到 ${#desktop_files[@]} 个桌面文件:" - for i in "${!desktop_files[@]}"; do - local file="${desktop_files[$i]}" - local filename=$(basename "$file") - echo " $((i+1)). $filename" - - # 检查是否是符号链接 - if [ -L "$file" ]; then - local target=$(readlink "$file") - echo " → 符号链接指向: $target" - # 解析符号链接获取实际文件 - local resolved_file=$(resolve_symlink "$file" "$core_dir") - if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then - echo " → 解析为: $(basename "$resolved_file")" - desktop_files[$i]="$resolved_file" - fi - fi - done - - echo "" - read -r -p "请选择要复制的桌面文件编号(多个用逗号分隔,all=全部,none=跳过): " desktop_choice - - if [[ "$desktop_choice" =~ ^[Aa][Ll][Ll]$ ]]; then - # 复制所有桌面文件到 entries/applications - for file in "${desktop_files[@]}"; do - local filename=$(basename "$file") - local dest_path="$entries_dir/applications/$filename" - cp -v "$file" "$dest_path" - - # 处理桌面文件内容 - process_desktop_file "$dest_path" "$NEW_PKGNAME" - done - elif [[ ! "$desktop_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$desktop_choice" ]; then - # 处理选择的文件 - IFS=',' read -ra choices <<< "$desktop_choice" - for choice in "${choices[@]}"; do - choice=$(echo "$choice" | tr -d ' ') - if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#desktop_files[@]} ]; then - local idx=$((choice-1)) - local file="${desktop_files[$idx]}" - local filename=$(basename "$file") - local dest_path="$entries_dir/applications/$filename" - cp -v "$file" "$dest_path" - - # 处理桌面文件内容 - process_desktop_file "$dest_path" "$NEW_PKGNAME" - else - log.warn "无效的选择: $choice" - fi - done - else - log.info "跳过桌面文件复制" - fi - else - log.info "未找到桌面文件" - fi - - # 处理图标文件 - if [ ${#icon_files[@]} -gt 0 ]; then - log.info "找到 ${#icon_files[@]} 个图标文件:" - for i in "${!icon_files[@]}"; do - local file="${icon_files[$i]}" - local filename=$(basename "$file") - echo " $((i+1)). $filename" - - # 检查是否是符号链接 - if [ -L "$file" ]; then - local target=$(readlink "$file") - echo " → 符号链接指向: $target" - # 解析符号链接获取实际文件 - local resolved_file=$(resolve_symlink "$file" "$core_dir") - if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then - echo " → 解析为: $(basename "$resolved_file")" - icon_files[$i]="$resolved_file" - fi - fi - done - - echo "" - read -r -p "请选择要复制的图标文件编号(多个用逗号分隔,all=全部,none=跳过): " icon_choice - - if [[ "$icon_choice" =~ ^[Aa][Ll][Ll]$ ]]; then - # 复制所有图标文件到 entries/icons - for file in "${icon_files[@]}"; do - local filename=$(basename "$file") - local dest_path="$entries_dir/icons/$filename" - cp -v "$file" "$dest_path" - done - elif [[ ! "$icon_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$icon_choice" ]; then - # 处理选择的文件 - IFS=',' read -ra choices <<< "$icon_choice" - for choice in "${choices[@]}"; do - choice=$(echo "$choice" | tr -d ' ') - if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#icon_files[@]} ]; then - local idx=$((choice-1)) - local file="${icon_files[$idx]}" - local filename=$(basename "$file") - local dest_path="$entries_dir/icons/$filename" - cp -v "$file" "$dest_path" - else - log.warn "无效的选择: $choice" - fi - done - else - log.info "跳过图标文件复制" - fi - else - log.info "未找到图标文件" - fi +    local core_dir="$CRAFT_DIR/core" +    local entries_dir="$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries" +     +    log.info "开始交互式选择文件复制到 entries 目录..." +    mkdir -p "$entries_dir/applications" "$entries_dir/icons" +     +    # 查找桌面文件 +    local desktop_files=() +    while IFS= read -r -d '' file; do +        [[ -f "$file" ]] && desktop_files+=("$file") +    done < <(find "$core_dir/usr/share" -name "*.desktop" -print0 2>/dev/null || true) +     +    # 查找图标文件 +    local icon_files=() +    while IFS= read -r -d '' file; do +        [[ -f "$file" ]] && icon_files+=("$file") +    done < <(find "$core_dir/usr/share" \( -name "*.png" -o -name "*.svg" -o -name "*.xpm" \) -print0 2>/dev/null || true) +     +    # 处理桌面文件 +    if [ ${#desktop_files[@]} -gt 0 ]; then +        log.info "找到 ${#desktop_files[@]} 个桌面文件:" +        for i in "${!desktop_files[@]}"; do +            local file="${desktop_files[$i]}" +            local relative_path="${file#$core_dir}" # 获取相对于 core_dir 的路径 +            echo "  $((i+1)). $relative_path" # 打印相对路径 +             +            # 检查是否是符号链接 +            if [ -L "$file" ]; then +                local target=$(readlink "$file") +                echo "      → 符号链接指向: $target" +                # 解析符号链接获取实际文件 +                local resolved_file=$(resolve_symlink "$file" "$core_dir") +                if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then +                    local resolved_relative_path="${resolved_file#$core_dir}" +                    echo "      → 解析为: $resolved_relative_path" +                    desktop_files[$i]="$resolved_file" +                fi +            fi +        done +         +        echo "" +        read -r -p "请选择要复制的桌面文件编号(多个用逗号分隔,all=全部,none=跳过): " desktop_choice +         +        if [[ "$desktop_choice" =~ ^[Aa][Ll][Ll]$ ]]; then +            # 复制所有桌面文件到 entries/applications +            for file in "${desktop_files[@]}"; do +                local filename=$(basename "$file") +                local dest_path="$entries_dir/applications/$filename" +                cp -v "$file" "$dest_path" +                 +                # 处理桌面文件内容 +                process_desktop_file "$dest_path" "$NEW_PKGNAME" +            done +        elif [[ ! "$desktop_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$desktop_choice" ]; then +            # 处理选择的文件 +            IFS=',' read -ra choices <<< "$desktop_choice" +            for choice in "${choices[@]}"; do +                choice=$(echo "$choice" | tr -d ' ') +                if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#desktop_files[@]} ]; then +                    local idx=$((choice-1)) +                    local file="${desktop_files[$idx]}" +                    local filename=$(basename "$file") +                    local dest_path="$entries_dir/applications/$filename" +                    cp -v "$file" "$dest_path" +                     +                    # 处理桌面文件内容 +                    process_desktop_file "$dest_path" "$NEW_PKGNAME" +                else +                    log.warn "无效的选择: $choice" +                fi +            done +        else +            log.info "跳过桌面文件复制" +        fi +    else +        log.info "未找到桌面文件" +    fi +     +    # 处理图标文件 +    if [ ${#icon_files[@]} -gt 0 ]; then +        log.info "找到 ${#icon_files[@]} 个图标文件:" +        for i in "${!icon_files[@]}"; do +            local file="${icon_files[$i]}" +            local relative_path="${file#$core_dir}"  # <-- 修改:获取相对于 core_dir 的路径 +            echo "  $((i+1)). $relative_path"          # <-- 修改:打印相对路径 +             +            # 检查是否是符号链接 +            if [ -L "$file" ]; then +                local target=$(readlink "$file") +                echo "      → 符号链接指向: $target" +                # 解析符号链接获取实际文件 +                local resolved_file=$(resolve_symlink "$file" "$core_dir") +                if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then +                    local resolved_relative_path="${resolved_file#$core_dir}" # <-- 修改:计算解析后的相对路径 +                    echo "      → 解析为: $resolved_relative_path"              # <-- 修改:打印解析后的相对路径 +                    icon_files[$i]="$resolved_file" +                fi +            fi +        done +         +        echo "" +        read -r -p "请选择要复制的图标文件编号(多个用逗号分隔,all=全部,none=跳过): " icon_choice +         +        if [[ "$icon_choice" =~ ^[Aa][Ll][Ll]$ ]]; then +            # 复制所有图标文件到 entries/icons +            for file in "${icon_files[@]}"; do +                local filename=$(basename "$file") +                local dest_path="$entries_dir/icons/$filename" +                cp -v "$file" "$dest_path" +            done +        elif [[ ! "$icon_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$icon_choice" ]; then +            # 处理选择的文件 +            IFS=',' read -ra choices <<< "$icon_choice" +            for choice in "${choices[@]}"; do +                choice=$(echo "$choice" | tr -d ' ') +                if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#icon_files[@]} ]; then +                    local idx=$((choice-1)) +                    local file="${icon_files[$idx]}" +                    local filename=$(basename "$file") +                    local dest_path="$entries_dir/icons/$filename" +                    cp -v "$file" "$dest_path" +                else +                    log.warn "无效的选择: $choice" +                fi +            done +        else +            log.info "跳过图标文件复制" +        fi +    else +        log.info "未找到图标文件" +    fi } -# 函数:处理桌面文件内容 # 函数:处理桌面文件内容(安全版本,避免重复处理) process_desktop_file() { - local desktop_file="$1" - local pkgname="$2" - # 新增:精确路径检查 - local apps_path1="/usr/share/applications" - local apps_path2="/opt/apps/${ORIG_PKGNAME}/entries/applications" - local apps_path3="/usr/local/share/applications" - - if [[ ! "$desktop_file" =~ ^.*${apps_path1}/.*\.desktop$ ]] && - [[ ! "$desktop_file" =~ ^.*${apps_path2}/.*\.desktop$ ]] && - [[ ! "$desktop_file" =~ ^.*${apps_path3}/.*\.desktop$ ]]; then - log.debug "跳过非应用程序 desktop 文件: $desktop_file" - return 0 - fi - - log.info "处理桌面文件: $desktop_file" - - # 检查文件是否已经处理过(避免重复添加 apm run) - if grep -q "^Exec=apm run $pkgname " "$desktop_file"; then - log.info "桌面文件已经处理过,跳过: $desktop_file" - return 0 - fi - - # 检查是否有其他包的 apm run 前缀(清理旧的) - if grep -q "^Exec=apm run [^ ]* " "$desktop_file"; then - log.info "发现旧的 apm run 前缀,清理后重新添加" - # 移除所有 apm run 前缀 - sed -i "s|^Exec=apm run [^ ]* ||" "$desktop_file" - fi - - # 尝试用 busybox dos2unix(若不存在则跳过转换) - if command -v busybox >/dev/null 2>&1; then - busybox dos2unix "$desktop_file" 2>/dev/null || true - else - dos2unix "$desktop_file" 2>/dev/null || true - fi - - # 处理 Exec 行:在原有命令前追加 apm run $pkgname - if grep -q '^Exec=' "$desktop_file"; then - sed -i "s|^Exec=\(.*\)$|Exec=apm run $pkgname \1|" "$desktop_file" - fi - - # 删除 TryExec 行 - if grep -q '^TryExec=' "$desktop_file"; then - sed -i '/^TryExec=/d' "$desktop_file" - log.info "已删除 TryExec 行" - fi - - # 处理 Icon 路径(若以 / 开头) - if grep -q '^Icon=/' "$desktop_file"; then - sed -i "s|^Icon=/|Icon=/var/lib/apm/apm/files/ace-env/var/lib/apm/$pkgname/files/core/|" "$desktop_file" - fi - - # 添加 X-APM-APPID(如果不存在) - if ! grep -q "X-APM-APPID" "$desktop_file"; then - echo "" >> "$desktop_file" - echo "X-APM-APPID=$pkgname" >> "$desktop_file" - fi - - # 检查修改结果并打印调试 - if grep -q "apm run $pkgname" "$desktop_file"; then - log.info "桌面文件修改成功: $desktop_file" - else - log.warn "桌面文件可能未正确修改: $desktop_file" - fi +    local desktop_file="$1" +    local pkgname="$2" +    # 新增:精确路径检查 +    local apps_path1="/usr/share/applications" +    local apps_path2="/opt/apps/${ORIG_PKGNAME}/entries/applications" +    local apps_path3="/usr/local/share/applications" +     +    if [[ ! "$desktop_file" =~ ^.*${apps_path1}/.*\.desktop$ ]] &&  +       [[ ! "$desktop_file" =~ ^.*${apps_path2}/.*\.desktop$ ]] && +       [[ ! "$desktop_file" =~ ^.*${apps_path3}/.*\.desktop$ ]]; then +        log.debug "跳过非应用程序 desktop 文件: $desktop_file" +        return 0 +    fi +     +    log.info "处理桌面文件: $desktop_file" +     +    # 检查文件是否已经处理过(避免重复添加 apm run) +    if grep -q "^Exec=apm run $pkgname " "$desktop_file"; then +        log.info "桌面文件已经处理过,跳过: $desktop_file" +        return 0 +    fi +     +    # 检查是否有其他包的 apm run 前缀(清理旧的) +    if grep -q "^Exec=apm run [^ ]* " "$desktop_file"; then +        log.info "发现旧的 apm run 前缀,清理后重新添加" +        # 移除所有 apm run 前缀 +        sed -i "s|^Exec=apm run [^ ]* ||" "$desktop_file" +    fi +     +    # 尝试用 busybox dos2unix(若不存在则跳过转换) +    if command -v busybox >/dev/null 2>&1; then +        busybox dos2unix "$desktop_file" 2>/dev/null || true +    else +        dos2unix "$desktop_file" 2>/dev/null || true +    fi +     +    # 处理 Exec 行:在原有命令前追加 apm run $pkgname +    if grep -q '^Exec=' "$desktop_file"; then +        sed -i "s|^Exec=\(.*\)$|Exec=apm run $pkgname \1|" "$desktop_file" +    fi +     +    # 删除 TryExec 行 +    if grep -q '^TryExec=' "$desktop_file"; then +        sed -i '/^TryExec=/d' "$desktop_file" +        log.info "已删除 TryExec 行" +    fi +     +    # 处理 Icon 路径(若以 / 开头) +    if grep -q '^Icon=/' "$desktop_file"; then +        sed -i "s|^Icon=/|Icon=/var/lib/apm/apm/files/ace-env/var/lib/apm/$pkgname/files/core/|" "$desktop_file" +    fi +     +    # 添加 X-APM-APPID(如果不存在) +    if ! grep -q "X-APM-APPID" "$desktop_file"; then +        echo "" >> "$desktop_file" +        echo "X-APM-APPID=$pkgname" >> "$desktop_file" +    fi +     +    # 检查修改结果并打印调试 +    if grep -q "apm run $pkgname" "$desktop_file"; then +        log.info "桌面文件修改成功: $desktop_file" +    else +        log.warn "桌面文件可能未正确修改: $desktop_file" +    fi } # 4. 如果有 DEB 文件,进行自动化的检查、解包与修改 if [ -n "$DEB_PATH" ]; then - # 在融合环境中更新包列表并做 dry-run 检查(如果 ace-run-pkg aptss 可用) - log.info "在融合环境中测试安装 DEB 包(dry-run)..." - sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss update || log.warn "aptss update 返回非零状态,继续但请注意" - if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss install "$DEB_PATH" --dry-run ; then - log.error "错误:安装前检查失败,DEB包可能无法在基础环境中安装" - log.error "请检查依赖关系或基础环境是否兼容" - exit 1 - fi - log.info "安装前检查通过,准备进行提取与修改..." - sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg mkdir -p /var/cache/apt/archives/partial +    # 在融合环境中更新包列表并做 dry-run 检查(如果 ace-run-pkg aptss 可用) +    log.info "在融合环境中测试安装 DEB 包(dry-run)..." +    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss update || log.warn "aptss update 返回非零状态,继续但请注意" +    if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss install "$DEB_PATH" --dry-run ; then +        log.error "错误:安装前检查失败,DEB包可能无法在基础环境中安装" +        log.error "请检查依赖关系或基础环境是否兼容" +        exit 1 +    fi +    log.info "安装前检查通过,准备进行提取与修改..." +    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg mkdir -p /var/cache/apt/archives/partial - # 提取 DEB 包内容并准备修改 - log.info "提取并修改原DEB包..." - EXTRACT_DIR="$CRAFT_DIR/extract" - MODIFIED_DEB_DIR="$CRAFT_DIR/modified_deb" - mkdir -p "$EXTRACT_DIR" - mkdir -p "$MODIFIED_DEB_DIR/DEBIAN" +    # 提取 DEB 包内容并准备修改 +    log.info "提取并修改原DEB包..." +    EXTRACT_DIR="$CRAFT_DIR/extract" +    MODIFIED_DEB_DIR="$CRAFT_DIR/modified_deb" +    mkdir -p "$EXTRACT_DIR" +    mkdir -p "$MODIFIED_DEB_DIR/DEBIAN" - dpkg -x "$DEB_PATH" "$EXTRACT_DIR" - dpkg -e "$DEB_PATH" "$MODIFIED_DEB_DIR/DEBIAN" +    dpkg -x "$DEB_PATH" "$EXTRACT_DIR" +    dpkg -e "$DEB_PATH" "$MODIFIED_DEB_DIR/DEBIAN" - # 处理 .desktop 文件 - DESKTOP_MODIFIED=false - while IFS= read -r desktop_file; do - [ -z "$desktop_file" ] && continue - process_desktop_file "$desktop_file" "${NEW_PKGNAME:-$ORIG_PKGNAME}" - DESKTOP_MODIFIED=true - done < <(find "$EXTRACT_DIR" -name "*.desktop" -print) +    # 处理 .desktop 文件 +    DESKTOP_MODIFIED=false +    while IFS= read -r desktop_file; do +        [ -z "$desktop_file" ] && continue +        process_desktop_file "$desktop_file" "${NEW_PKGNAME:-$ORIG_PKGNAME}" +        DESKTOP_MODIFIED=true +    done < <(find "$EXTRACT_DIR" -name "*.desktop" -print) - if [ "$DESKTOP_MODIFIED" = false ]; then - log.info "未找到需要修改的 .desktop 文件" - fi +    if [ "$DESKTOP_MODIFIED" = false ]; then +        log.info "未找到需要修改的 .desktop 文件" +    fi - # 复制修改后的文件结构到打包目录并重新打包 modified deb(供本地测试/安装使用) - MODIFIED_DEB_PATH="$CRAFT_DIR/modified_${ORIG_PKGNAME:-package}.deb" - log.info "重新打包修改后的 DEB: $MODIFIED_DEB_PATH" - mkdir -p "$MODIFIED_DEB_DIR/data" - cp -r "$EXTRACT_DIR"/* "$MODIFIED_DEB_DIR/" 2>/dev/null || true +    # 复制修改后的文件结构到打包目录并重新打包 modified deb(供本地测试/安装使用) +    MODIFIED_DEB_PATH="$CRAFT_DIR/modified_${ORIG_PKGNAME:-package}.deb" +    log.info "重新打包修改后的 DEB: $MODIFIED_DEB_PATH" +    mkdir -p "$MODIFIED_DEB_DIR/data" +    cp -r "$EXTRACT_DIR"/* "$MODIFIED_DEB_DIR/" 2>/dev/null || true - (cd "$MODIFIED_DEB_DIR" && fakeroot dpkg-deb --build -Z none . "$MODIFIED_DEB_PATH") || { - log.error "错误:重新打包 DEB 失败" - exit 1 - } +    (cd "$MODIFIED_DEB_DIR" && fakeroot dpkg-deb --build -Z none . "$MODIFIED_DEB_PATH") || { +        log.error "错误:重新打包 DEB 失败" +        exit 1 +    } - if [ ! -f "$MODIFIED_DEB_PATH" ]; then - log.error "错误:重新打包后的 DEB 未生成: $MODIFIED_DEB_PATH" - exit 1 - fi - log.info "修改后的 DEB 包已生成: $MODIFIED_DEB_PATH" +    if [ ! -f "$MODIFIED_DEB_PATH" ]; then +        log.error "错误:重新打包后的 DEB 未生成: $MODIFIED_DEB_PATH" +        exit 1 +    fi +    log.info "修改后的 DEB 包已生成: $MODIFIED_DEB_PATH" - # 可选:在融合环境中实际安装修改后的包(默认使用 ssaudit 命令) - if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg ssaudit "$MODIFIED_DEB_PATH" --native --no-create-desktop-entry ; then - log.error "错误:修改后的 DEB 包安装失败(ssaudit)" - exit 1 - fi - log.info "修改后的 DEB 包安装完成(ssaudit)" +    # 可选:在融合环境中实际安装修改后的包(默认使用 ssaudit 命令) +    if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg ssaudit "$MODIFIED_DEB_PATH" --native --no-create-desktop-entry ; then +        log.error "错误:修改后的 DEB 包安装失败(ssaudit)" +        exit 1 +    fi +    log.info "修改后的 DEB 包安装完成(ssaudit)" fi - # 清理 apt 缓存 - sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss clean || true - sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/apt/lists || true - sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/aptss/lists || true - sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/cache/apt/* || true +    # 清理 apt 缓存 +    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss clean || true +    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/apt/lists || true +    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/aptss/lists || true +    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/cache/apt/* || true # 5. 创建新的 APM 包结构 log.info "创建新的APM包结构..." @@ -605,15 +606,15 @@ mkdir -p "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME"/{entries,files} 2>/dev/null | log.info "创建 info 文件(包含原始输入的基础环境)..." : > "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info" 2>/dev/null || true for BASENAME in "${BASENAMES_ORIG[@]}"; do - echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info" - log.info " 写入: $BASENAME" +    echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info" +    log.info "  写入: $BASENAME" done log.info "创建 info_debug 文件(包含所有递归依赖的基础环境)..." : > "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_debug" 2>/dev/null || true for BASENAME in "${BASENAMES[@]}"; do - echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_debug" - log.info " 写入: $BASENAME" +    echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_debug" +    log.info "  写入: $BASENAME" done # 创建 postrm 脚本 @@ -622,15 +623,15 @@ cat > "$PKG_BUILD_DIR/DEBIAN/postrm" << 'EOF' PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE" if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then - echo "清理卸载残留" - rm -rf "/var/lib/apm/$PACKAGE_NAME" - for username in $(ls /home); do - if [ -d "/home/$username/.apm/$PACKAGE_NAME" ]; then - rm -fr "/home/$username/.apm/$PACKAGE_NAME" - fi - done +    echo "清理卸载残留" +    rm -rf "/var/lib/apm/$PACKAGE_NAME" +    for username in $(ls /home); do +        if [ -d "/home/$username/.apm/$PACKAGE_NAME" ]; then +            rm -fr "/home/$username/.apm/$PACKAGE_NAME" +        fi +    done else - echo "非卸载,跳过清理" +    echo "非卸载,跳过清理" fi EOF @@ -641,20 +642,20 @@ log.info "复制文件到新的APM包..." # 如果是手动模式且没有DEB文件,进行交互式文件选择 if [ "$MANUAL_MODE" = true ] && [ -z "$DEB_PATH" ]; then - interactive_copy_entries +    interactive_copy_entries fi # 复制 /usr/share 内容到 entries if [ -d "$CRAFT_DIR/extract/usr/share" ]; then - log.info "复制 /usr/share 内容..." - mkdir -p "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries" - cp -r "$CRAFT_DIR/extract/usr/share/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true +    log.info "复制 /usr/share 内容..." +    mkdir -p "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries" +    cp -r "$CRAFT_DIR/extract/usr/share/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true fi # 复制 /opt/apps//entries(如果存在) if [ -n "$ORIG_PKGNAME" ] && [ -d "$CRAFT_DIR/extract/opt/apps/$ORIG_PKGNAME/entries" ]; then - log.info "复制 /opt/apps/$ORIG_PKGNAME/entries 内容..." - cp -r "$CRAFT_DIR/extract/opt/apps/$ORIG_PKGNAME/entries/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true +    log.info "复制 /opt/apps/$ORIG_PKGNAME/entries 内容..." +    cp -r "$CRAFT_DIR/extract/opt/apps/$ORIG_PKGNAME/entries/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true fi # 复制融合环境(core, work)到新的包内 files(以便运行时使用) @@ -671,12 +672,12 @@ cleanup_mount # 8. 计算目录大小函数 calculate_directory_size() { - local dir="$1" - if [ -d "$dir" ]; then - du -sk "$dir" | cut -f1 - else - echo "0" - fi +    local dir="$1" +    if [ -d "$dir" ]; then +        du -sk "$dir" | cut -f1 +    else +        echo "0" +    fi } # 构建依赖字符串 - 包含所有用户原始输入的 base(用于 control) @@ -684,10 +685,10 @@ DEPENDS_STR=$(IFS=,; echo "${BASENAMES_ORIG[*]}") # 若打包前没有 NEW_PKGNAME/NEW_VERSION,交互询问(一般出现在手动无DEB场景) if [ -z "$NEW_PKGNAME" ]; then - read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME +    read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME fi if [ -z "$NEW_VERSION" ] || [[ "$NEW_VERSION" == "-apm" ]]; then - read -r -p "请输入要创建的版本 (Version): " NEW_VERSION +    read -r -p "请输入要创建的版本 (Version): " NEW_VERSION fi # 创建 control 文件 @@ -699,16 +700,16 @@ Maintainer: APM Converter Depends: $DEPENDS_STR Installed-Size: $(calculate_directory_size "$PKG_BUILD_DIR") Description: APM converted package from ${ORIG_PKGNAME:-original} - This package was automatically converted from the original deb package. - Based on: ${BASENAMES_ORIG[*]} +  This package was automatically converted from the original deb package. +  Based on: ${BASENAMES_ORIG[*]} EOF # 9. 打包并生成输出文件名 OUTPUT_DEB="${NEW_PKGNAME}_${NEW_VERSION}_${ORIG_ARCH}.deb" log.info "开始使用 fakeroot 打包: $OUTPUT_DEB" fakeroot dpkg-deb -Z xz --build "$PKG_BUILD_DIR" "$OUTPUT_DEB" || { - log.error "错误:打包 APM 包失败" - exit 1 +    log.error "错误:打包 APM 包失败" +    exit 1 } log.info "转换完成!" @@ -722,4 +723,4 @@ log.info "基础环境(递归展开): ${BASENAMES[*]}" log.info "注意:桌面文件如存在已被修改,添加了 apm run 前缀和 X-APM-APPID" # 退出(trap 会触发 cleanup) -exit 0 +exit 0 \ No newline at end of file From 9b1e435f4f2170ec7657789d7d9a0dbf3b8ee727 Mon Sep 17 00:00:00 2001 From: shenmo Date: Tue, 9 Dec 2025 09:10:29 +0000 Subject: [PATCH 04/15] Revert "update src/usr/bin/amber-pm-convert." This reverts commit 61e747ba088d398c4e6401110803146e203f81aa. --- src/usr/bin/amber-pm-convert | 967 +++++++++++++++++------------------ 1 file changed, 483 insertions(+), 484 deletions(-) diff --git a/src/usr/bin/amber-pm-convert b/src/usr/bin/amber-pm-convert index 6f7424f..0bed887 100755 --- a/src/usr/bin/amber-pm-convert +++ b/src/usr/bin/amber-pm-convert @@ -1,41 +1,41 @@ #!/bin/bash # APM软件包转换器 - 将DEB包转换为APM格式 -log.warn()  { echo -e "[\e[33mWARN\e[0m]:  \e[1m$*\e[0m"; } +log.warn() { echo -e "[\e[33mWARN\e[0m]: \e[1m$*\e[0m"; } log.error() { echo -e "[\e[31mERROR\e[0m]: \e[1m$*\e[0m"; } -log.info()  { echo -e "[\e[96mINFO\e[0m]:  \e[1m$*\e[0m"; } +log.info() { echo -e "[\e[96mINFO\e[0m]: \e[1m$*\e[0m"; } log.debug() { echo -e "[\e[32mDEBUG\e[0m]: \e[1m$*\e[0m"; } SCRIPT_NAME=$(basename "$0") if ! command -v dpkg > /dev/null ; then -    log.error "若想使用APM软件包转换器,您需先安装dpkg" -    exit 1 + log.error "若想使用APM软件包转换器,您需先安装dpkg" + exit 1 fi # 显示用法信息 usage() { -    echo "用法: $SCRIPT_NAME [--manual] --base [--base ...] " -    echo "       或者在手动模式下不传入 DEB 文件: $SCRIPT_NAME --manual --base [--base ...]" -    echo "" -    echo "参数说明:" -    echo "  --manual     启用手动模式:融合挂载后打开交互 shell,退出 shell 后脚本继续" -    echo "  --basename   必填参数(非手动模式下),指定基础环境名称,可多次使用" -    echo "  deb文件路径  要转换的DEB文件路径(非手动且非空模式下必填)" -    echo "  --pkgname    可选参数,指定新包的包名(默认使用原DEB包名)" -    echo "  --version    可选参数,指定新包的版本号(默认在原版本后追加'-apm')" -    echo "" -    echo "示例:" -    echo "  $SCRIPT_NAME --base amber-pm-trixie /path/to/package.deb" -    echo "  $SCRIPT_NAME --manual --base amber-pm-trixie   # 只融合挂载并进入手动 shell" -    echo "  $SCRIPT_NAME --manual --base amber-pm-trixie --pkgname newpkg --version 1.2.3 /path/to/package.deb" -    echo "" -    echo "说明: 最下层的base在最后面,从上到下写base" + echo "用法: $SCRIPT_NAME [--manual] --base [--base ...] " + echo " 或者在手动模式下不传入 DEB 文件: $SCRIPT_NAME --manual --base [--base ...]" + echo "" + echo "参数说明:" + echo " --manual 启用手动模式:融合挂载后打开交互 shell,退出 shell 后脚本继续" + echo " --basename 必填参数(非手动模式下),指定基础环境名称,可多次使用" + echo " deb文件路径 要转换的DEB文件路径(非手动且非空模式下必填)" + echo " --pkgname 可选参数,指定新包的包名(默认使用原DEB包名)" + echo " --version 可选参数,指定新包的版本号(默认在原版本后追加'-apm')" + echo "" + echo "示例:" + echo " $SCRIPT_NAME --base amber-pm-trixie /path/to/package.deb" + echo " $SCRIPT_NAME --manual --base amber-pm-trixie # 只融合挂载并进入手动 shell" + echo " $SCRIPT_NAME --manual --base amber-pm-trixie --pkgname newpkg --version 1.2.3 /path/to/package.deb" + echo "" + echo "说明: 最下层的base在最后面,从上到下写base" } # 解析参数 -BASENAMES=()        # 存放实际用于构建 overlay 的 base(可能会被递归添加) -BASENAMES_ORIG=()   # 存放用户原始输入的 base 列表(用于 control 中 Depends 等) +BASENAMES=() # 存放实际用于构建 overlay 的 base(可能会被递归添加) +BASENAMES_ORIG=() # 存放用户原始输入的 base 列表(用于 control 中 Depends 等) DEB_PATH="" PKGNAME="" VERSION="" @@ -43,81 +43,81 @@ MANUAL_MODE=false # 简单参数解析(顺序敏感) while [ $# -gt 0 ]; do -    case "$1" in -        --base) -            if [ -z "$2" ]; then -                log.error "--base 后需要跟名称" -                usage -                exit 1 -            fi -            BASENAMES+=("$2") -            BASENAMES_ORIG+=("$2") -            shift 2 -            ;; -        --pkgname) -            PKGNAME="$2" -            shift 2 -            ;; -        --version) -            VERSION="$2" -            shift 2 -            ;; -        --manual) -            MANUAL_MODE=true -            shift -            ;; -        -*) -            log.error "未知选项: $1" -            usage -            exit 1 -            ;; -        *) -            # 非选项,视为 DEB 路径(只接受第一个非选项作为 DEB) -            if [ -z "$DEB_PATH" ]; then -                DEB_PATH="$1" -                shift -            else -                log.error "未知参数或多余的参数: $1" -                usage -                exit 1 -            fi -            ;; -    esac + case "$1" in + --base) + if [ -z "$2" ]; then + log.error "--base 后需要跟名称" + usage + exit 1 + fi + BASENAMES+=("$2") + BASENAMES_ORIG+=("$2") + shift 2 + ;; + --pkgname) + PKGNAME="$2" + shift 2 + ;; + --version) + VERSION="$2" + shift 2 + ;; + --manual) + MANUAL_MODE=true + shift + ;; + -*) + log.error "未知选项: $1" + usage + exit 1 + ;; + *) + # 非选项,视为 DEB 路径(只接受第一个非选项作为 DEB) + if [ -z "$DEB_PATH" ]; then + DEB_PATH="$1" + shift + else + log.error "未知参数或多余的参数: $1" + usage + exit 1 + fi + ;; + esac done # 基本参数验证: # 如果不是手动模式,则至少需要一个 --base 和一个 deb 文件 if [ "$MANUAL_MODE" = false ]; then -    if [ ${#BASENAMES[@]} -eq 0 ] || [ -z "$DEB_PATH" ]; then -        log.error "错误:非手动模式下至少需要一个 --base 参数 且 必须提供 DEB 文件路径" -        usage -        exit 1 -    fi + if [ ${#BASENAMES[@]} -eq 0 ] || [ -z "$DEB_PATH" ]; then + log.error "错误:非手动模式下至少需要一个 --base 参数 且 必须提供 DEB 文件路径" + usage + exit 1 + fi else -    # 手动模式下允许没有 DEB_FILE,但仍然要有至少一个 base -    if [ ${#BASENAMES[@]} -eq 0 ]; then -        log.error "错误:手动模式下仍需提供至少一个 --base 参数" -        usage -        exit 1 -    fi + # 手动模式下允许没有 DEB_FILE,但仍然要有至少一个 base + if [ ${#BASENAMES[@]} -eq 0 ]; then + log.error "错误:手动模式下仍需提供至少一个 --base 参数" + usage + exit 1 + fi fi # 如果传入了 DEB_PATH,检查文件是否存在 if [ -n "$DEB_PATH" ] && [ ! -f "$DEB_PATH" ]; then -    log.error "错误:DEB文件不存在: $DEB_PATH" -    exit 1 + log.error "错误:DEB文件不存在: $DEB_PATH" + exit 1 fi log.info "开始转换(手动模式: $MANUAL_MODE)" log.info "基础环境数量: ${#BASENAMES_ORIG[@]}" for i in "${!BASENAMES_ORIG[@]}"; do -    log.info "  原始基础环境 $((i+1)): ${BASENAMES_ORIG[$i]}" + log.info " 原始基础环境 $((i+1)): ${BASENAMES_ORIG[$i]}" done if [ -n "$DEB_PATH" ]; then -    log.info "目标 DEB: $DEB_PATH" + log.info "目标 DEB: $DEB_PATH" else -    log.info "未提供 DEB 文件,处于纯手动模式(手动修改/安装/打包)" + log.info "未提供 DEB 文件,处于纯手动模式(手动修改/安装/打包)" fi # 1. 创建临时工作目录 @@ -128,20 +128,20 @@ export CRAFT_DIR # 检查是否已挂载,避免重复挂载 cleanup_mount() { -    if mountpoint -q "$CRAFT_DIR/mergedir"; then -        log.info "解除挂载: $CRAFT_DIR/mergedir" -        sudo umount "$CRAFT_DIR/mergedir" || true -    fi + if mountpoint -q "$CRAFT_DIR/mergedir"; then + log.info "解除挂载: $CRAFT_DIR/mergedir" + sudo umount "$CRAFT_DIR/mergedir" || true + fi } # 清理函数 cleanup() { -    log.info "开始清理..." -    cleanup_mount -    if [ -d "$CRAFT_DIR" ]; then -        log.info "删除临时目录: $CRAFT_DIR" -        sudo rm -rf "$CRAFT_DIR" -    fi + log.info "开始清理..." + cleanup_mount + if [ -d "$CRAFT_DIR" ]; then + log.info "删除临时目录: $CRAFT_DIR" + sudo rm -rf "$CRAFT_DIR" + fi } # 设置退出时清理 @@ -149,52 +149,52 @@ trap cleanup EXIT # 递归获取info文件中的依赖 (会把新依赖追加到 BASENAMES 数组中) get_recursive_basenames() { -    local basename="$1" -    # 注意:根据之前脚本结构,info 存放在 /var/lib/apm/apm/files/ace-env/var/lib/apm//info -    local base_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/$basename" -    local info_file="$base_dir/info" + local basename="$1" + # 注意:根据之前脚本结构,info 存放在 /var/lib/apm/apm/files/ace-env/var/lib/apm//info + local base_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/$basename" + local info_file="$base_dir/info" -    if [ -f "$info_file" ]; then -        log.info "读取info文件: $info_file" -        while IFS= read -r base; do -            [[ -z "$base" ]] && continue -            # 如果依赖的 base 没有被记录过,则递归添加 -            local found=false -            for existing in "${BASENAMES[@]}"; do -                if [ "$existing" = "$base" ]; then -                    found=true -                    break -                fi -            done -            if [ "$found" = false ]; then -                BASENAMES+=("$base") -                get_recursive_basenames "$base" -            fi -        done < "$info_file" -    else -        log.info "未找到info文件,跳过: $info_file" -    fi + if [ -f "$info_file" ]; then + log.info "读取info文件: $info_file" + while IFS= read -r base; do + [[ -z "$base" ]] && continue + # 如果依赖的 base 没有被记录过,则递归添加 + local found=false + for existing in "${BASENAMES[@]}"; do + if [ "$existing" = "$base" ]; then + found=true + break + fi + done + if [ "$found" = false ]; then + BASENAMES+=("$base") + get_recursive_basenames "$base" + fi + done < "$info_file" + else + log.info "未找到info文件,跳过: $info_file" + fi } # 递归获取所有基础环境(从用户输入的 base 开始) for BASE in "${BASENAMES[@]}"; do -    get_recursive_basenames "$BASE" + get_recursive_basenames "$BASE" done # 如果用户传了 DEB,则读取原包信息(否则跳过) if [ -n "$DEB_PATH" ]; then -    log.info "检查原DEB包信息..." -    ORIG_PKGNAME=$(dpkg -f "$DEB_PATH" Package 2>/dev/null || echo "") -    ORIG_VERSION=$(dpkg -f "$DEB_PATH" Version 2>/dev/null || echo "") -    ORIG_ARCH=$(dpkg -f "$DEB_PATH" Architecture 2>/dev/null || echo "") + log.info "检查原DEB包信息..." + ORIG_PKGNAME=$(dpkg -f "$DEB_PATH" Package 2>/dev/null || echo "") + ORIG_VERSION=$(dpkg -f "$DEB_PATH" Version 2>/dev/null || echo "") + ORIG_ARCH=$(dpkg -f "$DEB_PATH" Architecture 2>/dev/null || echo "") -    log.info "原包名: ${ORIG_PKGNAME:-未知}" -    log.info "原版本: ${ORIG_VERSION:-未知}" -    log.info "原架构: ${ORIG_ARCH:-unknown}" + log.info "原包名: ${ORIG_PKGNAME:-未知}" + log.info "原版本: ${ORIG_VERSION:-未知}" + log.info "原架构: ${ORIG_ARCH:-unknown}" else -    ORIG_PKGNAME="" -    ORIG_VERSION="" -    ORIG_ARCH="$(dpkg --print-architecture 2>/dev/null || echo "unknown")" + ORIG_PKGNAME="" + ORIG_VERSION="" + ORIG_ARCH="$(dpkg --print-architecture 2>/dev/null || echo "unknown")" fi # 设置新包名和版本(若手动模式且未指定,则稍后询问) @@ -210,21 +210,21 @@ log.info "构建 overlay lowerdir 路径..." LOWERDIRS=() for BASENAME in "${BASENAMES[@]}"; do -    ACE_ENV_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/ace-env" -    CORE_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/core" + ACE_ENV_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/ace-env" + CORE_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/core" -    if [ -d "$ACE_ENV_PATH" ]; then -        log.info "使用 ace-env 路径: $ACE_ENV_PATH" -        LOWERDIRS+=("$ACE_ENV_PATH") -    elif [ -d "$CORE_PATH" ]; then -        log.info "使用 core 路径: $CORE_PATH" -        LOWERDIRS+=("$CORE_PATH") -    else -        log.error "错误:基础环境路径不存在: $BASENAME" -        log.error "  检查的路径: $ACE_ENV_PATH" -        log.error "  检查的路径: $CORE_PATH" -        exit 1 -    fi + if [ -d "$ACE_ENV_PATH" ]; then + log.info "使用 ace-env 路径: $ACE_ENV_PATH" + LOWERDIRS+=("$ACE_ENV_PATH") + elif [ -d "$CORE_PATH" ]; then + log.info "使用 core 路径: $CORE_PATH" + LOWERDIRS+=("$CORE_PATH") + else + log.error "错误:基础环境路径不存在: $BASENAME" + log.error " 检查的路径: $ACE_ENV_PATH" + log.error " 检查的路径: $CORE_PATH" + exit 1 + fi done # 将 lowerdirs 数组用冒号连接 @@ -234,12 +234,12 @@ log.debug "最终 lowerdir: $LOWERDIR" # 3. 进行融合挂载 log.info "正在进行融合挂载..." sudo mount -t overlay overlay \ -    -o "lowerdir=$LOWERDIR,upperdir=$CRAFT_DIR/core/,workdir=$CRAFT_DIR/work/" \ -    "$CRAFT_DIR/mergedir" + -o "lowerdir=$LOWERDIR,upperdir=$CRAFT_DIR/core/,workdir=$CRAFT_DIR/work/" \ + "$CRAFT_DIR/mergedir" if ! mountpoint -q "$CRAFT_DIR/mergedir"; then -    log.error "错误:融合挂载失败" -    exit 1 + log.error "错误:融合挂载失败" + exit 1 fi log.info "挂载完成: $CRAFT_DIR/mergedir" @@ -250,351 +250,350 @@ log.debug "已导出 chrootEnvPath=$chrootEnvPath" # 如果在手动模式下,立即打开交互 shell 并在退出后继续脚本 if [ "$MANUAL_MODE" = true ]; then -    log.info "进入手动模式:将在融合挂载环境中打开交互 shell(使用 ace-run-pkg)。" -    log.info "在 shell 中,您可以手动修改、测试安装或进行其他操作。退出 shell 后脚本将继续。" -    # 启动交互 shell,保留环境变量(使用 sudo -E) -    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || { -        log.warn "ace-run-pkg shell 退出或出现错误,继续脚本..." -    } -    log.info "用户已退出手动 shell,脚本将继续。" -    # 如果没有 DEB,询问是否要进行后续打包(允许返回 shell) -    if [ -z "$DEB_PATH" ]; then -        while true; do -            echo "" -            read -r -p "未提供 DEB 文件。是否现在进行新 APM 包的自动打包? (y = 打包, r = 返回 shell, n = 跳过打包) [y/r/n]: " yn -            case "$yn" in -                y|Y) -                    # 如果缺少包名或版本,交互询问 -                    if [ -z "$NEW_PKGNAME" ]; then -                        read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME -                    fi -                    if [ -z "$NEW_VERSION" ] || [[ "$NEW_VERSION" == "-apm" ]]; then -                        read -r -p "请输入要创建的版本 (Version): " NEW_VERSION -                    fi -                    break -                    ;; -                r|R) -                    log.info "返回交互 shell(使用 ace-run-pkg)。退出 shell 后再次询问。" -                    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || true -                    ;; -                n|N) -                    log.info "跳过自动打包。脚本结束。" -                    exit 0 -                    ;; -                *) -                    echo "请输入 y, r, 或 n。" -                    ;; -            esac -        done -    fi + log.info "进入手动模式:将在融合挂载环境中打开交互 shell(使用 ace-run-pkg)。" + log.info "在 shell 中,您可以手动修改、测试安装或进行其他操作。退出 shell 后脚本将继续。" + # 启动交互 shell,保留环境变量(使用 sudo -E) + sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || { + log.warn "ace-run-pkg shell 退出或出现错误,继续脚本..." + } + log.info "用户已退出手动 shell,脚本将继续。" + # 如果没有 DEB,询问是否要进行后续打包(允许返回 shell) + if [ -z "$DEB_PATH" ]; then + while true; do + echo "" + read -r -p "未提供 DEB 文件。是否现在进行新 APM 包的自动打包? (y = 打包, r = 返回 shell, n = 跳过打包) [y/r/n]: " yn + case "$yn" in + y|Y) + # 如果缺少包名或版本,交互询问 + if [ -z "$NEW_PKGNAME" ]; then + read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME + fi + if [ -z "$NEW_VERSION" ] || [[ "$NEW_VERSION" == "-apm" ]]; then + read -r -p "请输入要创建的版本 (Version): " NEW_VERSION + fi + break + ;; + r|R) + log.info "返回交互 shell(使用 ace-run-pkg)。退出 shell 后再次询问。" + sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || true + ;; + n|N) + log.info "跳过自动打包。脚本结束。" + exit 0 + ;; + *) + echo "请输入 y, r, 或 n。" + ;; + esac + done + fi fi # 到这里:非手动模式或手动模式退出后继续(如果是非手动并且有 DEB,继续原本流程) # 函数:查找并处理符号链接,返回实际文件路径 resolve_symlink() { -    local file="$1" -    local target_dir="$2" -     -    if [ -L "$file" ]; then -        # 获取符号链接目标 -        local target=$(readlink "$file") -         -        # 如果目标是绝对路径,则在目标目录中查找 -        if [[ "$target" == /* ]]; then -            local resolved_path="$target_dir${target}" -            if [ -f "$resolved_path" ]; then -                echo "$resolved_path" -                return 0 -            fi -        else -            # 相对路径,在符号链接所在目录解析 -            local link_dir=$(dirname "$file") -            local resolved_path="$link_dir/$target" -            if [ -f "$resolved_path" ]; then -                echo "$resolved_path" -                return 0 -            fi -        fi -    fi -     -    # 如果不是符号链接或解析失败,返回原文件 -    echo "$file" + local file="$1" + local target_dir="$2" + + if [ -L "$file" ]; then + # 获取符号链接目标 + local target=$(readlink "$file") + + # 如果目标是绝对路径,则在目标目录中查找 + if [[ "$target" == /* ]]; then + local resolved_path="$target_dir${target}" + if [ -f "$resolved_path" ]; then + echo "$resolved_path" + return 0 + fi + else + # 相对路径,在符号链接所在目录解析 + local link_dir=$(dirname "$file") + local resolved_path="$link_dir/$target" + if [ -f "$resolved_path" ]; then + echo "$resolved_path" + return 0 + fi + fi + fi + + # 如果不是符号链接或解析失败,返回原文件 + echo "$file" } # 函数:交互式选择文件复制到entries目录(用于手动模式无DEB情况) interactive_copy_entries() { -    local core_dir="$CRAFT_DIR/core" -    local entries_dir="$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries" -     -    log.info "开始交互式选择文件复制到 entries 目录..." -    mkdir -p "$entries_dir/applications" "$entries_dir/icons" -     -    # 查找桌面文件 -    local desktop_files=() -    while IFS= read -r -d '' file; do -        [[ -f "$file" ]] && desktop_files+=("$file") -    done < <(find "$core_dir/usr/share" -name "*.desktop" -print0 2>/dev/null || true) -     -    # 查找图标文件 -    local icon_files=() -    while IFS= read -r -d '' file; do -        [[ -f "$file" ]] && icon_files+=("$file") -    done < <(find "$core_dir/usr/share" \( -name "*.png" -o -name "*.svg" -o -name "*.xpm" \) -print0 2>/dev/null || true) -     -    # 处理桌面文件 -    if [ ${#desktop_files[@]} -gt 0 ]; then -        log.info "找到 ${#desktop_files[@]} 个桌面文件:" -        for i in "${!desktop_files[@]}"; do -            local file="${desktop_files[$i]}" -            local relative_path="${file#$core_dir}" # 获取相对于 core_dir 的路径 -            echo "  $((i+1)). $relative_path" # 打印相对路径 -             -            # 检查是否是符号链接 -            if [ -L "$file" ]; then -                local target=$(readlink "$file") -                echo "      → 符号链接指向: $target" -                # 解析符号链接获取实际文件 -                local resolved_file=$(resolve_symlink "$file" "$core_dir") -                if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then -                    local resolved_relative_path="${resolved_file#$core_dir}" -                    echo "      → 解析为: $resolved_relative_path" -                    desktop_files[$i]="$resolved_file" -                fi -            fi -        done -         -        echo "" -        read -r -p "请选择要复制的桌面文件编号(多个用逗号分隔,all=全部,none=跳过): " desktop_choice -         -        if [[ "$desktop_choice" =~ ^[Aa][Ll][Ll]$ ]]; then -            # 复制所有桌面文件到 entries/applications -            for file in "${desktop_files[@]}"; do -                local filename=$(basename "$file") -                local dest_path="$entries_dir/applications/$filename" -                cp -v "$file" "$dest_path" -                 -                # 处理桌面文件内容 -                process_desktop_file "$dest_path" "$NEW_PKGNAME" -            done -        elif [[ ! "$desktop_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$desktop_choice" ]; then -            # 处理选择的文件 -            IFS=',' read -ra choices <<< "$desktop_choice" -            for choice in "${choices[@]}"; do -                choice=$(echo "$choice" | tr -d ' ') -                if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#desktop_files[@]} ]; then -                    local idx=$((choice-1)) -                    local file="${desktop_files[$idx]}" -                    local filename=$(basename "$file") -                    local dest_path="$entries_dir/applications/$filename" -                    cp -v "$file" "$dest_path" -                     -                    # 处理桌面文件内容 -                    process_desktop_file "$dest_path" "$NEW_PKGNAME" -                else -                    log.warn "无效的选择: $choice" -                fi -            done -        else -            log.info "跳过桌面文件复制" -        fi -    else -        log.info "未找到桌面文件" -    fi -     -    # 处理图标文件 -    if [ ${#icon_files[@]} -gt 0 ]; then -        log.info "找到 ${#icon_files[@]} 个图标文件:" -        for i in "${!icon_files[@]}"; do -            local file="${icon_files[$i]}" -            local relative_path="${file#$core_dir}"  # <-- 修改:获取相对于 core_dir 的路径 -            echo "  $((i+1)). $relative_path"          # <-- 修改:打印相对路径 -             -            # 检查是否是符号链接 -            if [ -L "$file" ]; then -                local target=$(readlink "$file") -                echo "      → 符号链接指向: $target" -                # 解析符号链接获取实际文件 -                local resolved_file=$(resolve_symlink "$file" "$core_dir") -                if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then -                    local resolved_relative_path="${resolved_file#$core_dir}" # <-- 修改:计算解析后的相对路径 -                    echo "      → 解析为: $resolved_relative_path"              # <-- 修改:打印解析后的相对路径 -                    icon_files[$i]="$resolved_file" -                fi -            fi -        done -         -        echo "" -        read -r -p "请选择要复制的图标文件编号(多个用逗号分隔,all=全部,none=跳过): " icon_choice -         -        if [[ "$icon_choice" =~ ^[Aa][Ll][Ll]$ ]]; then -            # 复制所有图标文件到 entries/icons -            for file in "${icon_files[@]}"; do -                local filename=$(basename "$file") -                local dest_path="$entries_dir/icons/$filename" -                cp -v "$file" "$dest_path" -            done -        elif [[ ! "$icon_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$icon_choice" ]; then -            # 处理选择的文件 -            IFS=',' read -ra choices <<< "$icon_choice" -            for choice in "${choices[@]}"; do -                choice=$(echo "$choice" | tr -d ' ') -                if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#icon_files[@]} ]; then -                    local idx=$((choice-1)) -                    local file="${icon_files[$idx]}" -                    local filename=$(basename "$file") -                    local dest_path="$entries_dir/icons/$filename" -                    cp -v "$file" "$dest_path" -                else -                    log.warn "无效的选择: $choice" -                fi -            done -        else -            log.info "跳过图标文件复制" -        fi -    else -        log.info "未找到图标文件" -    fi + local core_dir="$CRAFT_DIR/core" + local entries_dir="$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries" + + log.info "开始交互式选择文件复制到 entries 目录..." + mkdir -p "$entries_dir/applications" "$entries_dir/icons" + + # 查找桌面文件 + local desktop_files=() + while IFS= read -r -d '' file; do + [[ -f "$file" ]] && desktop_files+=("$file") + done < <(find "$core_dir/usr/share" -name "*.desktop" -print0 2>/dev/null || true) + + # 查找图标文件 + local icon_files=() + while IFS= read -r -d '' file; do + [[ -f "$file" ]] && icon_files+=("$file") + done < <(find "$core_dir/usr/share" \( -name "*.png" -o -name "*.svg" -o -name "*.xpm" \) -print0 2>/dev/null || true) + + # 处理桌面文件 + if [ ${#desktop_files[@]} -gt 0 ]; then + log.info "找到 ${#desktop_files[@]} 个桌面文件:" + for i in "${!desktop_files[@]}"; do + local file="${desktop_files[$i]}" + local filename=$(basename "$file") + echo " $((i+1)). $filename" + + # 检查是否是符号链接 + if [ -L "$file" ]; then + local target=$(readlink "$file") + echo " → 符号链接指向: $target" + # 解析符号链接获取实际文件 + local resolved_file=$(resolve_symlink "$file" "$core_dir") + if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then + echo " → 解析为: $(basename "$resolved_file")" + desktop_files[$i]="$resolved_file" + fi + fi + done + + echo "" + read -r -p "请选择要复制的桌面文件编号(多个用逗号分隔,all=全部,none=跳过): " desktop_choice + + if [[ "$desktop_choice" =~ ^[Aa][Ll][Ll]$ ]]; then + # 复制所有桌面文件到 entries/applications + for file in "${desktop_files[@]}"; do + local filename=$(basename "$file") + local dest_path="$entries_dir/applications/$filename" + cp -v "$file" "$dest_path" + + # 处理桌面文件内容 + process_desktop_file "$dest_path" "$NEW_PKGNAME" + done + elif [[ ! "$desktop_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$desktop_choice" ]; then + # 处理选择的文件 + IFS=',' read -ra choices <<< "$desktop_choice" + for choice in "${choices[@]}"; do + choice=$(echo "$choice" | tr -d ' ') + if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#desktop_files[@]} ]; then + local idx=$((choice-1)) + local file="${desktop_files[$idx]}" + local filename=$(basename "$file") + local dest_path="$entries_dir/applications/$filename" + cp -v "$file" "$dest_path" + + # 处理桌面文件内容 + process_desktop_file "$dest_path" "$NEW_PKGNAME" + else + log.warn "无效的选择: $choice" + fi + done + else + log.info "跳过桌面文件复制" + fi + else + log.info "未找到桌面文件" + fi + + # 处理图标文件 + if [ ${#icon_files[@]} -gt 0 ]; then + log.info "找到 ${#icon_files[@]} 个图标文件:" + for i in "${!icon_files[@]}"; do + local file="${icon_files[$i]}" + local filename=$(basename "$file") + echo " $((i+1)). $filename" + + # 检查是否是符号链接 + if [ -L "$file" ]; then + local target=$(readlink "$file") + echo " → 符号链接指向: $target" + # 解析符号链接获取实际文件 + local resolved_file=$(resolve_symlink "$file" "$core_dir") + if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then + echo " → 解析为: $(basename "$resolved_file")" + icon_files[$i]="$resolved_file" + fi + fi + done + + echo "" + read -r -p "请选择要复制的图标文件编号(多个用逗号分隔,all=全部,none=跳过): " icon_choice + + if [[ "$icon_choice" =~ ^[Aa][Ll][Ll]$ ]]; then + # 复制所有图标文件到 entries/icons + for file in "${icon_files[@]}"; do + local filename=$(basename "$file") + local dest_path="$entries_dir/icons/$filename" + cp -v "$file" "$dest_path" + done + elif [[ ! "$icon_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$icon_choice" ]; then + # 处理选择的文件 + IFS=',' read -ra choices <<< "$icon_choice" + for choice in "${choices[@]}"; do + choice=$(echo "$choice" | tr -d ' ') + if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#icon_files[@]} ]; then + local idx=$((choice-1)) + local file="${icon_files[$idx]}" + local filename=$(basename "$file") + local dest_path="$entries_dir/icons/$filename" + cp -v "$file" "$dest_path" + else + log.warn "无效的选择: $choice" + fi + done + else + log.info "跳过图标文件复制" + fi + else + log.info "未找到图标文件" + fi } +# 函数:处理桌面文件内容 # 函数:处理桌面文件内容(安全版本,避免重复处理) process_desktop_file() { -    local desktop_file="$1" -    local pkgname="$2" -    # 新增:精确路径检查 -    local apps_path1="/usr/share/applications" -    local apps_path2="/opt/apps/${ORIG_PKGNAME}/entries/applications" -    local apps_path3="/usr/local/share/applications" -     -    if [[ ! "$desktop_file" =~ ^.*${apps_path1}/.*\.desktop$ ]] &&  -       [[ ! "$desktop_file" =~ ^.*${apps_path2}/.*\.desktop$ ]] && -       [[ ! "$desktop_file" =~ ^.*${apps_path3}/.*\.desktop$ ]]; then -        log.debug "跳过非应用程序 desktop 文件: $desktop_file" -        return 0 -    fi -     -    log.info "处理桌面文件: $desktop_file" -     -    # 检查文件是否已经处理过(避免重复添加 apm run) -    if grep -q "^Exec=apm run $pkgname " "$desktop_file"; then -        log.info "桌面文件已经处理过,跳过: $desktop_file" -        return 0 -    fi -     -    # 检查是否有其他包的 apm run 前缀(清理旧的) -    if grep -q "^Exec=apm run [^ ]* " "$desktop_file"; then -        log.info "发现旧的 apm run 前缀,清理后重新添加" -        # 移除所有 apm run 前缀 -        sed -i "s|^Exec=apm run [^ ]* ||" "$desktop_file" -    fi -     -    # 尝试用 busybox dos2unix(若不存在则跳过转换) -    if command -v busybox >/dev/null 2>&1; then -        busybox dos2unix "$desktop_file" 2>/dev/null || true -    else -        dos2unix "$desktop_file" 2>/dev/null || true -    fi -     -    # 处理 Exec 行:在原有命令前追加 apm run $pkgname -    if grep -q '^Exec=' "$desktop_file"; then -        sed -i "s|^Exec=\(.*\)$|Exec=apm run $pkgname \1|" "$desktop_file" -    fi -     -    # 删除 TryExec 行 -    if grep -q '^TryExec=' "$desktop_file"; then -        sed -i '/^TryExec=/d' "$desktop_file" -        log.info "已删除 TryExec 行" -    fi -     -    # 处理 Icon 路径(若以 / 开头) -    if grep -q '^Icon=/' "$desktop_file"; then -        sed -i "s|^Icon=/|Icon=/var/lib/apm/apm/files/ace-env/var/lib/apm/$pkgname/files/core/|" "$desktop_file" -    fi -     -    # 添加 X-APM-APPID(如果不存在) -    if ! grep -q "X-APM-APPID" "$desktop_file"; then -        echo "" >> "$desktop_file" -        echo "X-APM-APPID=$pkgname" >> "$desktop_file" -    fi -     -    # 检查修改结果并打印调试 -    if grep -q "apm run $pkgname" "$desktop_file"; then -        log.info "桌面文件修改成功: $desktop_file" -    else -        log.warn "桌面文件可能未正确修改: $desktop_file" -    fi + local desktop_file="$1" + local pkgname="$2" + # 新增:精确路径检查 + local apps_path1="/usr/share/applications" + local apps_path2="/opt/apps/${ORIG_PKGNAME}/entries/applications" + local apps_path3="/usr/local/share/applications" + + if [[ ! "$desktop_file" =~ ^.*${apps_path1}/.*\.desktop$ ]] && + [[ ! "$desktop_file" =~ ^.*${apps_path2}/.*\.desktop$ ]] && + [[ ! "$desktop_file" =~ ^.*${apps_path3}/.*\.desktop$ ]]; then + log.debug "跳过非应用程序 desktop 文件: $desktop_file" + return 0 + fi + + log.info "处理桌面文件: $desktop_file" + + # 检查文件是否已经处理过(避免重复添加 apm run) + if grep -q "^Exec=apm run $pkgname " "$desktop_file"; then + log.info "桌面文件已经处理过,跳过: $desktop_file" + return 0 + fi + + # 检查是否有其他包的 apm run 前缀(清理旧的) + if grep -q "^Exec=apm run [^ ]* " "$desktop_file"; then + log.info "发现旧的 apm run 前缀,清理后重新添加" + # 移除所有 apm run 前缀 + sed -i "s|^Exec=apm run [^ ]* ||" "$desktop_file" + fi + + # 尝试用 busybox dos2unix(若不存在则跳过转换) + if command -v busybox >/dev/null 2>&1; then + busybox dos2unix "$desktop_file" 2>/dev/null || true + else + dos2unix "$desktop_file" 2>/dev/null || true + fi + + # 处理 Exec 行:在原有命令前追加 apm run $pkgname + if grep -q '^Exec=' "$desktop_file"; then + sed -i "s|^Exec=\(.*\)$|Exec=apm run $pkgname \1|" "$desktop_file" + fi + + # 删除 TryExec 行 + if grep -q '^TryExec=' "$desktop_file"; then + sed -i '/^TryExec=/d' "$desktop_file" + log.info "已删除 TryExec 行" + fi + + # 处理 Icon 路径(若以 / 开头) + if grep -q '^Icon=/' "$desktop_file"; then + sed -i "s|^Icon=/|Icon=/var/lib/apm/apm/files/ace-env/var/lib/apm/$pkgname/files/core/|" "$desktop_file" + fi + + # 添加 X-APM-APPID(如果不存在) + if ! grep -q "X-APM-APPID" "$desktop_file"; then + echo "" >> "$desktop_file" + echo "X-APM-APPID=$pkgname" >> "$desktop_file" + fi + + # 检查修改结果并打印调试 + if grep -q "apm run $pkgname" "$desktop_file"; then + log.info "桌面文件修改成功: $desktop_file" + else + log.warn "桌面文件可能未正确修改: $desktop_file" + fi } # 4. 如果有 DEB 文件,进行自动化的检查、解包与修改 if [ -n "$DEB_PATH" ]; then -    # 在融合环境中更新包列表并做 dry-run 检查(如果 ace-run-pkg aptss 可用) -    log.info "在融合环境中测试安装 DEB 包(dry-run)..." -    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss update || log.warn "aptss update 返回非零状态,继续但请注意" -    if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss install "$DEB_PATH" --dry-run ; then -        log.error "错误:安装前检查失败,DEB包可能无法在基础环境中安装" -        log.error "请检查依赖关系或基础环境是否兼容" -        exit 1 -    fi -    log.info "安装前检查通过,准备进行提取与修改..." -    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg mkdir -p /var/cache/apt/archives/partial + # 在融合环境中更新包列表并做 dry-run 检查(如果 ace-run-pkg aptss 可用) + log.info "在融合环境中测试安装 DEB 包(dry-run)..." + sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss update || log.warn "aptss update 返回非零状态,继续但请注意" + if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss install "$DEB_PATH" --dry-run ; then + log.error "错误:安装前检查失败,DEB包可能无法在基础环境中安装" + log.error "请检查依赖关系或基础环境是否兼容" + exit 1 + fi + log.info "安装前检查通过,准备进行提取与修改..." + sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg mkdir -p /var/cache/apt/archives/partial -    # 提取 DEB 包内容并准备修改 -    log.info "提取并修改原DEB包..." -    EXTRACT_DIR="$CRAFT_DIR/extract" -    MODIFIED_DEB_DIR="$CRAFT_DIR/modified_deb" -    mkdir -p "$EXTRACT_DIR" -    mkdir -p "$MODIFIED_DEB_DIR/DEBIAN" + # 提取 DEB 包内容并准备修改 + log.info "提取并修改原DEB包..." + EXTRACT_DIR="$CRAFT_DIR/extract" + MODIFIED_DEB_DIR="$CRAFT_DIR/modified_deb" + mkdir -p "$EXTRACT_DIR" + mkdir -p "$MODIFIED_DEB_DIR/DEBIAN" -    dpkg -x "$DEB_PATH" "$EXTRACT_DIR" -    dpkg -e "$DEB_PATH" "$MODIFIED_DEB_DIR/DEBIAN" + dpkg -x "$DEB_PATH" "$EXTRACT_DIR" + dpkg -e "$DEB_PATH" "$MODIFIED_DEB_DIR/DEBIAN" -    # 处理 .desktop 文件 -    DESKTOP_MODIFIED=false -    while IFS= read -r desktop_file; do -        [ -z "$desktop_file" ] && continue -        process_desktop_file "$desktop_file" "${NEW_PKGNAME:-$ORIG_PKGNAME}" -        DESKTOP_MODIFIED=true -    done < <(find "$EXTRACT_DIR" -name "*.desktop" -print) + # 处理 .desktop 文件 + DESKTOP_MODIFIED=false + while IFS= read -r desktop_file; do + [ -z "$desktop_file" ] && continue + process_desktop_file "$desktop_file" "${NEW_PKGNAME:-$ORIG_PKGNAME}" + DESKTOP_MODIFIED=true + done < <(find "$EXTRACT_DIR" -name "*.desktop" -print) -    if [ "$DESKTOP_MODIFIED" = false ]; then -        log.info "未找到需要修改的 .desktop 文件" -    fi + if [ "$DESKTOP_MODIFIED" = false ]; then + log.info "未找到需要修改的 .desktop 文件" + fi -    # 复制修改后的文件结构到打包目录并重新打包 modified deb(供本地测试/安装使用) -    MODIFIED_DEB_PATH="$CRAFT_DIR/modified_${ORIG_PKGNAME:-package}.deb" -    log.info "重新打包修改后的 DEB: $MODIFIED_DEB_PATH" -    mkdir -p "$MODIFIED_DEB_DIR/data" -    cp -r "$EXTRACT_DIR"/* "$MODIFIED_DEB_DIR/" 2>/dev/null || true + # 复制修改后的文件结构到打包目录并重新打包 modified deb(供本地测试/安装使用) + MODIFIED_DEB_PATH="$CRAFT_DIR/modified_${ORIG_PKGNAME:-package}.deb" + log.info "重新打包修改后的 DEB: $MODIFIED_DEB_PATH" + mkdir -p "$MODIFIED_DEB_DIR/data" + cp -r "$EXTRACT_DIR"/* "$MODIFIED_DEB_DIR/" 2>/dev/null || true -    (cd "$MODIFIED_DEB_DIR" && fakeroot dpkg-deb --build -Z none . "$MODIFIED_DEB_PATH") || { -        log.error "错误:重新打包 DEB 失败" -        exit 1 -    } + (cd "$MODIFIED_DEB_DIR" && fakeroot dpkg-deb --build -Z none . "$MODIFIED_DEB_PATH") || { + log.error "错误:重新打包 DEB 失败" + exit 1 + } -    if [ ! -f "$MODIFIED_DEB_PATH" ]; then -        log.error "错误:重新打包后的 DEB 未生成: $MODIFIED_DEB_PATH" -        exit 1 -    fi -    log.info "修改后的 DEB 包已生成: $MODIFIED_DEB_PATH" + if [ ! -f "$MODIFIED_DEB_PATH" ]; then + log.error "错误:重新打包后的 DEB 未生成: $MODIFIED_DEB_PATH" + exit 1 + fi + log.info "修改后的 DEB 包已生成: $MODIFIED_DEB_PATH" -    # 可选:在融合环境中实际安装修改后的包(默认使用 ssaudit 命令) -    if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg ssaudit "$MODIFIED_DEB_PATH" --native --no-create-desktop-entry ; then -        log.error "错误:修改后的 DEB 包安装失败(ssaudit)" -        exit 1 -    fi -    log.info "修改后的 DEB 包安装完成(ssaudit)" + # 可选:在融合环境中实际安装修改后的包(默认使用 ssaudit 命令) + if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg ssaudit "$MODIFIED_DEB_PATH" --native --no-create-desktop-entry ; then + log.error "错误:修改后的 DEB 包安装失败(ssaudit)" + exit 1 + fi + log.info "修改后的 DEB 包安装完成(ssaudit)" fi -    # 清理 apt 缓存 -    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss clean || true -    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/apt/lists || true -    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/aptss/lists || true -    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/cache/apt/* || true + # 清理 apt 缓存 + sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss clean || true + sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/apt/lists || true + sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/aptss/lists || true + sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/cache/apt/* || true # 5. 创建新的 APM 包结构 log.info "创建新的APM包结构..." @@ -606,15 +605,15 @@ mkdir -p "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME"/{entries,files} 2>/dev/null | log.info "创建 info 文件(包含原始输入的基础环境)..." : > "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info" 2>/dev/null || true for BASENAME in "${BASENAMES_ORIG[@]}"; do -    echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info" -    log.info "  写入: $BASENAME" + echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info" + log.info " 写入: $BASENAME" done log.info "创建 info_debug 文件(包含所有递归依赖的基础环境)..." : > "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_debug" 2>/dev/null || true for BASENAME in "${BASENAMES[@]}"; do -    echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_debug" -    log.info "  写入: $BASENAME" + echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_debug" + log.info " 写入: $BASENAME" done # 创建 postrm 脚本 @@ -623,15 +622,15 @@ cat > "$PKG_BUILD_DIR/DEBIAN/postrm" << 'EOF' PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE" if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then -    echo "清理卸载残留" -    rm -rf "/var/lib/apm/$PACKAGE_NAME" -    for username in $(ls /home); do -        if [ -d "/home/$username/.apm/$PACKAGE_NAME" ]; then -            rm -fr "/home/$username/.apm/$PACKAGE_NAME" -        fi -    done + echo "清理卸载残留" + rm -rf "/var/lib/apm/$PACKAGE_NAME" + for username in $(ls /home); do + if [ -d "/home/$username/.apm/$PACKAGE_NAME" ]; then + rm -fr "/home/$username/.apm/$PACKAGE_NAME" + fi + done else -    echo "非卸载,跳过清理" + echo "非卸载,跳过清理" fi EOF @@ -642,20 +641,20 @@ log.info "复制文件到新的APM包..." # 如果是手动模式且没有DEB文件,进行交互式文件选择 if [ "$MANUAL_MODE" = true ] && [ -z "$DEB_PATH" ]; then -    interactive_copy_entries + interactive_copy_entries fi # 复制 /usr/share 内容到 entries if [ -d "$CRAFT_DIR/extract/usr/share" ]; then -    log.info "复制 /usr/share 内容..." -    mkdir -p "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries" -    cp -r "$CRAFT_DIR/extract/usr/share/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true + log.info "复制 /usr/share 内容..." + mkdir -p "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries" + cp -r "$CRAFT_DIR/extract/usr/share/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true fi # 复制 /opt/apps//entries(如果存在) if [ -n "$ORIG_PKGNAME" ] && [ -d "$CRAFT_DIR/extract/opt/apps/$ORIG_PKGNAME/entries" ]; then -    log.info "复制 /opt/apps/$ORIG_PKGNAME/entries 内容..." -    cp -r "$CRAFT_DIR/extract/opt/apps/$ORIG_PKGNAME/entries/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true + log.info "复制 /opt/apps/$ORIG_PKGNAME/entries 内容..." + cp -r "$CRAFT_DIR/extract/opt/apps/$ORIG_PKGNAME/entries/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true fi # 复制融合环境(core, work)到新的包内 files(以便运行时使用) @@ -672,12 +671,12 @@ cleanup_mount # 8. 计算目录大小函数 calculate_directory_size() { -    local dir="$1" -    if [ -d "$dir" ]; then -        du -sk "$dir" | cut -f1 -    else -        echo "0" -    fi + local dir="$1" + if [ -d "$dir" ]; then + du -sk "$dir" | cut -f1 + else + echo "0" + fi } # 构建依赖字符串 - 包含所有用户原始输入的 base(用于 control) @@ -685,10 +684,10 @@ DEPENDS_STR=$(IFS=,; echo "${BASENAMES_ORIG[*]}") # 若打包前没有 NEW_PKGNAME/NEW_VERSION,交互询问(一般出现在手动无DEB场景) if [ -z "$NEW_PKGNAME" ]; then -    read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME + read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME fi if [ -z "$NEW_VERSION" ] || [[ "$NEW_VERSION" == "-apm" ]]; then -    read -r -p "请输入要创建的版本 (Version): " NEW_VERSION + read -r -p "请输入要创建的版本 (Version): " NEW_VERSION fi # 创建 control 文件 @@ -700,16 +699,16 @@ Maintainer: APM Converter Depends: $DEPENDS_STR Installed-Size: $(calculate_directory_size "$PKG_BUILD_DIR") Description: APM converted package from ${ORIG_PKGNAME:-original} -  This package was automatically converted from the original deb package. -  Based on: ${BASENAMES_ORIG[*]} + This package was automatically converted from the original deb package. + Based on: ${BASENAMES_ORIG[*]} EOF # 9. 打包并生成输出文件名 OUTPUT_DEB="${NEW_PKGNAME}_${NEW_VERSION}_${ORIG_ARCH}.deb" log.info "开始使用 fakeroot 打包: $OUTPUT_DEB" fakeroot dpkg-deb -Z xz --build "$PKG_BUILD_DIR" "$OUTPUT_DEB" || { -    log.error "错误:打包 APM 包失败" -    exit 1 + log.error "错误:打包 APM 包失败" + exit 1 } log.info "转换完成!" @@ -723,4 +722,4 @@ log.info "基础环境(递归展开): ${BASENAMES[*]}" log.info "注意:桌面文件如存在已被修改,添加了 apm run 前缀和 X-APM-APPID" # 退出(trap 会触发 cleanup) -exit 0 \ No newline at end of file +exit 0 From 6abdb10a7c9ceebf958f3f80242a1c0e61dd7c0e Mon Sep 17 00:00:00 2001 From: shenmo Date: Tue, 9 Dec 2025 09:16:14 +0000 Subject: [PATCH 05/15] update src/usr/bin/amber-pm-convert. Signed-off-by: shenmo --- src/usr/bin/amber-pm-convert | 89 ++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 18 deletions(-) diff --git a/src/usr/bin/amber-pm-convert b/src/usr/bin/amber-pm-convert index 0bed887..c6c86b2 100755 --- a/src/usr/bin/amber-pm-convert +++ b/src/usr/bin/amber-pm-convert @@ -322,6 +322,7 @@ resolve_symlink() { echo "$file" } +# 函数:交互式选择文件复制到entries目录(用于手动模式无DEB情况) # 函数:交互式选择文件复制到entries目录(用于手动模式无DEB情况) interactive_copy_entries() { local core_dir="$CRAFT_DIR/core" @@ -330,13 +331,13 @@ interactive_copy_entries() { log.info "开始交互式选择文件复制到 entries 目录..." mkdir -p "$entries_dir/applications" "$entries_dir/icons" - # 查找桌面文件 + # 查找桌面文件(保留完整路径) local desktop_files=() while IFS= read -r -d '' file; do [[ -f "$file" ]] && desktop_files+=("$file") done < <(find "$core_dir/usr/share" -name "*.desktop" -print0 2>/dev/null || true) - # 查找图标文件 + # 查找图标文件(保留完整路径) local icon_files=() while IFS= read -r -d '' file; do [[ -f "$file" ]] && icon_files+=("$file") @@ -347,8 +348,9 @@ interactive_copy_entries() { log.info "找到 ${#desktop_files[@]} 个桌面文件:" for i in "${!desktop_files[@]}"; do local file="${desktop_files[$i]}" - local filename=$(basename "$file") - echo " $((i+1)). $filename" + # 显示完整路径(相对于 core_dir) + local relative_path="${file#$core_dir}" + echo " $((i+1)). $relative_path" # 检查是否是符号链接 if [ -L "$file" ]; then @@ -357,7 +359,8 @@ interactive_copy_entries() { # 解析符号链接获取实际文件 local resolved_file=$(resolve_symlink "$file" "$core_dir") if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then - echo " → 解析为: $(basename "$resolved_file")" + local resolved_relative="${resolved_file#$core_dir}" + echo " → 解析为: $resolved_relative" desktop_files[$i]="$resolved_file" fi fi @@ -367,10 +370,22 @@ interactive_copy_entries() { read -r -p "请选择要复制的桌面文件编号(多个用逗号分隔,all=全部,none=跳过): " desktop_choice if [[ "$desktop_choice" =~ ^[Aa][Ll][Ll]$ ]]; then - # 复制所有桌面文件到 entries/applications + # 复制所有桌面文件到 entries/applications,但保持目录结构 for file in "${desktop_files[@]}"; do - local filename=$(basename "$file") - local dest_path="$entries_dir/applications/$filename" + local relative_path="${file#$core_dir}" + local dest_filename=$(basename "$file") + + # 如果文件在 applications 目录下,直接复制到 entries/applications + if [[ "$relative_path" == /usr/share/applications/* ]]; then + local dest_path="$entries_dir/applications/$dest_filename" + else + # 其他位置的桌面文件,保持相对路径结构 + local path_dir=$(dirname "$relative_path") + local dest_dir="$entries_dir/applications$path_dir" + mkdir -p "$dest_dir" + local dest_path="$dest_dir/$dest_filename" + fi + cp -v "$file" "$dest_path" # 处理桌面文件内容 @@ -384,8 +399,19 @@ interactive_copy_entries() { if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#desktop_files[@]} ]; then local idx=$((choice-1)) local file="${desktop_files[$idx]}" - local filename=$(basename "$file") - local dest_path="$entries_dir/applications/$filename" + local relative_path="${file#$core_dir}" + local dest_filename=$(basename "$file") + + # 根据路径决定目标位置 + if [[ "$relative_path" == /usr/share/applications/* ]]; then + local dest_path="$entries_dir/applications/$dest_filename" + else + local path_dir=$(dirname "$relative_path") + local dest_dir="$entries_dir/applications$path_dir" + mkdir -p "$dest_dir" + local dest_path="$dest_dir/$dest_filename" + fi + cp -v "$file" "$dest_path" # 处理桌面文件内容 @@ -406,8 +432,8 @@ interactive_copy_entries() { log.info "找到 ${#icon_files[@]} 个图标文件:" for i in "${!icon_files[@]}"; do local file="${icon_files[$i]}" - local filename=$(basename "$file") - echo " $((i+1)). $filename" + local relative_path="${file#$core_dir}" + echo " $((i+1)). $relative_path" # 检查是否是符号链接 if [ -L "$file" ]; then @@ -416,7 +442,8 @@ interactive_copy_entries() { # 解析符号链接获取实际文件 local resolved_file=$(resolve_symlink "$file" "$core_dir") if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then - echo " → 解析为: $(basename "$resolved_file")" + local resolved_relative="${resolved_file#$core_dir}" + echo " → 解析为: $resolved_relative" icon_files[$i]="$resolved_file" fi fi @@ -426,10 +453,23 @@ interactive_copy_entries() { read -r -p "请选择要复制的图标文件编号(多个用逗号分隔,all=全部,none=跳过): " icon_choice if [[ "$icon_choice" =~ ^[Aa][Ll][Ll]$ ]]; then - # 复制所有图标文件到 entries/icons + # 复制所有图标文件到 entries/icons,保持目录结构 for file in "${icon_files[@]}"; do - local filename=$(basename "$file") - local dest_path="$entries_dir/icons/$filename" + local relative_path="${file#$core_dir}" + local dest_filename=$(basename "$file") + + # 如果文件在 icons 主题目录下,直接复制到 entries/icons + if [[ "$relative_path" == /usr/share/icons/* ]] || + [[ "$relative_path" == /usr/share/pixmaps/* ]]; then + local dest_path="$entries_dir/icons/$dest_filename" + else + # 其他位置的图标文件,保持相对路径结构 + local path_dir=$(dirname "$relative_path") + local dest_dir="$entries_dir/icons$path_dir" + mkdir -p "$dest_dir" + local dest_path="$dest_dir/$dest_filename" + fi + cp -v "$file" "$dest_path" done elif [[ ! "$icon_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$icon_choice" ]; then @@ -440,8 +480,20 @@ interactive_copy_entries() { if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#icon_files[@]} ]; then local idx=$((choice-1)) local file="${icon_files[$idx]}" - local filename=$(basename "$file") - local dest_path="$entries_dir/icons/$filename" + local relative_path="${file#$core_dir}" + local dest_filename=$(basename "$file") + + # 根据路径决定目标位置 + if [[ "$relative_path" == /usr/share/icons/* ]] || + [[ "$relative_path" == /usr/share/pixmaps/* ]]; then + local dest_path="$entries_dir/icons/$dest_filename" + else + local path_dir=$(dirname "$relative_path") + local dest_dir="$entries_dir/icons$path_dir" + mkdir -p "$dest_dir" + local dest_path="$dest_dir/$dest_filename" + fi + cp -v "$file" "$dest_path" else log.warn "无效的选择: $choice" @@ -456,6 +508,7 @@ interactive_copy_entries() { } + # 函数:处理桌面文件内容 # 函数:处理桌面文件内容(安全版本,避免重复处理) process_desktop_file() { From e373ae7bdeb47fa91a79a897ab0d7a8c708820a6 Mon Sep 17 00:00:00 2001 From: shenmo Date: Thu, 11 Dec 2025 10:12:04 +0800 Subject: [PATCH 06/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E5=9C=A8btrfs?= =?UTF-8?q?=E4=B8=8Aconvert=E6=97=B6=E6=97=A0=E6=B3=95=E6=8C=82=E8=BD=BD?= =?UTF-8?q?=E5=A4=9A=E5=B1=82layer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/usr/bin/amber-pm-convert | 2 +- src/usr/bin/amber-pm-dstore-patch | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/usr/bin/amber-pm-convert b/src/usr/bin/amber-pm-convert index c6c86b2..7835da5 100755 --- a/src/usr/bin/amber-pm-convert +++ b/src/usr/bin/amber-pm-convert @@ -233,7 +233,7 @@ log.debug "最终 lowerdir: $LOWERDIR" # 3. 进行融合挂载 log.info "正在进行融合挂载..." -sudo mount -t overlay overlay \ +sudo fuse-overlayfs \ -o "lowerdir=$LOWERDIR,upperdir=$CRAFT_DIR/core/,workdir=$CRAFT_DIR/work/" \ "$CRAFT_DIR/mergedir" diff --git a/src/usr/bin/amber-pm-dstore-patch b/src/usr/bin/amber-pm-dstore-patch index d21e51d..cc6b77f 100755 --- a/src/usr/bin/amber-pm-dstore-patch +++ b/src/usr/bin/amber-pm-dstore-patch @@ -98,7 +98,7 @@ function exec_link_clean(){ find /usr/share/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/help -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/locale -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & - find /usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH`/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & + find /usr/lib/$(gcc -dumpmachine)/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/lib/mozilla/plugins -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/polkit-1/actions -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/fonts -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & From 3b25a62a54edf885a54a606ebe7a2bfa4d7438fb Mon Sep 17 00:00:00 2001 From: shenmo Date: Thu, 18 Dec 2025 15:21:52 +0800 Subject: [PATCH 07/15] =?UTF-8?q?=E6=94=AF=E6=8C=81info=5Fenv=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/usr/bin/apm | 162 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 108 insertions(+), 54 deletions(-) diff --git a/src/usr/bin/apm b/src/usr/bin/apm index 50dc37a..355b412 100755 --- a/src/usr/bin/apm +++ b/src/usr/bin/apm @@ -50,32 +50,36 @@ Commands: EOF } - apm_exec(){ - # 递归读取info文件并构建lowerdir + # =============================== + # 基础变量 + # =============================== local lowerdirs=() - local current_dir="${PATH_PREFIX}/var/lib/apm/${coredir}" # 当前目录开始 + local env_layers=() + local current_dir="${PATH_PREFIX}/var/lib/apm/${coredir}" local next_info_file="" - - # 使用统一的 ace-run 脚本 - APM_RUN_EXEC=/var/lib/apm/apm/files/ace-run - - while : ; do - # 构建info文件的路径 - next_info_file="${current_dir}/info" - # 检查info文件是否存在 - if [[ ! -f "$next_info_file" ]]; then - break - fi - - # 读取info文件的每一行并构建lowerdir - while IFS= read -r basedir; do - [[ -z "$basedir" ]] && continue # 跳过空行 + local APM_RUN_EXEC=/var/lib/apm/apm/files/ace-run + + # =============================== + # 递归读取 info / info_env + # =============================== + while : ; do + next_info_file="${current_dir}/info" + + # 记录 info_env(底层优先) + if [[ -f "${current_dir}/info_env" ]]; then + env_layers+=("${current_dir}/info_env") + fi + + # 没有 info 就停止 + [[ ! -f "$next_info_file" ]] && break + + # 读取依赖层 + while IFS= read -r basedir; do + [[ -z "$basedir" ]] && continue - # 检查ace-env目录是否存在 if [[ -d "${PATH_PREFIX}/var/lib/apm/${basedir}/files/ace-env" ]]; then lowerdirs+=("${PATH_PREFIX}/var/lib/apm/${basedir}/files/ace-env") - # 如果ace-env不存在,检查core目录 elif [[ -d "${PATH_PREFIX}/var/lib/apm/${basedir}/files/core" ]]; then lowerdirs+=("${PATH_PREFIX}/var/lib/apm/${basedir}/files/core") else @@ -83,61 +87,111 @@ apm_exec(){ fi done < "$next_info_file" - # 尝试获取下一个依赖信息的路径 - local next_basedir=$(tail -n 1 "$next_info_file") - if [[ -z "$next_basedir" || ! -d "${PATH_PREFIX}/var/lib/apm/${next_basedir}" ]]; then - break - fi - # 更新当前目录,递归处理下一个依赖 + # 递归到下一个 + local next_basedir + next_basedir="$(tail -n 1 "$next_info_file")" + [[ -z "$next_basedir" || ! -d "${PATH_PREFIX}/var/lib/apm/${next_basedir}" ]] && break current_dir="${PATH_PREFIX}/var/lib/apm/${next_basedir}" done - - # 添加info_layer_override功能 + + # =============================== + # info_layer_override(最高优先级) + # =============================== local override_file="${PATH_PREFIX}/var/lib/apm/${coredir}/info_layer_override" if [[ -f "$override_file" ]]; then - log.debug "Found info_layer_override file: $override_file" + log.debug "Found info_layer_override: $override_file" + local override_dirs=() - - # 读取override文件并构建override目录数组 + local override_envs=() + while IFS= read -r basedir; do [[ -z "$basedir" ]] && continue - - # 检查override目录是否存在 - if [[ -d "${PATH_PREFIX}/var/lib/apm/${basedir}/files/ace-env" ]]; then - override_dirs+=("${PATH_PREFIX}/var/lib/apm/${basedir}/files/ace-env") - elif [[ -d "${PATH_PREFIX}/var/lib/apm/${basedir}/files/core" ]]; then - override_dirs+=("${PATH_PREFIX}/var/lib/apm/${basedir}/files/core") + local base="${PATH_PREFIX}/var/lib/apm/${basedir}" + + if [[ -d "${base}/files/ace-env" ]]; then + override_dirs+=("${base}/files/ace-env") + elif [[ -d "${base}/files/core" ]]; then + override_dirs+=("${base}/files/core") else - log.warn "Neither ace-env nor core directory found for override base: $basedir" + log.warn "Override layer not found: $basedir" + fi + + if [[ -f "${base}/info_env" ]]; then + override_envs+=("${base}/info_env") fi done < "$override_file" - - # 将override目录插入到现有lowerdirs数组的最前面(最左侧/最顶层) + + # override 层放最前(最高) if [[ ${#override_dirs[@]} -gt 0 ]]; then - log.debug "Adding override directories to the top layer" lowerdirs=("${override_dirs[@]}" "${lowerdirs[@]}") fi + + # override env 最后应用(最高) + if [[ ${#override_envs[@]} -gt 0 ]]; then + env_layers+=("${override_envs[@]}") + fi fi - - # 检查是否找到了有效的lowerdir + + # =============================== + # 检查 lowerdir + # =============================== if [[ ${#lowerdirs[@]} -eq 0 ]]; then log.error "No valid lower directories found for package: $coredir" return 1 fi - - # 将lowerdirs数组用冒号连接起来 - local lowerdir=$(IFS=:; echo "${lowerdirs[*]}") - # 创建挂载点目录 + + local lowerdir + lowerdir=$(IFS=:; echo "${lowerdirs[*]}") + mkdir -p "/tmp/apm/${coredir}" - - # 使用fuse-overlayfs挂载 - log.debug "Mounting with lowerdir: $lowerdir" - fuse-overlayfs -o lowerdir="$lowerdir",upperdir="${PATH_PREFIX}/var/lib/apm/${coredir}/files/core/",workdir="${PATH_PREFIX}/var/lib/apm/${coredir}/files/work/" "/tmp/apm/${coredir}" - - # 执行命令 + + # =============================== + # 应用 info_env(从下到上) + # =============================== + for env_file in "${env_layers[@]}"; do + log.debug "Applying env: $env_file" + + while IFS= read -r line || [[ -n "$line" ]]; do + [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue + + if [[ "$line" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then + local key="${line%%=*}" + local val="${line#*=}" + + # 去首尾空白 + val="${val#"${val%%[![:space:]]*}"}" + val="${val%"${val##*[![:space:]]}"}" + + # 去外层引号 + if [[ "$val" =~ ^\".*\"$ || "$val" =~ ^\'.*\'$ ]]; then + val="${val:1:-1}" + fi + + export "$key=$val" + else + log.warn "Invalid env line ignored: $line" + fi + done < "$env_file" + done + + # =============================== + # 挂载 overlay + # =============================== + log.debug "Mounting overlayfs" + log.debug "lowerdir=$lowerdir" + + fuse-overlayfs \ + -o lowerdir="$lowerdir",upperdir="${PATH_PREFIX}/var/lib/apm/${coredir}/files/core/",workdir="${PATH_PREFIX}/var/lib/apm/${coredir}/files/work/" \ + "/tmp/apm/${coredir}" + + # =============================== + # 执行 + # =============================== chrootEnvPath="/tmp/apm/${coredir}" "${APM_RUN_EXEC}" "$@" - + + # =============================== # 卸载 + # =============================== umount "/tmp/apm/${coredir}" } From 869d11d351ac0df53c9f85a92e3d96195f792030 Mon Sep 17 00:00:00 2001 From: shenmo Date: Thu, 18 Dec 2025 15:22:18 +0800 Subject: [PATCH 08/15] version bump to 1.1.6 --- build.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.config b/build.config index 7a9f3e6..df6d802 100644 --- a/build.config +++ b/build.config @@ -1 +1 @@ -@VERSION@=1.1.5 +@VERSION@=1.1.6 From 705c16937d4ef31fcb5fc4048917f12d02f69081 Mon Sep 17 00:00:00 2001 From: shenmo Date: Thu, 18 Dec 2025 15:27:12 +0800 Subject: [PATCH 09/15] update doc --- Packaging-demo/README.md | 368 +++++++++++++++++++++++++++++---------- 1 file changed, 273 insertions(+), 95 deletions(-) diff --git a/Packaging-demo/README.md b/Packaging-demo/README.md index 6d2fd04..63bd45f 100644 --- a/Packaging-demo/README.md +++ b/Packaging-demo/README.md @@ -1,16 +1,19 @@ + + # APM 软件包打包流程 -本文档为开发者准备,若您只是想从 deb 软件包打包 APM 软件包,您可以通过 `amber-pm-convert`指令进行全自动一键转换 +本文档为开发者准备,若您只是想从 deb 软件包打包 APM 软件包,您可以通过 `amber-pm-convert` 指令进行全自动一键转换。 -通过 `apm search amber-pm- ` 即可搜索到所有可用的 base 列表 +通过 `apm search amber-pm-` 即可搜索到所有可用的 base 列表。 --- ## APM 软件包结构规范 -在阅读前,请确保您对overlayfs有了基本的了解 +在阅读前,请确保您对 OverlayFS 有了基本的了解。 -overlayfs 原理解析:https://www.cnblogs.com/arnoldlu/p/13055501.html +OverlayFS 原理解析: +[https://www.cnblogs.com/arnoldlu/p/13055501.html](https://www.cnblogs.com/arnoldlu/p/13055501.html) --- @@ -18,16 +21,25 @@ overlayfs 原理解析:https://www.cnblogs.com/arnoldlu/p/13055501.html APM 使用 OverlayFS 来管理软件包的文件系统层级,从上到下的层叠顺序为: -1. **Upperdir** - 当前包的可写层 `files/core/` -2. **Info Layer Override** - 覆盖层指定的目录(位于所有依赖层之上) -3. **依赖层** - 从 `info` 文件递归解析出的所有依赖包 -3. **底层** - 最基础的运行时环境 +1. **Upperdir** + 当前包的可写层:`files/core/` -这种层叠结构允许上层文件覆盖下层文件,实现依赖管理和自定义覆盖。 +2. **Info Layer Override** + 由 `info_layer_override` 指定的覆盖层,位于所有依赖层之上 + +3. **依赖层** + 由 `info` 文件递归解析出的所有依赖包 + +4. **底层 Runtime** + 最基础的运行时环境(如 `amber-pm-bookworm`) + +这种层叠结构允许上层文件覆盖下层文件,实现灵活、高效的依赖管理与环境定制。 --- -一个典型的 APM 软件/中层依赖包应当包含以下内容 +## APM 软件包目录结构示例 + +一个典型的 APM 应用或中层依赖包应当包含以下内容: ``` ├── DEBIAN @@ -41,20 +53,23 @@ APM 使用 OverlayFS 来管理软件包的文件系统层级,从上到下的 │ ├── applications │ ├── doc │ ├── glib-2.0 -│ │ └── man -│ ├── files -│ │ ├── core -│ │ └── work + │ └── man + ├── files + │ ├── core + │ └── work ├── info - └── info_layer_override # 可选,用于自定义覆盖层 - + ├── info_layer_override # 可选 + └── info_env # 可选(高级功能) ``` -### DEBIAN 目录 +--- -包含软件包的基本信息和依赖的环境信息 +## DEBIAN 目录说明 + +包含软件包的基本信息和依赖环境声明。 + +### control 文件示例 -**control 文件示例:** ``` Package: eom Version: 1.26.0-2-apm @@ -63,18 +78,34 @@ Maintainer: APM Converter Depends: amber-pm-bookworm Installed-Size: 45228 Description: APM converted package from eom - This package was automatically converted from the original deb package. - Based on: amber-pm-bookworm + This package was automatically converted from the original deb package. + Based on: amber-pm-bookworm ``` -- **Package**: 包名,应当唯一。若使用转换器进行转换,默认和原包名一致 -- **Version**: 版本号。若使用转换器进行转换,默认在原版本号后加 `-apm` -- **Architecture**: 软件包架构,同 dpkg 规范填写 -- **Depends**: 直接依赖的 base 包名 -- **Installed-Size**: 安装后的大小,转换器会自动计算 -- **Description**: 包描述,转换器会自动填写 +字段说明: + +* **Package** + 包名,应当唯一。使用转换器时默认与原 deb 包名一致 + +* **Version** + 软件包版本号,转换器会自动追加 `-apm` + +* **Architecture** + 架构信息,遵循 dpkg 规范 + +* **Depends** + 直接依赖的 base 包名 + +* **Installed-Size** + 安装后大小,转换器自动计算 + +* **Description** + 软件包描述信息 + +--- + +### postinst 文件 -**postinst 文件内容:** ``` #!/bin/bash PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE" @@ -82,121 +113,268 @@ PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE" if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then echo "清理卸载残留" rm -rf "/var/lib/apm/$PACKAGE_NAME" -for username in $(ls /home) - do - echo /home/$username - if [ -d "/home/$username/.apm/$PACKAGE_NAME" ] - then - rm -fr "/home/$username/.apm/$PACKAGE_NAME" + + for username in $(ls /home); do + if [ -d "/home/$username/.apm/$PACKAGE_NAME" ]; then + rm -rf "/home/$username/.apm/$PACKAGE_NAME" fi -done + done else echo "非卸载,跳过清理" fi ``` -若无特殊需求,内容保持一致即可,用于在卸载软件包后清理环境。 +若无特殊需求,保持该内容即可,用于卸载时清理残留环境。 -### /var/lib/apm 目录结构 +--- -包含 APM 软件容器的文件和信息: +## /var/lib/apm 目录结构说明 -- **entries** (可选):包含需要放置到 `/usr/share/` 的文件,如 desktop、icon 等 -- **files** (必须):包含软件包的 upperdir 和 workdir -- **info** (必须):包含直接依赖的 base 信息。若应用使用了多层的依赖,会一层一层寻找 info 信息,直到找到底层依赖。如填写 amber-pm-bookworm-spark-wine10 会自动解析出 amber-pm-bookworm -- **info_layer_override** (可选):用于指定自定义覆盖层的目录 +该目录包含 APM 软件包的运行环境与元数据。 -> 关于 Info: 使用多层的依赖并不是必须的,即使不使用也可以正常打包,但恰当地使用多层依赖可大大降低包体积。 可用的多层依赖见 `apm search amber-pm-[base名称]- ` 。若有必要,可申请新增 base +### 必须目录 +* **files/** -**entries 目录说明:** -- `entries/applications`:存放 `.desktop` 文件 -- `entries/doc`:存放文档 -- `entries/glib-2.0`:存放 GLib 相关文件 -- `entries/man`:存放帮助文档 + * `core/`:upperdir,可写层 + * `work/`:OverlayFS 工作目录 -> **重要提示**:`.desktop` 文件应当添加一行 `X-APM-APPID=包名` 来允许软件管理器管理应用 +* **info** -### info_layer_override 文件 + * 声明直接依赖的 base 包 + * 支持多层递归解析 -`info_layer_override` 是一个可选文件,用于在当前包的依赖层之上插入额外的覆盖层。这个功能在以下场景特别有用: +### 可选目录 / 文件 -1. **自定义库版本**:覆盖依赖包中的特定库文件,如你想要用更新版本的 mesa 覆盖 debian 默认提供的版本作为运行环境 -2. **配置文件自定义**:使用自定义配置覆盖默认配置 -- **语法**:与 `info` 文件一致,每行一个包名 -- **层叠位置**:位于所有依赖层之上、当前包的 upperdir 之下 -- **文件位置**:`${PATH_PREFIX}/var/lib/apm/${coredir}/info_layer_override` +* **entries/** -**示例:** -假设您想用自定义的 `override-layer` 包来覆盖 `base-package` 中的某些文件: + * `applications/`:`.desktop` 文件 + * `doc/`:文档 + * `glib-2.0/`:GLib 相关文件 + * `man/`:手册页 + +> ⚠ `.desktop` 文件中 **必须** 添加: +> +> ``` +> X-APM-APPID=包名 +> ``` +> +> 以允许软件管理器正确识别和管理应用。 + +--- + +## info 文件说明(依赖解析) + +`info` 文件用于声明当前包直接依赖的 base 包,每行一个包名: + +``` +amber-pm-bookworm-spark-wine10 +``` + +APM 会递归解析该 base 的 `info` 文件,直到找到最底层 runtime(如 `amber-pm-bookworm`)。 + +> 使用多层依赖并非强制,但合理拆分 base 能显著减小包体积。 +> 可用的 base 列表可通过: +> +> ``` +> apm search amber-pm- +> ``` +> +> 查看。 + +--- + +## info_layer_override 文件(覆盖层) + +`info_layer_override` 是一个可选文件,用于在**所有依赖层之上**插入额外覆盖层。 + +### 使用场景 + +1. 覆盖依赖中的特定库版本(如 mesa) +2. 覆盖默认配置文件 +3. 提供特殊运行环境 + +### 规则说明 + +* 语法与 `info` 完全一致 +* 每行一个包名 +* 层级位置: + + ``` + upperdir + ↑ + info_layer_override + ↑ + info 递归依赖 + ``` + +### 示例 + +`info`: -`my-package/info` 内容: ``` amber-pm-bookworm ``` -`my-package/info_layer_override` 内容: +`info_layer_override`: + ``` amber-pm-bookworm-mesa ``` -最终的挂载 lowerdir 为:`amber-pm-bookworm-mesa:amber-pm-bookworm` +最终 lowerdir 顺序: -这样,`override-layer` 中的文件会覆盖 `base-package` 中的同名文件(除非当前包的 upperdir 中也有该文件)。 - -## APM upperdir 制作流程 - -以下为手动制作 upperdir 的流程: - -1. **安装依赖**:首先安装 apm 并使用 `sudo apm install` 安装所需的 base - -2. **创建目录结构**: -```bash -mkdir -p core work ace-env +``` +amber-pm-bookworm-mesa:amber-pm-bookworm ``` -3. **挂载 overlay**: -```bash -sudo mount -t overlay overlay \ - -o lowerdir='/var/lib/apm/apm/files/ace-env/var/lib/apm/base包的包名(如amber-pm-trixie)/files/ace-env',upperdir=core/,workdir=work/ ./ace-env +--- + +## info_env(环境变量层 · 高级功能) + +`info_env` 是一个 **可选的高级特性**,用于为 APM 容器运行时提供**分层的环境变量配置能力**。 + +### 功能概述 + +* 为软件包及其依赖提供环境变量 +* 支持 **多层叠加** +* **上层自动覆盖下层** +* 与 OverlayFS 层级顺序完全一致 +* 不执行 shell 代码,仅解析键值对,安全可靠 + +--- + +### info_env 文件位置 + +``` +/var/lib/apm/<包名>/info_env ``` -4. **chroot 安装**:chroot 进入 `./ace-env` 进行安装操作,可以使用 `apt install` 或其他方式 +--- -5. **卸载并打包**:完成后解除挂载 `./ace-env` +### info_env 应用顺序(重要) -您将得到: -- **core**:保存新增文件 -- **work**:保存变更信息 +环境变量的加载顺序为: -将这两个目录权限设置为 755 后放入对应的目录进行 apm 打包。 +1. 底层 runtime 的 `info_env` +2. 中间依赖包的 `info_env` +3. 当前包的 `info_env` +4. `info_layer_override` 中包的 `info_env`(最高优先级) + +**后加载的变量会覆盖之前的同名变量。** + +--- + +### info_env 文件格式 + +每行一条环境变量定义: + +``` +KEY=VALUE +``` + +示例: + +``` +QT_QPA_PLATFORM=dxcb;xcb +LANG=zh_CN.UTF-8 +XMODIFIERS="@im=fcitx" +PATH="/custom/bin:$PATH" +``` + +#### 规则说明 + +* 支持分号 `;` +* 支持带引号的值 +* 支持引用已有环境变量(如 `$PATH`) +* 支持注释行(`#`) +* 不允许执行任何 shell 语句 + +❌ 以下内容将被忽略: + +``` +export A=1 +rm -rf / +$(whoami) +``` + +--- + +### 使用场景示例 + +* 指定 Qt / GTK 平台插件 +* 设置输入法变量 +* 调整运行时 PATH / LD_LIBRARY_PATH +* 为特定应用注入兼容性环境变量 + +--- + +## APM upperdir 制作流程(手动) + +1. 安装 APM 并安装所需 base: + + ```bash + sudo apm install amber-pm-xxx + ``` + +2. 创建目录结构: + + ```bash + mkdir -p core work ace-env + ``` + +3. 挂载 OverlayFS: + + ```bash + sudo mount -t overlay overlay \ + -o lowerdir='/var/lib/apm/apm/files/ace-env/var/lib/apm/amber-pm-xxx/files/ace-env',upperdir=core/,workdir=work/ \ + ./ace-env + ``` + +4. chroot 进入 `ace-env` 进行安装 + +5. 卸载并打包 + +--- ## APM 软件包测试 -您可以测试刚刚打包的软件: - ```bash -fuse-overlayfs -o lowerdir='/var/lib/apm/apm/files/ace-env/var/lib/apm/base包的包名(如amber-pm-trixie)/files/ace-env',upperdir=core/,workdir=work/ ./ace-env +fuse-overlayfs -o lowerdir='...',upperdir=core/,workdir=work/ ./ace-env ``` -即可只读挂载。`apm run 包名` 会自动完成: -- 寻找 `/var/lib/apm/包名/` 是否存在 -- 根据 `info` 文件(和可选的 `info_layer_override`)合成 fuse-overlayfs 参数进行挂载 -- 使用 ACE 工具 chroot 进入并启动应用 +或直接使用: -使用 `./ace-run` 即可进入容器环境,测试您安装的应用。 +```bash +apm run 包名 +``` -## APM 打包 +APM 会自动完成: + +* 解析 `info` / `info_layer_override` +* 应用 `info_env` +* 构建 OverlayFS +* 进入容器并运行应用 + +--- + +## APM 软件包打包 -使用以下命令进行打包: ```bash dpkg-deb --build 软件包目录 输出目录 ``` -## APM 底层 Base Runtime 的构建 +--- -详见 https://gitee.com/amber-ce/amber-pm-common +## APM 底层 Base Runtime 构建 + +详见: +[https://gitee.com/amber-ce/amber-pm-common](https://gitee.com/amber-ce/amber-pm-common) --- -**备注**:APM 打包工具和转换器会为您自动处理大部分复杂操作,手动打包主要用于特殊情况或自定义需求。 \ No newline at end of file +### 备注 + +APM 的打包工具与转换器会自动处理绝大多数复杂操作。 +手动打包与 `info_env` 主要用于 **特殊运行环境、深度定制或调试用途**。 + From 301079a9992492c936629d900c7b204b3e7b73a1 Mon Sep 17 00:00:00 2001 From: shenmo Date: Thu, 18 Dec 2025 15:56:03 +0800 Subject: [PATCH 10/15] =?UTF-8?q?add:=20apm=20=E4=B8=8A=E6=B8=B8=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/etc/apt/sources.list.d/apm.list | 3 +++ src/etc/apt/trusted.gpg.d/apm.gpg | Bin 0 -> 1742 bytes 2 files changed, 3 insertions(+) create mode 100644 src/etc/apt/sources.list.d/apm.list create mode 100644 src/etc/apt/trusted.gpg.d/apm.gpg diff --git a/src/etc/apt/sources.list.d/apm.list b/src/etc/apt/sources.list.d/apm.list new file mode 100644 index 0000000..390f3bc --- /dev/null +++ b/src/etc/apt/sources.list.d/apm.list @@ -0,0 +1,3 @@ +deb [Signed-by=/etc/apt/trusted.gpg.d/gxde.gpg] https://repo.gxde.top/gxde-os/lizhi ./ +# 大学镜像站 +#deb [Signed-by=/etc/apt/trusted.gpg.d/gxde.gpg] https://mirrors.cernet.edu.cn/GXDE/gxde-os/lizhi ./ diff --git a/src/etc/apt/trusted.gpg.d/apm.gpg b/src/etc/apt/trusted.gpg.d/apm.gpg new file mode 100644 index 0000000000000000000000000000000000000000..99dab09d5dd7d9397ae3281866e27fe0ce1fb747 GIT binary patch literal 1742 zcmV;<1~K`W0gVJ+>>Ahs3;@cz9=AmbhK;zT5D_a5HpU1s7p(Q(|GziiVqAhlpQ3D;=eC&Q?V%CKUe6TkAOXA z+T}O0VSFI*)qjpuH6BD?v~#|gGo{89nZ_~vqy5|-l|lSR`z=P)e>BUDJ`2X~Wa=?k zc+x!*VkO_BU(c#IPw0l%)6kCn9rdPO`-dJCU!qJB=1>CGhrMNVzLVVHPDI; zSf)qZ5$x21apS%=%pftG^P_A?6e|-4;%hRLJctL*W z;2yD!dPZ`#25{=q{a8E03LuIpl!kiO?gjRZV=lKq)ojfbQ{;o6=@>S?&`4O%;)nt| z6Vz-r5hXY&Qci?nHH zAUtYmW@TQkH;Z>BTM1S6ByY1>)Ndj#e5FzK3+ncN-W3 ztvPCEZVhKjB3%zH+>9@QHH3{m;diQrI$%dgd{0toa1F)p`Rz3uH$>Wr0a$exdmAjC zzB@uF)x1YekSP!IHlk8$g9lYxLm(x?2_7=PIjUTmX?(&;z;(T_^1|88aaSGbnDF`jS!&__|8=`4S; z1cvO?)?hx5nG0%|eK9DTA6%cNtnpu5>;e0Fknw^itoca)*KEO< zl@d{gnY0t5cgCts)8-_hsVUjOCIgRSgAPgPKDWfy-xEZi8V}6coBY-6(otL$IapKB-8iGVC1b7V(X0)xv?32QKP4qEReQ7Q=*8Z1LDN*CnnVl*0%ESl695Vc z5Dr1pRHB+h4C%ZJ|8U>*Eq7iy-&4M3%FvPYJ_jN%7*eaBJ^>=2|M%HZ?M36=oxg0} z$Qis1Qm|=&TC01XSYQBhuxx?va@K`Qh!`q!sV!xT6|);ei~9Q(|BZQ9e-RH=AysO$J$i zalKofQv}y-qzzz#3TY>_pl=DTS;1p?U0`TKo?B!2jiw&>+<0D>IJy1!)#+1zDZDig z!hA>I0)6wdMoyY=m)x0V79QX|Zyz}#157OqkegKKxnR2LYbp>F2_wo5S{?2F(wZy` zva8wvf4UwnG}_T;BLFqdG$h~}0^<%nY_5*`6IzwdTBiVH# zIixUfRvoEX*{8tmORc|xUN&tbp*=%8l;#bIB#t-k|LcB2d4ac*pf_)az+X3U;!dfv k#7^-qh;CMg Date: Thu, 18 Dec 2025 16:00:02 +0800 Subject: [PATCH 11/15] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=B8=8A=E6=B8=B8?= =?UTF-8?q?=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/etc/apt/sources.list.d/apm.list | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/etc/apt/sources.list.d/apm.list b/src/etc/apt/sources.list.d/apm.list index 390f3bc..74ac89b 100644 --- a/src/etc/apt/sources.list.d/apm.list +++ b/src/etc/apt/sources.list.d/apm.list @@ -1,3 +1,2 @@ -deb [Signed-by=/etc/apt/trusted.gpg.d/gxde.gpg] https://repo.gxde.top/gxde-os/lizhi ./ -# 大学镜像站 -#deb [Signed-by=/etc/apt/trusted.gpg.d/gxde.gpg] https://mirrors.cernet.edu.cn/GXDE/gxde-os/lizhi ./ +deb [signed-by=/etc/apt/trusted.gpg.d/apm.gpg] https://d.spark-app.store/apm-deb-source / +# 上面这行配置可在4.1.2+版本普及后启用,可以做到分不同目录 From 3a8a8e2f14cd17b29c0d18725f7cebfecbbf27d6 Mon Sep 17 00:00:00 2001 From: shenmo Date: Fri, 19 Dec 2025 08:32:41 +0800 Subject: [PATCH 12/15] dummy update --- apm-dummy/DEBIAN/control | 2 +- apm-dummy/usr/bin/amber-pm-dstore-patch | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apm-dummy/DEBIAN/control b/apm-dummy/DEBIAN/control index d31e745..e776b5e 100755 --- a/apm-dummy/DEBIAN/control +++ b/apm-dummy/DEBIAN/control @@ -1,5 +1,5 @@ Package: apm -Version: 1.1.1 +Version: 1.1.2 Maintainer: shenmo Priority: optional Section: utils diff --git a/apm-dummy/usr/bin/amber-pm-dstore-patch b/apm-dummy/usr/bin/amber-pm-dstore-patch index cc6b77f..3ffb8f2 100755 --- a/apm-dummy/usr/bin/amber-pm-dstore-patch +++ b/apm-dummy/usr/bin/amber-pm-dstore-patch @@ -98,7 +98,7 @@ function exec_link_clean(){ find /usr/share/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/help -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/locale -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & - find /usr/lib/$(gcc -dumpmachine)/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & +# find /usr/lib/$(gcc -dumpmachine)/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/lib/mozilla/plugins -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/polkit-1/actions -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/fonts -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & From 60ff1c1ec85aa63c0ab5628d1f7f4f60a3d74728 Mon Sep 17 00:00:00 2001 From: shenmo Date: Fri, 19 Dec 2025 08:34:04 +0800 Subject: [PATCH 13/15] =?UTF-8?q?fix=20=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/usr/bin/amber-pm-dstore-patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usr/bin/amber-pm-dstore-patch b/src/usr/bin/amber-pm-dstore-patch index cc6b77f..3ffb8f2 100755 --- a/src/usr/bin/amber-pm-dstore-patch +++ b/src/usr/bin/amber-pm-dstore-patch @@ -98,7 +98,7 @@ function exec_link_clean(){ find /usr/share/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/help -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/locale -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & - find /usr/lib/$(gcc -dumpmachine)/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & +# find /usr/lib/$(gcc -dumpmachine)/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/lib/mozilla/plugins -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/polkit-1/actions -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/fonts -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & From 89d17eb5f14057c93703a581057aa0f94a7b4196 Mon Sep 17 00:00:00 2001 From: shenmo Date: Fri, 19 Dec 2025 07:03:45 +0000 Subject: [PATCH 14/15] update src/var/lib/apm/apm/files/bin/ace-init. Signed-off-by: shenmo --- src/var/lib/apm/apm/files/bin/ace-init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/var/lib/apm/apm/files/bin/ace-init b/src/var/lib/apm/apm/files/bin/ace-init index 8c19785..4e9a2be 100755 --- a/src/var/lib/apm/apm/files/bin/ace-init +++ b/src/var/lib/apm/apm/files/bin/ace-init @@ -112,7 +112,7 @@ chown -R root $chrootEnvPath mkdir -p $chrootEnvPath/amber-ce-tools/data-dir ln -sv ../../usr/share/applications $chrootEnvPath/amber-ce-tools/data-dir/ ln -sv ../../usr/share/icons $chrootEnvPath/amber-ce-tools/data-dir/ -mkdir -p chrootEnvPath/usr/share/templates +mkdir -p $chrootEnvPath/usr/share/templates ln -sfv ../../usr/share/templates/ $chrootEnvPath/amber-ce-tools/data-dir/ From 01bbf1265d0b5b92d236cd6ac8098f3529a8f71d Mon Sep 17 00:00:00 2001 From: shenmo Date: Sat, 27 Dec 2025 10:44:49 +0000 Subject: [PATCH 15/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=89=93=E5=8C=85?= =?UTF-8?q?=E5=87=BA=E6=9D=A5=E7=9A=84=E5=BA=94=E7=94=A8=E5=8C=85=E5=90=AB?= =?UTF-8?q?=20.dpkg-new=20=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: shenmo --- src/usr/bin/amber-pm-convert | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/usr/bin/amber-pm-convert b/src/usr/bin/amber-pm-convert index 7835da5..385b307 100755 --- a/src/usr/bin/amber-pm-convert +++ b/src/usr/bin/amber-pm-convert @@ -648,6 +648,23 @@ fi sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/aptss/lists || true sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/cache/apt/* || true +#清理 .dpkg-new 文件 +log.info "搜索并清理 .dpkg-new 文件..." +# 在 core 目录下查找并删除所有以 .dpkg-new 结尾的文件 +find "$CRAFT_DIR/core" -name "*.dpkg-new" -type f 2>/dev/null | while read -r file; do + log.info "删除: $file" + rm -f "$file" +done + +# 统计清理结果 +COUNT=$(find "$CRAFT_DIR/core" -name "*.dpkg-new" -type f 2>/dev/null | wc -l) +if [ "$COUNT" -eq 0 ]; then + log.info "已清理所有 .dpkg-new 文件" +else + log.warn "仍有 $COUNT 个 .dpkg-new 文件存在" +fi + + # 5. 创建新的 APM 包结构 log.info "创建新的APM包结构..." PKG_BUILD_DIR="$CRAFT_DIR/new-pkg"