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}" }