refactor: 迁移至 bashly CLI 与功能域模块结构
- CLI 定义迁移至 src/bashly.yml(bashly 1.4 生成参数解析),入口收敛为 src/root_command.sh - 源码按功能域重组:config/storage/integrate/media/pipeline,消除扁平散落 - 新增零依赖测试框架 tests/(123 用例)与 CI 流水线(lint + test + build + 产物一致性) - build.sh 支持版本单一来源注入与 --check 产物校验;新增 lint.sh(bash -n + shellcheck 零容忍) - 删除旧单文件 media_organizer.sh 与旧扁平模块
This commit is contained in:
1 parent
d978a13a83
commit
0df07ad0ae
48 files changed
+5813
-6812
No files matched your search
@@ -0,0 +1,90 @@
|
||||
# shellcheck shell=bash
|
||||
|
||||
################################################################################
|
||||
# 硬链接处理
|
||||
################################################################################
|
||||
|
||||
# 判断源与目标是否为同一 inode(硬链接已存在)。
|
||||
# 获取文件 inode(兼容 GNU/BSD/BusyBox stat)。
|
||||
# 依次尝试:GNU stat -c '%i' -> BSD stat -f '%i' -> ls -i -> find -printf。
|
||||
get_file_inode() {
|
||||
local filepath="$1"
|
||||
local inode
|
||||
inode=$(stat -c '%i' "$filepath" 2>/dev/null)
|
||||
[[ -n "$inode" ]] && {
|
||||
echo "$inode"
|
||||
return 0
|
||||
}
|
||||
inode=$(stat -f '%i' "$filepath" 2>/dev/null)
|
||||
[[ -n "$inode" ]] && {
|
||||
echo "$inode"
|
||||
return 0
|
||||
}
|
||||
# ls -i 解析 inode 字段(BusyBox 可靠,stat/find -printf 可能不可用)
|
||||
# shellcheck disable=SC2012
|
||||
inode=$(ls -i "$filepath" 2>/dev/null | awk '{print $1}')
|
||||
[[ -n "$inode" ]] && {
|
||||
echo "$inode"
|
||||
return 0
|
||||
}
|
||||
# GNU find 兜底:-printf 解析 inode
|
||||
find "$filepath" -maxdepth 0 -printf '%i' 2>/dev/null
|
||||
}
|
||||
|
||||
same_inode() {
|
||||
local src="$1" dst="$2"
|
||||
[[ ! -e "$dst" ]] && return 1
|
||||
local src_inode dst_inode
|
||||
|
||||
src_inode=$(get_file_inode "$src")
|
||||
dst_inode=$(get_file_inode "$dst")
|
||||
[[ -z "$src_inode" || -z "$dst_inode" ]] && return 1
|
||||
|
||||
[[ "$src_inode" == "$dst_inode" ]]
|
||||
}
|
||||
|
||||
# 创建硬链接;干运行模式下仅打印;目标已存在时直接替换(不备份)。
|
||||
# 注:不做 .bak 备份——遗留的 .bak_* 文件会被 Jellyfin 当作媒体扫描,干扰刮削。
|
||||
hardlink_or_dryrun() {
|
||||
local src="$1" dst="$2"
|
||||
|
||||
if $DRY_RUN; then
|
||||
_log 信息 "干运行:硬链接 '$src' -> '$dst'"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if same_inode "$src" "$dst"; then
|
||||
_log 跳过 "硬链接已存在,inode: $(stat -c '%i' "$src" 2>/dev/null)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 目标已存在:直接替换(先删旧目标再建硬链接)
|
||||
if [[ -e "$dst" ]]; then
|
||||
# 安全保护:目标是目录(如误传根目录)时拒绝替换,避免误操作真实目录
|
||||
if [[ -d "$dst" ]]; then
|
||||
_log 错误 "目标是目录,拒绝替换: $dst"
|
||||
return 1
|
||||
fi
|
||||
_log 信息 "目标已存在,直接替换: $dst"
|
||||
rm -f "$dst"
|
||||
fi
|
||||
|
||||
if ln "$src" "$dst"; then
|
||||
_log 成功 "硬链接已创建"
|
||||
return 0
|
||||
else
|
||||
_log 错误 "硬链接创建失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# 错误处理
|
||||
################################################################################
|
||||
|
||||
# 全局 ERR trap:记录出错行号后退出。
|
||||
_handle_error() {
|
||||
local line_num="$1"
|
||||
_log 错误 "脚本在第 $line_num 行出错(错误码:$?)"
|
||||
exit 1
|
||||
}
|
||||
Reference in new issue
Block a user