mirror of
https://gitee.com/mirrors/AllinSSL.git
synced 2026-05-06 03:51:25 +08:00
【新增】插件git同步模块,用于同步项目内容,加速项目开发
【调整】前端暗色问题
This commit is contained in:
589
frontend/scripts/temp/build-operations.sh
Normal file
589
frontend/scripts/temp/build-operations.sh
Normal file
@@ -0,0 +1,589 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===================================================
|
||||
# 项目编译处理脚本 - build-operations.sh
|
||||
# 用于处理项目编译、工作区选择和编译结果检查
|
||||
# ===================================================
|
||||
|
||||
# 依赖文件操作脚本的函数
|
||||
source "$(dirname "$0")/file-operations.sh"
|
||||
|
||||
# 检查依赖
|
||||
check_dependencies() {
|
||||
local deps=("pnpm" "git")
|
||||
local missing_deps=()
|
||||
|
||||
# 检查基本依赖
|
||||
for dep in "${deps[@]}"; do
|
||||
if ! command -v "$dep" &> /dev/null; then
|
||||
missing_deps+=("$dep")
|
||||
fi
|
||||
done
|
||||
|
||||
# 检查 yq
|
||||
if ! command -v yq &> /dev/null; then
|
||||
log_error "未安装 yq,这是必需的依赖"
|
||||
log_info "请按照以下步骤安装 yq:"
|
||||
case "$(uname -s)" in
|
||||
"Darwin")
|
||||
log_info "1. 使用 Homebrew 安装:"
|
||||
log_info " brew install yq"
|
||||
;;
|
||||
"Linux")
|
||||
log_info "1. 使用包管理器安装:"
|
||||
log_info " # Ubuntu/Debian"
|
||||
log_info " sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64"
|
||||
log_info " sudo chmod a+x /usr/local/bin/yq"
|
||||
log_info " # CentOS/RHEL"
|
||||
log_info " sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64"
|
||||
log_info " sudo chmod a+x /usr/local/bin/yq"
|
||||
;;
|
||||
"MINGW"*|"MSYS"*)
|
||||
log_info "1. 使用 Chocolatey 安装:"
|
||||
log_info " choco install yq"
|
||||
;;
|
||||
esac
|
||||
log_info "2. 安装完成后重新运行此脚本"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查其他缺失的依赖
|
||||
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
||||
log_error "未找到必要的依赖: ${missing_deps[*]}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检测操作系统
|
||||
detect_os() {
|
||||
case "$(uname -s)" in
|
||||
"Darwin")
|
||||
OS="macos"
|
||||
;;
|
||||
"Linux")
|
||||
OS="linux"
|
||||
;;
|
||||
"MINGW"*|"MSYS"*)
|
||||
OS="windows"
|
||||
;;
|
||||
*)
|
||||
log_error "不支持的操作系统"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
log_info "检测到操作系统: $OS"
|
||||
}
|
||||
|
||||
# 解析工作区
|
||||
parse_workspaces() {
|
||||
if [[ ! -f "$PROJECT_ROOT/pnpm-workspace.yaml" ]]; then
|
||||
log_error "未找到工作区配置文件"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 检查 apps 目录
|
||||
if [[ ! -d "$PROJECT_ROOT/apps" ]]; then
|
||||
log_error "未找到 apps 目录"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 扫描 apps 目录下的子目录作为工作区
|
||||
local workspaces=()
|
||||
for dir in "$PROJECT_ROOT/apps"/*/; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
local rel_path="${dir#$PROJECT_ROOT/apps/}"
|
||||
rel_path="${rel_path%/}"
|
||||
workspaces+=("$rel_path")
|
||||
fi
|
||||
done
|
||||
|
||||
# 检查是否找到工作区
|
||||
if [[ ${#workspaces[@]} -eq 0 ]]; then
|
||||
log_error "未在 apps 目录下找到任何工作区"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 初始化选择
|
||||
local selected_index=0
|
||||
local max_index=$((${#workspaces[@]}-1))
|
||||
|
||||
# 设置当前步骤
|
||||
CURRENT_STEP=1
|
||||
|
||||
# 显示工作区列表
|
||||
while true; do
|
||||
# 显示步骤状态
|
||||
show_steps
|
||||
|
||||
# 打印工作区列表
|
||||
printf "%s%s选择当前项目工作区%s\n\n" "${BOLD}" "${CYAN}" "${NC}"
|
||||
|
||||
for i in "${!workspaces[@]}"; do
|
||||
if [[ $i -eq $selected_index ]]; then
|
||||
printf "%s%s❯ %s%s\n" \
|
||||
"${BOLD}" "${GREEN}" "${workspaces[$i]}" "${NC}"
|
||||
else
|
||||
printf " %s%s%s\n" \
|
||||
"${DIM}" "${workspaces[$i]}" "${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
# 显示操作提示
|
||||
printf "\n%s%s使用上下箭头选择,回车确认,q键退出%s\n" \
|
||||
"${BOLD}" "${CYAN}" "${NC}"
|
||||
|
||||
# 读取用户输入 - 统一处理方式
|
||||
local key_pressed=""
|
||||
local key
|
||||
read -r -n 1 key
|
||||
|
||||
# 获取ASCII码用于调试
|
||||
if [[ -z "$key" ]]; then
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "空字符,可能是回车键\n"
|
||||
key_pressed="ENTER" # 空字符通常是回车键
|
||||
else
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "按键ASCII码: %d\n" "'$key"
|
||||
|
||||
# 处理其他按键
|
||||
case "$key" in
|
||||
$'\x1b') # ESC 序列,包括方向键
|
||||
read -r -n 2 seq
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "ESC序列: %s\n" "$seq"
|
||||
case "$seq" in
|
||||
"[A") key_pressed="UP" ;; # 上箭头
|
||||
"[B") key_pressed="DOWN" ;; # 下箭头
|
||||
*) key_pressed="ESC" ;; # 其他ESC序列
|
||||
esac
|
||||
;;
|
||||
"q"|"Q") # q键退出
|
||||
key_pressed="QUIT"
|
||||
;;
|
||||
*) # 其他按键忽略
|
||||
key_pressed="OTHER"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# 调试信息
|
||||
[[ "$DEBUG_MODE" == "true" ]] && log_debug "按键被解析为: $key_pressed"
|
||||
|
||||
# 处理操作
|
||||
case "$key_pressed" in
|
||||
"UP") # 上箭头
|
||||
if [[ $selected_index -gt 0 ]]; then
|
||||
selected_index=$((selected_index-1))
|
||||
else
|
||||
# 如果已经是第一项,跳到最后一项
|
||||
selected_index=$max_index
|
||||
fi
|
||||
;;
|
||||
"DOWN") # 下箭头
|
||||
if [[ $selected_index -lt $max_index ]]; then
|
||||
selected_index=$((selected_index+1))
|
||||
else
|
||||
# 如果已经是最后一项,回到第一项
|
||||
selected_index=0
|
||||
fi
|
||||
;;
|
||||
"ENTER") # 回车
|
||||
SELECTED_WORKSPACE="${workspaces[$selected_index]}"
|
||||
STEP_WORKSPACE="$SELECTED_WORKSPACE"
|
||||
CURRENT_STEP=2
|
||||
return 0
|
||||
;;
|
||||
"QUIT") # 退出
|
||||
log_error "操作已取消"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# 显示步骤状态
|
||||
show_steps() {
|
||||
clear
|
||||
printf "\n%s%s项目同步向导%s\n\n" "${BOLD}" "${MAGENTA}" "${NC}"
|
||||
|
||||
# 定义灰色文本样式,用于未到达的步骤
|
||||
local GRAY="${DIM}"
|
||||
|
||||
# 步骤一:选择工作区
|
||||
if [[ $CURRENT_STEP -eq 1 ]]; then
|
||||
printf "%s%s▶ 第一步:选择工作区%s\n" "${BOLD}" "${GREEN}" "${NC}"
|
||||
elif [[ $CURRENT_STEP -gt 1 ]]; then
|
||||
printf "%s%s✓ 第一步:选择工作区%s %s- %s%s%s\n" \
|
||||
"${DIM}" "${GREEN}" "${NC}" \
|
||||
"${DIM}" "${CYAN}" "$STEP_WORKSPACE" "${NC}"
|
||||
else
|
||||
printf "%s%s○ 第一步:选择工作区%s\n" "${GRAY}" "${GRAY}" "${NC}"
|
||||
fi
|
||||
|
||||
# 步骤二:选择Git仓库
|
||||
if [[ $CURRENT_STEP -eq 2 ]]; then
|
||||
printf "%s%s▶ 第二步:选择Git仓库%s\n" "${BOLD}" "${GREEN}" "${NC}"
|
||||
elif [[ $CURRENT_STEP -gt 2 ]]; then
|
||||
printf "%s%s✓ 第二步:选择Git仓库%s %s- %s%s%s\n" \
|
||||
"${DIM}" "${GREEN}" "${NC}" \
|
||||
"${DIM}" "${CYAN}" "$STEP_GIT_REPOS" "${NC}"
|
||||
else
|
||||
printf "%s%s○ 第二步:选择Git仓库%s\n" "${GRAY}" "${GRAY}" "${NC}"
|
||||
fi
|
||||
|
||||
# 步骤三:选择同步方式
|
||||
if [[ $CURRENT_STEP -eq 3 ]]; then
|
||||
printf "%s%s▶ 第三步:选择同步方式%s\n" "${BOLD}" "${GREEN}" "${NC}"
|
||||
elif [[ $CURRENT_STEP -gt 3 ]]; then
|
||||
printf "%s%s✓ 第三步:选择同步方式%s %s- %s%s%s\n" \
|
||||
"${DIM}" "${GREEN}" "${NC}" \
|
||||
"${DIM}" "${CYAN}" "$STEP_SYNC_MODE" "${NC}"
|
||||
else
|
||||
printf "%s%s○ 第三步:选择同步方式%s\n" "${GRAY}" "${GRAY}" "${NC}"
|
||||
fi
|
||||
|
||||
# 步骤四:执行同步
|
||||
if [[ $CURRENT_STEP -eq 4 ]]; then
|
||||
printf "%s%s▶ 第四步:执行同步%s\n" "${BOLD}" "${GREEN}" "${NC}"
|
||||
elif [[ $CURRENT_STEP -gt 4 ]]; then
|
||||
printf "%s%s✓ 第四步:执行同步%s\n" "${DIM}" "${GREEN}" "${NC}"
|
||||
else
|
||||
printf "%s%s○ 第四步:执行同步%s\n" "${GRAY}" "${GRAY}" "${NC}"
|
||||
fi
|
||||
|
||||
# 分隔线
|
||||
printf "\n"
|
||||
show_separator
|
||||
printf "\n"
|
||||
}
|
||||
|
||||
# 编译执行模块
|
||||
build_workspace() {
|
||||
log_info "开始编译工作区: $SELECTED_WORKSPACE"
|
||||
|
||||
# 切换到项目根目录
|
||||
cd "$PROJECT_ROOT" || {
|
||||
log_error "无法切换到项目根目录"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 执行编译命令
|
||||
log_info "执行编译命令: pnpm build --filter $SELECTED_WORKSPACE"
|
||||
if pnpm build --filter "$SELECTED_WORKSPACE"; then
|
||||
log_info "编译成功"
|
||||
return 0
|
||||
else
|
||||
log_error "编译失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查编译结果
|
||||
check_build_result() {
|
||||
local workspace_path="$PROJECT_ROOT/apps/$SELECTED_WORKSPACE"
|
||||
local dist_path="$workspace_path/dist"
|
||||
|
||||
if [[ ! -d "$dist_path" ]]; then
|
||||
log_error "未找到编译输出目录: $dist_path"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -z "$(ls -A "$dist_path")" ]]; then
|
||||
log_error "编译输出目录为空"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "编译结果检查通过"
|
||||
return 0
|
||||
}
|
||||
|
||||
# 并行编译功能
|
||||
parallel_build_workspaces() {
|
||||
local workspaces=("$@")
|
||||
local pids=()
|
||||
local results=()
|
||||
|
||||
# 检查参数
|
||||
if [[ ${#workspaces[@]} -eq 0 ]]; then
|
||||
log_error "未指定工作区"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "开始并行编译 ${#workspaces[@]} 个工作区..."
|
||||
|
||||
# 为每个工作区启动编译进程
|
||||
for workspace in "${workspaces[@]}"; do
|
||||
(
|
||||
log_info "开始编译工作区: $workspace"
|
||||
if pnpm build --filter "$workspace"; then
|
||||
echo "$workspace|success" > "/tmp/build_${workspace}.result"
|
||||
else
|
||||
echo "$workspace|failed" > "/tmp/build_${workspace}.result"
|
||||
fi
|
||||
) &
|
||||
pids+=($!)
|
||||
done
|
||||
|
||||
# 等待所有编译进程完成
|
||||
for pid in "${pids[@]}"; do
|
||||
wait "$pid" || {
|
||||
log_error "编译进程异常退出"
|
||||
return 1
|
||||
}
|
||||
done
|
||||
|
||||
# 收集编译结果
|
||||
local success=true
|
||||
for workspace in "${workspaces[@]}"; do
|
||||
if [[ -f "/tmp/build_${workspace}.result" ]]; then
|
||||
local result=$(cat "/tmp/build_${workspace}.result")
|
||||
local status=$(echo "$result" | cut -d'|' -f2)
|
||||
if [[ "$status" == "failed" ]]; then
|
||||
log_error "工作区 $workspace 编译失败"
|
||||
success=false
|
||||
else
|
||||
log_info "工作区 $workspace 编译成功"
|
||||
fi
|
||||
rm -f "/tmp/build_${workspace}.result"
|
||||
else
|
||||
log_error "工作区 $workspace 编译结果文件丢失"
|
||||
success=false
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$success" == "true" ]]; then
|
||||
log_info "所有工作区编译完成"
|
||||
return 0
|
||||
else
|
||||
log_error "部分工作区编译失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 显示选项列表
|
||||
show_option_list() {
|
||||
local title="$1"
|
||||
shift
|
||||
local selected_index="${!#}" # 取最后一个参数
|
||||
local items=("${@:1:$(($#-1))}") # 除最后一个参数外的所有参数
|
||||
local padding=2 # 选中标识的宽度
|
||||
|
||||
# 显示标题
|
||||
show_title "$title"
|
||||
printf "%s%s%s\n" "${DIM}" "使用方向键选择,回车确认,q 退出" "${NC}"
|
||||
show_separator
|
||||
|
||||
# 显示列表
|
||||
for i in "${!items[@]}"; do
|
||||
if [[ $i -eq $selected_index ]]; then
|
||||
# 选中项:使用固定宽度的选中标识
|
||||
printf "%s%s%s%*s%s%s%s\n" \
|
||||
"${BOLD}" "${CYAN}" "❯" \
|
||||
"$padding" "" \
|
||||
"${GREEN}" "${items[$i]}" "${NC}"
|
||||
else
|
||||
# 未选中项:使用相同的缩进保持对齐
|
||||
printf "%*s%s%s%s\n" \
|
||||
"$((padding + 1))" "" \
|
||||
"${DIM}" "${items[$i]}" "${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
show_separator
|
||||
}
|
||||
|
||||
# 显示多选列表
|
||||
show_multi_select_list() {
|
||||
local title="$1"
|
||||
shift
|
||||
|
||||
local items=()
|
||||
local i=0
|
||||
# 收集所有项目,直到遇到特殊标记 "--INDICES--"
|
||||
while [[ $i -lt $# && "$1" != "--INDICES--" ]]; do
|
||||
items+=("$1")
|
||||
shift
|
||||
((i++))
|
||||
done
|
||||
|
||||
shift # 跳过 "--INDICES--" 标记
|
||||
local selected_indices=($@) # 剩余的参数都是选中的索引
|
||||
local selected_index="${selected_indices[0]}" # 第一个是当前光标位置
|
||||
|
||||
# 移除当前索引,只保留选中项索引
|
||||
selected_indices=("${selected_indices[@]:1}")
|
||||
|
||||
local padding=2 # 选中标识的宽度
|
||||
|
||||
# 显示标题
|
||||
show_title "$title"
|
||||
printf "%s%s%s\n" "${DIM}" "使用数字键1选中/0取消,回车确认,q 退出" "${NC}"
|
||||
show_separator
|
||||
|
||||
# 显示列表
|
||||
for i in "${!items[@]}"; do
|
||||
# 检查当前索引是否在选中列表中
|
||||
local is_selected=false
|
||||
for sel_idx in "${selected_indices[@]}"; do
|
||||
if [[ $i -eq $sel_idx ]]; then
|
||||
is_selected=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $i -eq $selected_index ]]; then
|
||||
# 当前光标位置项 - 使用青色箭头标识
|
||||
if [[ "$is_selected" == "true" ]]; then
|
||||
# 选中项 - 绿色文本,带复选框
|
||||
printf "%s%s%s%*s%s%s%s\n" \
|
||||
"${BOLD}" "${CYAN}" "❯" \
|
||||
"$padding" "" \
|
||||
"${GREEN}" "[✓] ${items[$i]}" "${NC}"
|
||||
else
|
||||
# 未选中项 - 灰色文本,不带复选框
|
||||
printf "%s%s%s%*s%s%s%s\n" \
|
||||
"${BOLD}" "${CYAN}" "❯" \
|
||||
"$padding" "" \
|
||||
"${DIM}" "[ ] ${items[$i]}" "${NC}"
|
||||
fi
|
||||
else
|
||||
# 非当前光标位置项
|
||||
if [[ "$is_selected" == "true" ]]; then
|
||||
# 选中项 - 绿色文本,带复选框
|
||||
printf "%*s%s%s%s\n" \
|
||||
"$((padding + 1))" "" \
|
||||
"${GREEN}" "[✓] ${items[$i]}" "${NC}"
|
||||
else
|
||||
# 未选中项 - 灰色文本,不带复选框
|
||||
printf "%*s%s%s%s\n" \
|
||||
"$((padding + 1))" "" \
|
||||
"${DIM}" "[ ] ${items[$i]}" "${NC}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
show_separator
|
||||
}
|
||||
|
||||
# 显示帮助信息
|
||||
show_help() {
|
||||
show_title "使用帮助"
|
||||
printf "%s%s用法:%s %s [选项]\n\n" "${BOLD}" "${GREEN}" "${NC}" "$0"
|
||||
printf "%s%s选项:%s\n" "${BOLD}" "${BLUE}" "${NC}"
|
||||
printf " %s-w, --workspace%s WORKSPACE %s指定工作区%s\n" "${GREEN}" "${NC}" "${CYAN}" "${NC}"
|
||||
printf " %s-t, --target%s DIR %s指定目标 Git 仓库路径%s\n" "${GREEN}" "${NC}" "${CYAN}" "${NC}"
|
||||
printf " %s-b, --branch%s BRANCH %s指定分支名称%s\n" "${GREEN}" "${NC}" "${CYAN}" "${NC}"
|
||||
printf " %s-s, --sync-structure%s %s同步项目结构%s\n" "${GREEN}" "${NC}" "${CYAN}" "${NC}"
|
||||
printf " %s-p, --parallel%s %s并行编译%s\n" "${GREEN}" "${NC}" "${CYAN}" "${NC}"
|
||||
printf " %s-d, --dry-run%s %s干运行模式%s\n" "${GREEN}" "${NC}" "${CYAN}" "${NC}"
|
||||
printf " %s--debug%s %s调试模式(显示详细日志)%s\n" "${GREEN}" "${NC}" "${CYAN}" "${NC}"
|
||||
printf " %s-h, --help%s %s显示帮助信息%s\n" "${GREEN}" "${NC}" "${CYAN}" "${NC}"
|
||||
|
||||
show_separator
|
||||
}
|
||||
|
||||
# 命令行参数解析
|
||||
parse_args() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-w|--workspace)
|
||||
SELECTED_WORKSPACE="$2"
|
||||
shift 2
|
||||
;;
|
||||
-t|--target)
|
||||
TARGET_GIT_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-b|--branch)
|
||||
BRANCH="$2"
|
||||
shift 2
|
||||
;;
|
||||
-s|--sync-structure)
|
||||
SYNC_STRUCTURE=true
|
||||
shift
|
||||
;;
|
||||
-p|--parallel)
|
||||
PARALLEL_BUILD=true
|
||||
shift
|
||||
;;
|
||||
-d|--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
--debug)
|
||||
DEBUG_MODE=true
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_error "未知参数: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# 初始化插件目录
|
||||
init_plugins() {
|
||||
if [[ -z "$PLUGINS_DIR" ]]; then
|
||||
log_error "插件目录未初始化,请确保已找到项目根目录"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$PLUGINS_DIR" ]]; then
|
||||
mkdir -p "$PLUGINS_DIR" || {
|
||||
log_error "创建插件目录失败: $PLUGINS_DIR"
|
||||
return 1
|
||||
}
|
||||
log_info "已创建插件目录: $PLUGINS_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
# 加载插件
|
||||
load_plugins() {
|
||||
if [[ -z "$PLUGINS_DIR" ]]; then
|
||||
log_error "插件目录未初始化,请确保已找到项目根目录"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -d "$PLUGINS_DIR" ]]; then
|
||||
for plugin in "$PLUGINS_DIR"/*.sh; do
|
||||
if [[ -f "$plugin" ]]; then
|
||||
if ! source "$plugin"; then
|
||||
log_error "加载插件失败: $(basename "$plugin")"
|
||||
continue
|
||||
fi
|
||||
log_info "已加载插件: $(basename "$plugin")"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# 插件钩子函数
|
||||
run_hook() {
|
||||
local hook_name="$1"
|
||||
shift
|
||||
|
||||
# 检查是否存在对应的钩子函数
|
||||
if declare -F "hook_${hook_name}" > /dev/null; then
|
||||
"hook_${hook_name}" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# 导出函数
|
||||
export -f check_dependencies
|
||||
export -f detect_os
|
||||
export -f parse_workspaces
|
||||
export -f show_steps
|
||||
export -f build_workspace
|
||||
export -f check_build_result
|
||||
export -f parallel_build_workspaces
|
||||
export -f show_option_list
|
||||
export -f show_multi_select_list
|
||||
export -f show_help
|
||||
export -f parse_args
|
||||
export -f init_plugins
|
||||
export -f load_plugins
|
||||
export -f run_hook
|
||||
7
frontend/scripts/temp/clear.sh
Normal file
7
frontend/scripts/temp/clear.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
# 查找并删除当前目录及子目录下所有 node_modules 文件夹和pnpm-lock.yaml文件 和 .turbo 文件夹
|
||||
find . -name "node_modules" -type d -prune -exec rm -rf {} +
|
||||
find . -name "pnpm-lock.yaml" -type f -delete
|
||||
find . -name "dist" -type d -prune -exec rm -rf {} +
|
||||
find . -name ".turbo" -type d -prune -exec rm -rf {} +
|
||||
echo "删除成功"
|
||||
620
frontend/scripts/temp/cursor_backup.sh
Normal file
620
frontend/scripts/temp/cursor_backup.sh
Normal file
@@ -0,0 +1,620 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 检测操作系统并设置相关变量
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
OS="macOS"
|
||||
SETTINGS_DIR="$HOME/Library/Application Support/Cursor"
|
||||
EXTENSIONS_DIR="$HOME/.cursor"
|
||||
USER_DIR="$SETTINGS_DIR/User"
|
||||
TEMP_ROOT="/tmp"
|
||||
PATH_SEP="/"
|
||||
STAT_CMD="stat -f"
|
||||
STAT_TIME_FORMAT="%Sm"
|
||||
STAT_SIZE_FORMAT="%z"
|
||||
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" || "$OSTYPE" == "cygwin" ]]; then
|
||||
OS="Windows"
|
||||
# Windows 下使用 APPDATA 环境变量
|
||||
if [ -n "$APPDATA" ]; then
|
||||
SETTINGS_DIR="$APPDATA/Cursor"
|
||||
EXTENSIONS_DIR="$APPDATA/Cursor"
|
||||
else
|
||||
SETTINGS_DIR="$HOME/AppData/Roaming/Cursor"
|
||||
EXTENSIONS_DIR="$HOME/AppData/Roaming/Cursor"
|
||||
fi
|
||||
USER_DIR="$SETTINGS_DIR/User"
|
||||
TEMP_ROOT="$TEMP"
|
||||
[ -z "$TEMP_ROOT" ] && TEMP_ROOT="$TMP"
|
||||
[ -z "$TEMP_ROOT" ] && TEMP_ROOT="$HOME/AppData/Local/Temp"
|
||||
PATH_SEP="/"
|
||||
STAT_CMD="stat -c"
|
||||
STAT_TIME_FORMAT="%y"
|
||||
STAT_SIZE_FORMAT="%s"
|
||||
else
|
||||
echo -e "${RED}错误: 不支持的操作系统${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 规范化路径
|
||||
normalize_path() {
|
||||
local path="$1"
|
||||
echo "$path" | sed 's/\\/\//g'
|
||||
}
|
||||
|
||||
# 备份目录
|
||||
BACKUP_DIR="$(normalize_path "$HOME/cursor_backups")"
|
||||
|
||||
# 检查目录是否存在
|
||||
if [ ! -d "$SETTINGS_DIR" ] && [ ! -d "$EXTENSIONS_DIR" ]; then
|
||||
echo -e "${RED}错误: 未找到 Cursor 目录${NC}"
|
||||
echo -e "${YELLOW}请确保 Cursor 编辑器已经安装并运行过至少一次${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 创建备份目录
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# 获取文件修改时间
|
||||
get_file_time() {
|
||||
local file="$1"
|
||||
if [[ "$OS" == "Windows" ]]; then
|
||||
# 对于 Windows,使用兼容的时间格式
|
||||
$STAT_CMD "$STAT_TIME_FORMAT" "$file" 2>/dev/null || echo "Unknown"
|
||||
else
|
||||
$STAT_CMD "$STAT_TIME_FORMAT" "$file"
|
||||
fi
|
||||
}
|
||||
|
||||
# 获取文件大小
|
||||
get_file_size() {
|
||||
local file="$1"
|
||||
if [[ "$OS" == "Windows" ]]; then
|
||||
# 对于 Windows,使用兼容的大小获取方式
|
||||
$STAT_CMD "$STAT_SIZE_FORMAT" "$file" 2>/dev/null || echo "0"
|
||||
else
|
||||
$STAT_CMD "$STAT_SIZE_FORMAT" "$file"
|
||||
fi
|
||||
}
|
||||
|
||||
# 创建临时目录
|
||||
create_temp_dir() {
|
||||
local prefix="$1"
|
||||
local temp_dir
|
||||
|
||||
if [[ "$OS" == "Windows" ]]; then
|
||||
temp_dir="$(normalize_path "$TEMP_ROOT/$prefix")"
|
||||
else
|
||||
temp_dir="$TEMP_ROOT/$prefix"
|
||||
fi
|
||||
|
||||
mkdir -p "$temp_dir"
|
||||
echo "$temp_dir"
|
||||
}
|
||||
|
||||
# 获取下一个可用的序号
|
||||
get_next_sequence() {
|
||||
local date=$1
|
||||
local max_seq=0
|
||||
|
||||
# 查找同一天的备份,获取最大序号
|
||||
find "$BACKUP_DIR" -maxdepth 1 -type d -name "cursor_${date}_*" | while read -r backup; do
|
||||
if [ -d "$backup" ]; then
|
||||
backup_name=$(basename "$backup")
|
||||
# 提取日期和序号
|
||||
if [[ $backup_name =~ ^cursor_${date}_([0-9]+)$ ]]; then
|
||||
seq_num=${BASH_REMATCH[1]}
|
||||
if (( seq_num > max_seq )); then
|
||||
max_seq=$seq_num
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# 返回下一个序号
|
||||
echo $((max_seq + 1))
|
||||
}
|
||||
|
||||
# 获取插件列表
|
||||
get_extensions_list() {
|
||||
local extensions_dir="$(normalize_path "$1")"
|
||||
local output_file="$(normalize_path "$2")"
|
||||
|
||||
if [ ! -d "$extensions_dir/extensions" ]; then
|
||||
echo -e "${YELLOW}! 未找到插件目录${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}正在检查插件列表...${NC}"
|
||||
|
||||
# 创建一个临时文件来存储插件信息
|
||||
local temp_list="$(create_temp_dir "cursor_ext_list")/extensions.tmp"
|
||||
|
||||
# 遍历插件目录
|
||||
if [[ "$OS" == "Windows" ]]; then
|
||||
# Windows 环境使用 dir /b 命令
|
||||
(cd "$extensions_dir/extensions" && cmd //c "dir /b /ad" 2>/dev/null) | while read -r ext_name; do
|
||||
local package_json="$extensions_dir/extensions/$ext_name/package.json"
|
||||
package_json="$(normalize_path "$package_json")"
|
||||
if [ -f "$package_json" ]; then
|
||||
# 尝试从 package.json 中提取版本信息
|
||||
local version=$(grep -o '"version": *"[^"]*"' "$package_json" 2>/dev/null | cut -d'"' -f4)
|
||||
if [ -n "$version" ]; then
|
||||
echo "$ext_name@$version" >> "$temp_list"
|
||||
else
|
||||
echo "$ext_name" >> "$temp_list"
|
||||
fi
|
||||
else
|
||||
echo "$ext_name" >> "$temp_list"
|
||||
fi
|
||||
done
|
||||
else
|
||||
# Unix 环境使用 find 命令
|
||||
find "$extensions_dir/extensions" -maxdepth 1 -type d | while read -r ext_dir; do
|
||||
if [ "$ext_dir" != "$extensions_dir/extensions" ]; then
|
||||
local ext_name=$(basename "$ext_dir")
|
||||
local package_json="$ext_dir/package.json"
|
||||
if [ -f "$package_json" ]; then
|
||||
local version=$(grep -o '"version": *"[^"]*"' "$package_json" 2>/dev/null | cut -d'"' -f4)
|
||||
if [ -n "$version" ]; then
|
||||
echo "$ext_name@$version" >> "$temp_list"
|
||||
else
|
||||
echo "$ext_name" >> "$temp_list"
|
||||
fi
|
||||
else
|
||||
echo "$ext_name" >> "$temp_list"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# 排序插件列表
|
||||
if [ -f "$temp_list" ]; then
|
||||
sort "$temp_list" > "$output_file"
|
||||
rm -f "$temp_list"
|
||||
return 0
|
||||
fi
|
||||
|
||||
rm -f "$temp_list"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 显示插件列表差异
|
||||
show_extensions_diff() {
|
||||
local backup_list="$1"
|
||||
local current_list="$2"
|
||||
|
||||
if [ ! -f "$backup_list" ] || [ ! -f "$current_list" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "\n${YELLOW}插件对比:${NC}"
|
||||
|
||||
# 找出新增的插件
|
||||
echo -e "\n${GREEN}新增的插件:${NC}"
|
||||
comm -13 "$backup_list" "$current_list" | while read -r ext; do
|
||||
echo -e "${GREEN}+ $ext${NC}"
|
||||
done
|
||||
|
||||
# 找出删除的插件
|
||||
echo -e "\n${RED}删除的插件:${NC}"
|
||||
comm -23 "$backup_list" "$current_list" | while read -r ext; do
|
||||
echo -e "${RED}- $ext${NC}"
|
||||
done
|
||||
|
||||
# 找出相同的插件
|
||||
echo -e "\n${YELLOW}保持不变的插件:${NC}"
|
||||
comm -12 "$backup_list" "$current_list" | while read -r ext; do
|
||||
echo -e " $ext"
|
||||
done
|
||||
}
|
||||
|
||||
# 创建备份
|
||||
create_backup() {
|
||||
# 生成日期和序号
|
||||
DATE=$(date +"%Y%m%d")
|
||||
SEQ=$(get_next_sequence "$DATE")
|
||||
# 格式化序号为两位数
|
||||
printf -v SEQ_PADDED "%02d" "$SEQ"
|
||||
BACKUP_NAME="cursor_${DATE}_${SEQ_PADDED}"
|
||||
BACKUP_PATH="$BACKUP_DIR/$BACKUP_NAME"
|
||||
TEMP_PATH="/tmp/$BACKUP_NAME"
|
||||
|
||||
echo -e "${YELLOW}正在创建备份...${NC}"
|
||||
echo -e "${YELLOW}操作系统: $OS${NC}"
|
||||
echo -e "${YELLOW}设置目录: $SETTINGS_DIR${NC}"
|
||||
echo -e "${YELLOW}插件目录: $EXTENSIONS_DIR${NC}"
|
||||
|
||||
# 创建临时目录
|
||||
mkdir -p "$TEMP_PATH"
|
||||
|
||||
# 获取当前插件列表
|
||||
local extensions_list="$TEMP_PATH/extensions.list"
|
||||
if get_extensions_list "$EXTENSIONS_DIR" "$extensions_list"; then
|
||||
echo -e "${GREEN}✓ 已保存插件列表${NC}"
|
||||
echo -e "\n${YELLOW}当前安装的插件:${NC}"
|
||||
cat "$extensions_list" | while read -r ext; do
|
||||
echo " $ext"
|
||||
done
|
||||
echo
|
||||
fi
|
||||
|
||||
# 备份设置文件
|
||||
if [ -f "$USER_DIR/settings.json" ]; then
|
||||
mkdir -p "$TEMP_PATH/User"
|
||||
cp "$USER_DIR/settings.json" "$TEMP_PATH/User/"
|
||||
echo -e "${GREEN}✓ 已备份设置文件${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}! 未找到设置文件${NC}"
|
||||
fi
|
||||
|
||||
# 备份扩展目录
|
||||
if [ -d "$EXTENSIONS_DIR/extensions" ]; then
|
||||
cp -r "$EXTENSIONS_DIR/extensions" "$TEMP_PATH/"
|
||||
echo -e "${GREEN}✓ 已备份扩展目录${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}! 未找到扩展目录${NC}"
|
||||
fi
|
||||
|
||||
# 压缩备份
|
||||
echo -e "${YELLOW}正在压缩备份...${NC}"
|
||||
tar -czf "${BACKUP_PATH}.tar.gz" -C "/tmp" "$BACKUP_NAME"
|
||||
|
||||
# 清理临时目录
|
||||
rm -rf "$TEMP_PATH"
|
||||
|
||||
echo -e "${GREEN}备份创建成功: ${BACKUP_PATH}.tar.gz${NC}"
|
||||
}
|
||||
|
||||
# 还原备份
|
||||
restore_backup() {
|
||||
if [ -z "$1" ]; then
|
||||
echo -e "${RED}错误: 请指定要还原的备份名称${NC}"
|
||||
echo "用法: $0 restore <backup_name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACKUP_NAME="$1"
|
||||
BACKUP_PATH="$BACKUP_DIR/$BACKUP_NAME"
|
||||
TEMP_PATH="/tmp/$BACKUP_NAME"
|
||||
|
||||
if [ ! -f "${BACKUP_PATH}.tar.gz" ]; then
|
||||
echo -e "${RED}错误: 未找到备份文件: ${BACKUP_PATH}.tar.gz${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}正在还原备份...${NC}"
|
||||
echo -e "${YELLOW}操作系统: $OS${NC}"
|
||||
echo -e "${YELLOW}设置目录: $SETTINGS_DIR${NC}"
|
||||
echo -e "${YELLOW}插件目录: $EXTENSIONS_DIR${NC}"
|
||||
|
||||
# 解压备份到临时目录
|
||||
echo -e "${YELLOW}正在解压备份...${NC}"
|
||||
rm -rf "$TEMP_PATH"
|
||||
tar -xzf "${BACKUP_PATH}.tar.gz" -C "/tmp"
|
||||
|
||||
# 获取当前插件列表
|
||||
local current_list=$(mktemp)
|
||||
local backup_list="$TEMP_PATH/extensions.list"
|
||||
|
||||
if get_extensions_list "$EXTENSIONS_DIR" "$current_list"; then
|
||||
if [ -f "$backup_list" ]; then
|
||||
show_extensions_diff "$backup_list" "$current_list"
|
||||
echo
|
||||
echo -n "是否继续还原? [y/N] "
|
||||
read -r confirm
|
||||
if [[ ! $confirm =~ ^[Yy]$ ]]; then
|
||||
echo -e "${YELLOW}取消还原操作${NC}"
|
||||
rm -f "$current_list"
|
||||
rm -rf "$TEMP_PATH"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
rm -f "$current_list"
|
||||
|
||||
# 还原设置文件
|
||||
if [ -f "$TEMP_PATH/User/settings.json" ]; then
|
||||
mkdir -p "$USER_DIR"
|
||||
cp "$TEMP_PATH/User/settings.json" "$USER_DIR/"
|
||||
echo -e "${GREEN}✓ 已还原设置文件${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}! 备份中未找到设置文件${NC}"
|
||||
fi
|
||||
|
||||
# 还原扩展目录
|
||||
if [ -d "$TEMP_PATH/extensions" ]; then
|
||||
rm -rf "$EXTENSIONS_DIR/extensions"
|
||||
cp -r "$TEMP_PATH/extensions" "$EXTENSIONS_DIR/"
|
||||
echo -e "${GREEN}✓ 已还原扩展目录${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}! 备份中未找到扩展目录${NC}"
|
||||
fi
|
||||
|
||||
# 清理临时目录
|
||||
rm -rf "$TEMP_PATH"
|
||||
|
||||
echo -e "${GREEN}备份还原成功${NC}"
|
||||
echo -e "${YELLOW}请重启 Cursor 编辑器以使更改生效${NC}"
|
||||
}
|
||||
|
||||
# 删除备份
|
||||
delete_backup() {
|
||||
if [ -z "$1" ]; then
|
||||
echo -e "${RED}错误: 请指定要删除的备份名称${NC}"
|
||||
echo "用法: $0 delete <backup_name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACKUP_NAME="$1"
|
||||
BACKUP_PATH="$BACKUP_DIR/$BACKUP_NAME"
|
||||
|
||||
if [ ! -f "${BACKUP_PATH}.tar.gz" ]; then
|
||||
echo -e "${RED}错误: 未找到备份文件: ${BACKUP_PATH}.tar.gz${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}即将删除备份: $BACKUP_NAME${NC}"
|
||||
echo -n "确认删除? [y/N] "
|
||||
read -r confirm
|
||||
|
||||
if [[ $confirm =~ ^[Yy]$ ]]; then
|
||||
rm -f "${BACKUP_PATH}.tar.gz"
|
||||
echo -e "${GREEN}备份已删除: $BACKUP_NAME${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}取消删除操作${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# 删除所有备份
|
||||
delete_all_backups() {
|
||||
# 检查是否有备份
|
||||
if ! list_backups; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}警告: 即将删除所有备份!${NC}"
|
||||
echo -n "确认删除所有备份? [y/N] "
|
||||
read -r confirm
|
||||
|
||||
if [[ $confirm =~ ^[Yy]$ ]]; then
|
||||
rm -f "$BACKUP_DIR"/cursor_*.tar.gz
|
||||
echo -e "${GREEN}已删除所有备份${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}取消删除操作${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# 格式化文件大小
|
||||
format_size() {
|
||||
local size=$1
|
||||
local units=("B" "KiB" "MiB" "GiB" "TiB")
|
||||
local unit=0
|
||||
|
||||
while (( size > 1024 && unit < 4 )); do
|
||||
size=$(( (size + 512) / 1024 ))
|
||||
((unit++))
|
||||
done
|
||||
|
||||
echo "${size}${units[$unit]}"
|
||||
}
|
||||
|
||||
# 列出备份并返回备份名称数组
|
||||
list_backups() {
|
||||
if [ ! -d "$BACKUP_DIR" ]; then
|
||||
echo -e "${YELLOW}未找到备份${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 创建一个数组来存储备份名称
|
||||
backup_names=()
|
||||
|
||||
echo -e "${YELLOW}可用的备份:${NC}"
|
||||
id=1
|
||||
|
||||
if [[ "$OS" == "Windows" ]]; then
|
||||
# Windows 环境使用 dir 命令
|
||||
(cd "$BACKUP_DIR" && cmd //c "dir /b *.tar.gz" 2>/dev/null) | sort -r | while read -r backup_file; do
|
||||
local backup="$BACKUP_DIR/$backup_file"
|
||||
backup="$(normalize_path "$backup")"
|
||||
if [ -f "$backup" ]; then
|
||||
local backup_name=$(basename "$backup" .tar.gz)
|
||||
backup_names+=("$backup_name")
|
||||
local backup_time=$(get_file_time "$backup")
|
||||
local backup_size=$(get_file_size "$backup")
|
||||
local formatted_size=$(format_size "$backup_size")
|
||||
printf "%2d) %s (%s) [%8s]\n" $id "$backup_name" "$backup_time" "$formatted_size"
|
||||
((id++))
|
||||
fi
|
||||
done
|
||||
else
|
||||
# Unix 环境使用 find 命令
|
||||
find "$BACKUP_DIR" -maxdepth 1 -type f -name "cursor_*.tar.gz" | sort -r | while read -r backup; do
|
||||
if [ -f "$backup" ]; then
|
||||
local backup_name=$(basename "$backup" .tar.gz)
|
||||
backup_names+=("$backup_name")
|
||||
local backup_time=$(get_file_time "$backup")
|
||||
local backup_size=$(get_file_size "$backup")
|
||||
local formatted_size=$(format_size "$backup_size")
|
||||
printf "%2d) %s (%s) [%8s]\n" $id "$backup_name" "$backup_time" "$formatted_size"
|
||||
((id++))
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# 如果没有找到备份
|
||||
if [ ${#backup_names[@]} -eq 0 ]; then
|
||||
echo -e "${YELLOW}没有可用的备份${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# 根据ID获取备份名称
|
||||
get_backup_by_id() {
|
||||
local id=$1
|
||||
local -a backup_names=()
|
||||
|
||||
# 获取所有备份名称并排序
|
||||
find "$BACKUP_DIR" -maxdepth 1 -type f -name "cursor_*.tar.gz" | sort -r | while read -r backup; do
|
||||
if [ -f "$backup" ]; then
|
||||
backup_name=$(basename "$backup" .tar.gz)
|
||||
backup_names+=("$backup_name")
|
||||
fi
|
||||
done
|
||||
|
||||
# 检查ID是否有效
|
||||
if [ "$id" -le 0 ] || [ "$id" -gt "${#backup_names[@]}" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 返回对应的备份名称
|
||||
echo "${backup_names[$((id-1))]}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# 显示帮助信息
|
||||
show_help() {
|
||||
echo -e "${GREEN}Cursor 编辑器备份工具${NC}"
|
||||
echo -e "${YELLOW}当前操作系统: $OS${NC}"
|
||||
if [[ "$OS" == "macOS" ]]; then
|
||||
echo -e "${YELLOW}设置目录: $SETTINGS_DIR${NC}"
|
||||
echo -e "${YELLOW}插件目录: $EXTENSIONS_DIR${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Cursor 目录: $SETTINGS_DIR${NC}"
|
||||
fi
|
||||
echo -e "${YELLOW}备份目录: $BACKUP_DIR${NC}"
|
||||
echo
|
||||
echo "用法:"
|
||||
echo " 创建备份: $0 backup"
|
||||
echo " 还原备份: $0 restore <backup_name>"
|
||||
echo " 删除备份: $0 delete <backup_name>"
|
||||
echo " 删除所有: $0 delete-all"
|
||||
echo " 列出备份: $0 list"
|
||||
echo " 显示帮助: $0 help"
|
||||
}
|
||||
|
||||
# 显示菜单并获取用户选择
|
||||
show_menu() {
|
||||
clear
|
||||
echo -e "${GREEN}Cursor 编辑器备份工具${NC}"
|
||||
echo -e "${YELLOW}当前操作系统: $OS${NC}"
|
||||
if [[ "$OS" == "macOS" ]]; then
|
||||
echo -e "${YELLOW}设置目录: $SETTINGS_DIR${NC}"
|
||||
echo -e "${YELLOW}插件目录: $EXTENSIONS_DIR${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Cursor 目录: $SETTINGS_DIR${NC}"
|
||||
fi
|
||||
echo -e "${YELLOW}备份目录: $BACKUP_DIR${NC}"
|
||||
echo
|
||||
echo "请选择操作:"
|
||||
echo "1) 创建备份"
|
||||
echo "2) 还原备份"
|
||||
echo "3) 删除备份"
|
||||
echo "4) 删除所有备份"
|
||||
echo "5) 列出备份"
|
||||
echo "0) 退出"
|
||||
echo
|
||||
echo -n "请输入选项 [0-5]: "
|
||||
read -r choice
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
create_backup
|
||||
;;
|
||||
2)
|
||||
# 显示可用备份并获取用户选择
|
||||
echo
|
||||
if list_backups; then
|
||||
echo
|
||||
echo -n "请输入要还原的备份ID: "
|
||||
read -r backup_id
|
||||
if [[ "$backup_id" =~ ^[0-9]+$ ]]; then
|
||||
backup_name=$(get_backup_by_id "$backup_id")
|
||||
if [ -n "$backup_name" ]; then
|
||||
restore_backup "$backup_name"
|
||||
else
|
||||
echo -e "${RED}错误: 无效的备份ID${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}错误: 请输入有效的数字ID${NC}"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
3)
|
||||
# 显示可用备份并获取用户选择
|
||||
echo
|
||||
if list_backups; then
|
||||
echo
|
||||
echo -n "请输入要删除的备份ID: "
|
||||
read -r backup_id
|
||||
if [[ "$backup_id" =~ ^[0-9]+$ ]]; then
|
||||
backup_name=$(get_backup_by_id "$backup_id")
|
||||
if [ -n "$backup_name" ]; then
|
||||
delete_backup "$backup_name"
|
||||
else
|
||||
echo -e "${RED}错误: 无效的备份ID${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}错误: 请输入有效的数字ID${NC}"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
4)
|
||||
delete_all_backups
|
||||
;;
|
||||
5)
|
||||
list_backups
|
||||
;;
|
||||
0)
|
||||
echo "退出程序"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}无效的选项${NC}"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo
|
||||
echo -n "按回车键继续..."
|
||||
read -r
|
||||
show_menu
|
||||
}
|
||||
|
||||
# 主程序
|
||||
if [ $# -eq 0 ]; then
|
||||
# 如果没有命令行参数,显示交互式菜单
|
||||
show_menu
|
||||
else
|
||||
# 保持原有的命令行参数支持
|
||||
case "$1" in
|
||||
"backup")
|
||||
create_backup
|
||||
;;
|
||||
"restore")
|
||||
restore_backup "$2"
|
||||
;;
|
||||
"delete")
|
||||
delete_backup "$2"
|
||||
;;
|
||||
"delete-all")
|
||||
delete_all_backups
|
||||
;;
|
||||
"list")
|
||||
list_backups
|
||||
;;
|
||||
"help"|"--help"|"-h")
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}未知命令: $1${NC}"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
709
frontend/scripts/temp/file-operations.sh
Normal file
709
frontend/scripts/temp/file-operations.sh
Normal file
@@ -0,0 +1,709 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===================================================
|
||||
# 文件操作脚本 - file-operations.sh
|
||||
# 用于处理文件同步、路径处理和目录结构管理
|
||||
# ===================================================
|
||||
|
||||
# 颜色定义
|
||||
if [[ -t 1 ]]; then # 检查是否在终端中运行
|
||||
RED=$(tput setaf 1)
|
||||
GREEN=$(tput setaf 2)
|
||||
YELLOW=$(tput setaf 3)
|
||||
BLUE=$(tput setaf 4)
|
||||
MAGENTA=$(tput setaf 5)
|
||||
CYAN=$(tput setaf 6)
|
||||
BOLD=$(tput bold)
|
||||
DIM=$(tput dim)
|
||||
NC=$(tput sgr0) # No Color
|
||||
else
|
||||
RED=""
|
||||
GREEN=""
|
||||
YELLOW=""
|
||||
BLUE=""
|
||||
MAGENTA=""
|
||||
CYAN=""
|
||||
BOLD=""
|
||||
DIM=""
|
||||
NC=""
|
||||
fi
|
||||
|
||||
# 工具函数
|
||||
log_info() {
|
||||
printf "%s%s[INFO]%s %s\n" "${BOLD}" "${GREEN}" "${NC}" "$1"
|
||||
}
|
||||
|
||||
log_debug() {
|
||||
if [[ "$DEBUG_MODE" == "true" ]]; then
|
||||
printf "%s%s[DEBUG]%s %s\n" "${BOLD}" "${MAGENTA}" "${NC}" "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
printf "%s%s[WARN]%s %s\n" "${BOLD}" "${YELLOW}" "${NC}" "$1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
printf "%s%s[ERROR]%s %s\n" "${BOLD}" "${RED}" "${NC}" "$1"
|
||||
}
|
||||
|
||||
# 显示分隔线
|
||||
show_separator() {
|
||||
printf "%s%s%s\n" "${DIM}" "──────────────────────────────────────────" "${NC}"
|
||||
}
|
||||
|
||||
# 显示标题
|
||||
show_title() {
|
||||
printf "\n%s%s%s%s\n\n" "${BOLD}" "${CYAN}" "$1" "${NC}"
|
||||
}
|
||||
|
||||
# 显示进度条
|
||||
show_progress() {
|
||||
local current=$1
|
||||
local total=$2
|
||||
local width=30
|
||||
local percentage=$((current * 100 / total))
|
||||
local completed=$((width * current / total))
|
||||
local remaining=$((width - completed))
|
||||
|
||||
printf "\r%s%s[%s%s%s] %d%%" \
|
||||
"${BOLD}" "${CYAN}" \
|
||||
"$(printf '%*s' "$completed" | tr ' ' '●')" \
|
||||
"$(printf '%*s' "$remaining" | tr ' ' '○')" \
|
||||
"${NC}" \
|
||||
"$percentage"
|
||||
}
|
||||
|
||||
# 初始化同步目录结构
|
||||
init_sync_dirs() {
|
||||
if [[ -z "$PROJECT_ROOT" ]]; then
|
||||
log_error "项目根目录未初始化"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 创建同步配置目录
|
||||
SYNC_DIR="$PROJECT_ROOT/.sync"
|
||||
if [[ ! -d "$SYNC_DIR" ]]; then
|
||||
mkdir -p "$SYNC_DIR" || {
|
||||
log_error "创建同步配置目录失败: $SYNC_DIR"
|
||||
return 1
|
||||
}
|
||||
log_info "已创建同步配置目录: $SYNC_DIR"
|
||||
fi
|
||||
|
||||
# 创建 Git 仓库目录
|
||||
GIT_DIR="$PROJECT_ROOT/.git-sync"
|
||||
if [[ ! -d "$GIT_DIR" ]]; then
|
||||
mkdir -p "$GIT_DIR" || {
|
||||
log_error "创建 Git 仓库目录失败: $GIT_DIR"
|
||||
return 1
|
||||
}
|
||||
log_info "已创建 Git 仓库目录: $GIT_DIR"
|
||||
fi
|
||||
|
||||
# 初始化历史记录文件
|
||||
HISTORY_FILE="$SYNC_DIR/history"
|
||||
if [[ ! -f "$HISTORY_FILE" ]]; then
|
||||
touch "$HISTORY_FILE" || {
|
||||
log_error "创建历史记录文件失败: $HISTORY_FILE"
|
||||
return 1
|
||||
}
|
||||
log_info "已创建历史记录文件: $HISTORY_FILE"
|
||||
fi
|
||||
|
||||
# 初始化插件目录
|
||||
PLUGINS_DIR="$SYNC_DIR/plugins"
|
||||
if [[ ! -d "$PLUGINS_DIR" ]]; then
|
||||
mkdir -p "$PLUGINS_DIR" || {
|
||||
log_error "创建插件目录失败: $PLUGINS_DIR"
|
||||
return 1
|
||||
}
|
||||
log_info "已创建插件目录: $PLUGINS_DIR"
|
||||
fi
|
||||
|
||||
# 初始化同步配置文件
|
||||
SYNC_CONFIG_FILE="$SYNC_DIR/sync-config.yaml"
|
||||
if [[ ! -f "$SYNC_CONFIG_FILE" ]]; then
|
||||
cat > "$SYNC_CONFIG_FILE" << EOF
|
||||
# 工具配置
|
||||
config:
|
||||
parallel_build: false # 是否并行编译
|
||||
dry_run: false # 是否干运行
|
||||
|
||||
# 工作区配置
|
||||
workspaces:
|
||||
# 示例配置
|
||||
# app-name:
|
||||
# sync_mappings:
|
||||
# - source:
|
||||
# git_url: "https://github.com/user/repo.git"
|
||||
# branch: "main"
|
||||
# target:
|
||||
# sync_dir: "dist" # 要同步的目录
|
||||
# git_dir: "dist" # Git 仓库中的目标目录
|
||||
EOF
|
||||
log_info "已创建同步配置文件: $SYNC_CONFIG_FILE"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# 查找项目根目录
|
||||
find_project_root() {
|
||||
local current_dir="$PWD"
|
||||
while [[ "$current_dir" != "/" ]]; do
|
||||
if [[ -f "$current_dir/pnpm-workspace.yaml" ]]; then
|
||||
PROJECT_ROOT="$current_dir"
|
||||
log_info "找到项目根目录: $PROJECT_ROOT"
|
||||
# 在找到根目录后,初始化相关路径
|
||||
SYNC_DIR="$PROJECT_ROOT/.sync"
|
||||
GIT_DIR="$PROJECT_ROOT/.git-sync"
|
||||
SYNC_CONFIG_FILE="$SYNC_DIR/sync-config.yaml"
|
||||
HISTORY_FILE="$SYNC_DIR/history"
|
||||
PLUGINS_DIR="$SYNC_DIR/plugins"
|
||||
return 0
|
||||
fi
|
||||
current_dir="$(dirname "$current_dir")"
|
||||
done
|
||||
log_error "未找到项目根目录"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 检查并创建工作区配置目录
|
||||
check_workspace_config_dir() {
|
||||
# 检查工作区配置目录是否存在
|
||||
if [[ ! -d "$WORKSPACE_CONFIG_DIR" ]]; then
|
||||
log_info "工作区配置目录不存在,正在创建..."
|
||||
mkdir -p "$WORKSPACE_CONFIG_DIR" || {
|
||||
log_error "创建工作区配置目录失败: $WORKSPACE_CONFIG_DIR"
|
||||
return 1
|
||||
}
|
||||
log_info "已创建工作区配置目录: $WORKSPACE_CONFIG_DIR"
|
||||
|
||||
# 创建 .gitignore 文件
|
||||
cat > "$WORKSPACE_CONFIG_DIR/.gitignore" << EOF
|
||||
# 忽略所有文件
|
||||
*
|
||||
# 不忽略 .gitignore
|
||||
!.gitignore
|
||||
EOF
|
||||
log_info "已创建 .gitignore 文件"
|
||||
|
||||
# 创建 README.md 文件
|
||||
cat > "$WORKSPACE_CONFIG_DIR/README.md" << EOF
|
||||
# 工作区配置目录
|
||||
|
||||
此目录用于存储各个工作区的同步配置信息。
|
||||
|
||||
## 配置文件格式
|
||||
|
||||
每个工作区对应一个 YAML 配置文件,命名格式为 \`{workspace}.yaml\`。
|
||||
|
||||
### 配置示例
|
||||
|
||||
\`\`\`yaml
|
||||
# 工作区同步配置
|
||||
workspace: "app-name"
|
||||
sync_mappings:
|
||||
- source:
|
||||
git_url: "https://github.com/user/repo.git"
|
||||
branch: "main"
|
||||
target:
|
||||
sync_dir: "dist" # 要同步的目录
|
||||
git_dir: "dist" # Git 仓库中的目标目录
|
||||
\`\`\`
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 此目录不应被 Git 追踪
|
||||
2. 配置文件包含敏感信息,请妥善保管
|
||||
3. 建议定期备份配置文件
|
||||
EOF
|
||||
log_info "已创建 README.md 文件"
|
||||
fi
|
||||
|
||||
# 检查目录权限
|
||||
if [[ ! -w "$WORKSPACE_CONFIG_DIR" ]]; then
|
||||
log_error "工作区配置目录没有写入权限: $WORKSPACE_CONFIG_DIR"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# 同步文件操作函数
|
||||
sync_files() {
|
||||
local source_path="$PROJECT_ROOT/$SELECTED_WORKSPACE"
|
||||
local dist_path="$source_path/dist"
|
||||
|
||||
# 检查源目录
|
||||
if [[ ! -d "$dist_path" ]]; then
|
||||
log_error "源目录不存在: $dist_path"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 询问是否同步项目结构
|
||||
read -p "是否同步项目结构?(y/n): " sync_structure
|
||||
if [[ "$sync_structure" == "y" ]]; then
|
||||
# 同步项目结构
|
||||
log_info "开始同步项目结构..."
|
||||
|
||||
# 创建临时目录
|
||||
local temp_dir=$(mktemp -d)
|
||||
|
||||
# 复制项目结构
|
||||
find "$source_path" -type f -not -path "*/node_modules/*" -not -path "*/dist/*" | while IFS= read -r file; do
|
||||
local rel_path="${file#$source_path/}"
|
||||
local target_path="$temp_dir/$rel_path"
|
||||
mkdir -p "$(dirname "$target_path")"
|
||||
cp "$file" "$target_path"
|
||||
done
|
||||
|
||||
# 移动临时目录内容到目标目录
|
||||
cp -r "$temp_dir"/* "$TARGET_GIT_DIR/"
|
||||
rm -rf "$temp_dir"
|
||||
fi
|
||||
|
||||
# 同步编译结果
|
||||
log_info "开始同步编译结果..."
|
||||
if [[ "$OS" == "windows" ]]; then
|
||||
# Windows 路径处理
|
||||
local target_dist="${TARGET_GIT_DIR}\\dist"
|
||||
if [[ -d "$target_dist" ]]; then
|
||||
rm -rf "$target_dist"
|
||||
fi
|
||||
cp -r "$dist_path" "$target_dist"
|
||||
else
|
||||
# Unix 路径处理
|
||||
local target_dist="$TARGET_GIT_DIR/dist"
|
||||
if [[ -d "$target_dist" ]]; then
|
||||
rm -rf "$target_dist"
|
||||
fi
|
||||
cp -r "$dist_path" "$target_dist"
|
||||
fi
|
||||
|
||||
log_info "文件同步完成"
|
||||
return 0
|
||||
}
|
||||
|
||||
# 同步所有源码文件
|
||||
sync_all_source_files() {
|
||||
local files=("$@")
|
||||
local total=${#files[@]}
|
||||
local current=0
|
||||
|
||||
for target_dir in "${TARGET_GIT_DIRS[@]}"; do
|
||||
log_info "开始同步到: $target_dir"
|
||||
for file in "${files[@]}"; do
|
||||
local rel_path="${file#$PROJECT_ROOT/$SELECTED_WORKSPACE/}"
|
||||
local target_path="$target_dir/$rel_path"
|
||||
mkdir -p "$(dirname "$target_path")"
|
||||
cp "$file" "$target_path"
|
||||
((current++))
|
||||
show_progress "$current" "$total"
|
||||
done
|
||||
printf "\n"
|
||||
done
|
||||
|
||||
log_info "源码同步完成"
|
||||
return 0
|
||||
}
|
||||
|
||||
# 仅同步配置文件
|
||||
sync_config_files() {
|
||||
local files=("$@")
|
||||
local config_files=()
|
||||
|
||||
for file in "${files[@]}"; do
|
||||
if [[ "$file" =~ \.(json|yaml|yml|config\.js|config\.ts)$ ]]; then
|
||||
config_files+=("$file")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#config_files[@]} -eq 0 ]]; then
|
||||
log_error "未找到配置文件"
|
||||
return 1
|
||||
fi
|
||||
|
||||
sync_all_source_files "${config_files[@]}"
|
||||
}
|
||||
|
||||
# 仅同步源代码
|
||||
sync_source_files() {
|
||||
local files=("$@")
|
||||
local source_files=()
|
||||
|
||||
for file in "${files[@]}"; do
|
||||
if [[ "$file" =~ \.(js|ts|jsx|tsx|vue|css|scss|less)$ ]]; then
|
||||
source_files+=("$file")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#source_files[@]} -eq 0 ]]; then
|
||||
log_error "未找到源代码文件"
|
||||
return 1
|
||||
fi
|
||||
|
||||
sync_all_source_files "${source_files[@]}"
|
||||
}
|
||||
|
||||
# 记录操作历史
|
||||
record_history() {
|
||||
if [[ -z "$HISTORY_FILE" ]]; then
|
||||
log_error "历史记录文件未初始化,请确保已找到项目根目录"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local operation="$1" # 操作
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S') # 时间戳
|
||||
echo "$timestamp|$operation" >> "$HISTORY_FILE" # 写入历史记录文件
|
||||
|
||||
# 保持历史记录在最大限制内
|
||||
if [[ -f "$HISTORY_FILE" ]]; then
|
||||
tail -n "$MAX_HISTORY" "$HISTORY_FILE" > "${HISTORY_FILE}.tmp"
|
||||
mv "${HISTORY_FILE}.tmp" "$HISTORY_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# 显示操作历史
|
||||
show_history() {
|
||||
if [[ -z "$HISTORY_FILE" ]]; then
|
||||
log_error "历史记录文件未初始化,请确保已找到项目根目录"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -f "$HISTORY_FILE" ]]; then
|
||||
log_info "最近的操作历史:"
|
||||
while IFS='|' read -r timestamp operation; do
|
||||
echo "$timestamp - $operation"
|
||||
done < "$HISTORY_FILE"
|
||||
else
|
||||
log_info "暂无操作历史"
|
||||
fi
|
||||
}
|
||||
|
||||
# 同步源码
|
||||
sync_source_code() {
|
||||
local workspace_path="$PROJECT_ROOT/$SELECTED_WORKSPACE"
|
||||
local source_files=()
|
||||
|
||||
# 收集需要同步的源码文件
|
||||
for file in $(find "$workspace_path" -type f); do
|
||||
if [[ ! "$file" =~ /(node_modules|dist|\.git)/ ]]; then
|
||||
source_files+=("$file")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#source_files[@]} -eq 0 ]]; then
|
||||
log_error "未找到需要同步的源码文件"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 显示同步选项
|
||||
show_title "同步源码选项"
|
||||
printf "%s%s%s\n" "${DIM}" "选择要同步的内容" "${NC}"
|
||||
show_separator
|
||||
|
||||
local sync_options=(
|
||||
"同步所有源码文件"
|
||||
"仅同步配置文件"
|
||||
"仅同步源代码"
|
||||
"自定义同步"
|
||||
)
|
||||
|
||||
local selected_index=0
|
||||
local max_index=$((${#sync_options[@]}-1))
|
||||
local padding=2
|
||||
|
||||
while true; do
|
||||
clear
|
||||
# 显示选项列表
|
||||
show_title "同步源码选项"
|
||||
printf "%s%s%s\n" "${DIM}" "选择要同步的内容" "${NC}"
|
||||
show_separator
|
||||
|
||||
for i in "${!sync_options[@]}"; do
|
||||
if [[ $i -eq $selected_index ]]; then
|
||||
printf "%s%s%s%*s%s%s%s\n" \
|
||||
"${BOLD}" "${CYAN}" "❯" \
|
||||
"$padding" "" \
|
||||
"${GREEN}" "${sync_options[$i]}" "${NC}"
|
||||
else
|
||||
printf "%*s%s%s%s\n" \
|
||||
"$((padding + 1))" "" \
|
||||
"${DIM}" "${sync_options[$i]}" "${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
show_separator
|
||||
|
||||
# 读取用户输入
|
||||
local key_pressed=""
|
||||
local key
|
||||
read -r -n 1 key
|
||||
|
||||
# 获取ASCII码用于调试(针对回车键)
|
||||
if [[ -z "$key" ]]; then
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "空字符,可能是回车键\n"
|
||||
key_pressed="ENTER"
|
||||
else
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "按键ASCII码: %d\n" "'$key"
|
||||
fi
|
||||
|
||||
# 处理按键
|
||||
case "$key" in
|
||||
$'\x1b') # ESC 序列
|
||||
read -r -n 2 key
|
||||
case "$key" in
|
||||
"[A") # 上箭头
|
||||
if [[ $selected_index -gt 0 ]]; then
|
||||
selected_index=$((selected_index-1))
|
||||
else
|
||||
# 循环到最后一项
|
||||
selected_index=$max_index
|
||||
fi
|
||||
;;
|
||||
"[B") # 下箭头
|
||||
if [[ $selected_index -lt $max_index ]]; then
|
||||
selected_index=$((selected_index+1))
|
||||
else
|
||||
# 循环到第一项
|
||||
selected_index=0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"") # 回车
|
||||
case $selected_index in
|
||||
0) # 同步所有源码文件
|
||||
sync_all_source_files "${source_files[@]}"
|
||||
;;
|
||||
1) # 仅同步配置文件
|
||||
sync_config_files "${source_files[@]}"
|
||||
;;
|
||||
2) # 仅同步源代码
|
||||
sync_source_files "${source_files[@]}"
|
||||
;;
|
||||
3) # 自定义同步
|
||||
sync_custom_files "${source_files[@]}"
|
||||
;;
|
||||
esac
|
||||
return $?
|
||||
;;
|
||||
"q") # 退出
|
||||
log_error "操作已取消"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# 自定义同步文件选择
|
||||
sync_custom_files() {
|
||||
local files=("$@")
|
||||
local selected_files=()
|
||||
local selected_indices=()
|
||||
local cursor_index=0
|
||||
local max_index=$((${#files[@]}-1))
|
||||
local padding=2
|
||||
|
||||
while true; do
|
||||
clear
|
||||
show_title "选择要同步的文件"
|
||||
printf "%s%s%s\n" "${DIM}" "使用数字键1选中/0取消,回车确认,q 退出" "${NC}"
|
||||
show_separator
|
||||
|
||||
# 显示文件列表
|
||||
for i in "${!files[@]}"; do
|
||||
local is_selected=false
|
||||
# 检查当前文件是否已被选中
|
||||
for idx in "${selected_indices[@]}"; do
|
||||
if [[ $i -eq $idx ]]; then
|
||||
is_selected=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $i -eq $cursor_index ]]; then
|
||||
# 当前光标位置
|
||||
if [[ "$is_selected" == "true" ]]; then
|
||||
printf "%s%s%s%*s%s%s%s\n" \
|
||||
"${BOLD}" "${CYAN}" "❯" \
|
||||
"$padding" "" \
|
||||
"${GREEN}" "[✓] ${files[$i]#$PROJECT_ROOT/}" "${NC}"
|
||||
else
|
||||
printf "%s%s%s%*s%s%s%s\n" \
|
||||
"${BOLD}" "${CYAN}" "❯" \
|
||||
"$padding" "" \
|
||||
"${DIM}" "[ ] ${files[$i]#$PROJECT_ROOT/}" "${NC}"
|
||||
fi
|
||||
else
|
||||
# 非光标位置
|
||||
if [[ "$is_selected" == "true" ]]; then
|
||||
printf "%*s%s%s%s\n" \
|
||||
"$((padding + 1))" "" \
|
||||
"${GREEN}" "[✓] ${files[$i]#$PROJECT_ROOT/}" "${NC}"
|
||||
else
|
||||
printf "%*s%s%s%s\n" \
|
||||
"$((padding + 1))" "" \
|
||||
"${DIM}" "[ ] ${files[$i]#$PROJECT_ROOT/}" "${NC}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
show_separator
|
||||
|
||||
# 显示操作提示
|
||||
printf "\n%s%s使用上下箭头选择,数字键1选中/0取消,回车确认,q键退出%s\n" \
|
||||
"${BOLD}" "${CYAN}" "${NC}"
|
||||
|
||||
# 读取用户输入 - 统一处理方式
|
||||
local key_pressed=""
|
||||
local key
|
||||
read -r -n 1 key
|
||||
|
||||
# 获取ASCII码用于调试
|
||||
if [[ -z "$key" ]]; then
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "空字符,可能是回车键\n"
|
||||
key_pressed="ENTER" # 空字符通常是回车键
|
||||
elif [[ "$key" == "1" ]]; then
|
||||
printf "检测到数字键1,执行选中操作\n" # 始终输出,不依赖DEBUG_MODE
|
||||
key_pressed="SELECT" # 选中
|
||||
elif [[ "$key" == "0" ]]; then
|
||||
printf "检测到数字键0,执行取消选中操作\n" # 始终输出,不依赖DEBUG_MODE
|
||||
key_pressed="DESELECT" # 取消选中
|
||||
else
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "按键ASCII码: %d\n" "'$key"
|
||||
|
||||
# 处理其他按键
|
||||
case "$key" in
|
||||
$'\x1b') # ESC 序列,包括方向键
|
||||
read -r -n 2 seq
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "ESC序列: %s\n" "$seq"
|
||||
case "$seq" in
|
||||
"[A") key_pressed="UP" ;; # 上箭头
|
||||
"[B") key_pressed="DOWN" ;; # 下箭头
|
||||
*) key_pressed="ESC" ;; # 其他ESC序列
|
||||
esac
|
||||
;;
|
||||
"q"|"Q") # q键退出
|
||||
key_pressed="QUIT"
|
||||
;;
|
||||
*) # 其他按键忽略
|
||||
key_pressed="OTHER"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# 调试信息
|
||||
[[ "$DEBUG_MODE" == "true" ]] && log_debug "按键被解析为: $key_pressed"
|
||||
|
||||
# 处理操作
|
||||
case "$key_pressed" in
|
||||
"UP") # 上箭头
|
||||
if [[ $cursor_index -gt 0 ]]; then
|
||||
cursor_index=$((cursor_index-1))
|
||||
else
|
||||
# 如果已经是第一项,跳到最后一项
|
||||
cursor_index=$max_index
|
||||
fi
|
||||
;;
|
||||
"DOWN") # 下箭头
|
||||
if [[ $cursor_index -lt $max_index ]]; then
|
||||
cursor_index=$((cursor_index+1))
|
||||
else
|
||||
# 如果已经是最后一项,回到第一项
|
||||
cursor_index=0
|
||||
fi
|
||||
;;
|
||||
"SELECT") # 数字键1 - 选中当前项
|
||||
printf "处理SELECT操作 - 选中当前项: ${cursor_index}\n"
|
||||
# 检查当前索引是否已在选中列表中
|
||||
local found=false
|
||||
for idx in "${selected_indices[@]}"; do
|
||||
if [[ $idx -eq $cursor_index ]]; then
|
||||
found=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# 如果未选中,则添加到选中列表
|
||||
if [[ "$found" == "false" ]]; then
|
||||
selected_indices+=($cursor_index)
|
||||
printf "已添加索引 ${cursor_index} 到选中列表\n"
|
||||
# 对选中项排序
|
||||
if [[ ${#selected_indices[@]} -gt 0 ]]; then
|
||||
IFS=$'\n'
|
||||
selected_indices=($(sort -n <<<"${selected_indices[*]}"))
|
||||
unset IFS
|
||||
fi
|
||||
else
|
||||
printf "索引 ${cursor_index} 已在选中列表中\n"
|
||||
fi
|
||||
;;
|
||||
"DESELECT") # 数字键0 - 取消选中当前项
|
||||
printf "处理DESELECT操作 - 取消选中当前项: ${cursor_index}\n"
|
||||
# 检查当前索引是否已在选中列表中
|
||||
local found=false
|
||||
local new_indices=()
|
||||
|
||||
# 创建新数组,排除当前索引
|
||||
for idx in "${selected_indices[@]}"; do
|
||||
if [[ $idx -ne $cursor_index ]]; then
|
||||
new_indices+=($idx)
|
||||
else
|
||||
found=true # 标记找到了要删除的索引
|
||||
fi
|
||||
done
|
||||
|
||||
# 只有在找到并删除了索引的情况下才更新选中列表
|
||||
if [[ "$found" == "true" ]]; then
|
||||
selected_indices=("${new_indices[@]}")
|
||||
printf "已从选中列表中移除索引 ${cursor_index}\n"
|
||||
else
|
||||
printf "索引 ${cursor_index} 不在选中列表中\n"
|
||||
fi
|
||||
;;
|
||||
"ENTER") # 回车 - 确认选择
|
||||
if [[ ${#selected_indices[@]} -eq 0 ]]; then
|
||||
log_error "请至少选择一个文件"
|
||||
sleep 2 # 暂停显示错误信息
|
||||
continue
|
||||
fi
|
||||
|
||||
# 重建选中文件列表
|
||||
selected_files=()
|
||||
for idx in "${selected_indices[@]}"; do
|
||||
selected_files+=("${files[$idx]}")
|
||||
done
|
||||
|
||||
sync_all_source_files "${selected_files[@]}"
|
||||
return $?
|
||||
;;
|
||||
"QUIT") # 退出
|
||||
log_error "操作已取消"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# 导出函数
|
||||
export -f log_info
|
||||
export -f log_debug
|
||||
export -f log_warn
|
||||
export -f log_error
|
||||
export -f show_separator
|
||||
export -f show_title
|
||||
export -f show_progress
|
||||
export -f init_sync_dirs
|
||||
export -f find_project_root
|
||||
export -f check_workspace_config_dir
|
||||
export -f sync_files
|
||||
export -f sync_all_source_files
|
||||
export -f sync_config_files
|
||||
export -f sync_source_files
|
||||
export -f record_history
|
||||
export -f show_history
|
||||
export -f sync_source_code
|
||||
export -f sync_custom_files
|
||||
515
frontend/scripts/temp/git-operations.sh
Normal file
515
frontend/scripts/temp/git-operations.sh
Normal file
@@ -0,0 +1,515 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===================================================
|
||||
# Git 操作脚本 - git-operations.sh
|
||||
# 用于处理 Git 仓库管理、同步和提交相关功能
|
||||
# ===================================================
|
||||
|
||||
# 依赖文件操作脚本的函数
|
||||
source "$(dirname "$0")/file-operations.sh"
|
||||
|
||||
# Git 操作模块
|
||||
prepare_git_repo() {
|
||||
local git_url="$1"
|
||||
local branch="$2"
|
||||
local alias="$3"
|
||||
local target_dir="$GIT_DIR/${alias:-$(basename "$git_url" .git)}"
|
||||
|
||||
# 检查目标目录是否存在
|
||||
if [[ ! -d "$target_dir" ]]; then
|
||||
log_info "目标目录不存在,尝试克隆仓库"
|
||||
if ! git clone "$git_url" "$target_dir"; then
|
||||
log_error "克隆仓库失败"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 切换到目标目录
|
||||
cd "$target_dir" || {
|
||||
log_error "无法切换到目标目录"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 检查是否是 Git 仓库
|
||||
if [[ ! -d ".git" ]]; then
|
||||
log_error "目标目录不是有效的 Git 仓库"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 清理未提交的更改
|
||||
if [[ -n "$(git status --porcelain)" ]]; then
|
||||
log_warn "发现未提交的更改,正在清理..."
|
||||
git reset --hard HEAD
|
||||
git clean -fd
|
||||
fi
|
||||
|
||||
# 拉取最新代码
|
||||
log_info "拉取最新代码..."
|
||||
if ! git pull; then
|
||||
log_error "拉取代码失败"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 切换到指定分支
|
||||
if [[ -n "$branch" ]]; then
|
||||
log_info "切换到分支: $branch"
|
||||
if ! git checkout "$branch"; then
|
||||
log_error "切换分支失败"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "Git 仓库准备完成"
|
||||
return 0
|
||||
}
|
||||
|
||||
# 获取源项目的最新提交信息
|
||||
get_source_commit_info() {
|
||||
cd "$PROJECT_ROOT" || return 1
|
||||
local commit_hash=$(git rev-parse HEAD)
|
||||
local commit_msg=$(git log -1 --pretty=%B)
|
||||
echo "$commit_hash|$commit_msg"
|
||||
}
|
||||
|
||||
# 提交更改
|
||||
commit_changes() {
|
||||
local commit_info
|
||||
commit_info=$(get_source_commit_info) || {
|
||||
log_error "获取源项目提交信息失败"
|
||||
return 1
|
||||
}
|
||||
|
||||
local commit_hash=$(echo "$commit_info" | cut -d'|' -f1)
|
||||
local commit_msg=$(echo "$commit_info" | cut -d'|' -f2)
|
||||
|
||||
# 添加所有更改
|
||||
git add .
|
||||
|
||||
# 提交更改
|
||||
if git commit -m "sync: $commit_msg (from $commit_hash)"; then
|
||||
log_info "提交成功"
|
||||
return 0
|
||||
else
|
||||
log_error "提交失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 推送更改到远程仓库
|
||||
push_changes() {
|
||||
local current_branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
# 检查是否有远程仓库
|
||||
if ! git remote | grep -q origin; then
|
||||
log_error "未找到远程仓库 origin"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 推送到远程仓库
|
||||
log_info "正在推送更改到远程仓库..."
|
||||
if git push origin "$current_branch"; then
|
||||
log_info "推送成功"
|
||||
return 0
|
||||
else
|
||||
log_error "推送失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 选择 Git 项目目录
|
||||
select_git_dirs() {
|
||||
local git_dirs=()
|
||||
local selected_indices=()
|
||||
local SYNC_MAPPINGS=()
|
||||
|
||||
# 检查配置文件是否存在
|
||||
if [[ ! -f "$SYNC_CONFIG_FILE" ]]; then
|
||||
log_error "配置文件不存在: $SYNC_CONFIG_FILE"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 检查是否安装了 yq
|
||||
if ! command -v yq &> /dev/null; then
|
||||
log_error "未安装 yq,无法读取配置文件"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 检查工作区是否存在
|
||||
if ! yq e ".workspaces.$SELECTED_WORKSPACE" "$SYNC_CONFIG_FILE" &> /dev/null; then
|
||||
log_error "工作区 $SELECTED_WORKSPACE 不存在于配置文件中"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 获取工作区的所有 Git 仓库配置
|
||||
local count
|
||||
count=$(yq e ".workspaces.$SELECTED_WORKSPACE.sync_mappings | length" "$SYNC_CONFIG_FILE")
|
||||
|
||||
if [[ $count -eq 0 ]]; then
|
||||
log_error "工作区 $SELECTED_WORKSPACE 未配置任何 Git 仓库"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 构建显示列表和映射信息
|
||||
local all_mappings=()
|
||||
for ((i=0; i<count; i++)); do
|
||||
local git_url
|
||||
local branch
|
||||
local alias
|
||||
local sync_dir
|
||||
local git_dir
|
||||
|
||||
git_url=$(yq e ".workspaces.$SELECTED_WORKSPACE.sync_mappings[$i].source.git_url" "$SYNC_CONFIG_FILE")
|
||||
branch=$(yq e ".workspaces.$SELECTED_WORKSPACE.sync_mappings[$i].source.branch" "$SYNC_CONFIG_FILE")
|
||||
alias=$(yq e ".workspaces.$SELECTED_WORKSPACE.sync_mappings[$i].source.alias" "$SYNC_CONFIG_FILE")
|
||||
sync_dir=$(yq e ".workspaces.$SELECTED_WORKSPACE.sync_mappings[$i].target.sync_dir" "$SYNC_CONFIG_FILE")
|
||||
git_dir=$(yq e ".workspaces.$SELECTED_WORKSPACE.sync_mappings[$i].target.git_dir" "$SYNC_CONFIG_FILE")
|
||||
|
||||
if [[ -n "$git_url" ]]; then
|
||||
# 格式化显示信息
|
||||
local display_name
|
||||
if [[ -n "$alias" ]]; then
|
||||
display_name="[$alias] $git_url ($branch) -> $sync_dir:$git_dir"
|
||||
else
|
||||
display_name="$git_url ($branch) -> $sync_dir:$git_dir"
|
||||
fi
|
||||
git_dirs+=("$display_name")
|
||||
# 存储完整映射信息,稍后使用
|
||||
all_mappings+=("$git_url|$branch|$sync_dir|$git_dir|$alias")
|
||||
fi
|
||||
done
|
||||
|
||||
# 默认全选
|
||||
for i in "${!git_dirs[@]}"; do
|
||||
selected_indices+=($i)
|
||||
done
|
||||
|
||||
local cursor_index=0
|
||||
local max_index=$((${#git_dirs[@]}-1))
|
||||
|
||||
# 设置当前步骤
|
||||
CURRENT_STEP=2
|
||||
|
||||
# 主循环 - 处理用户输入并更新选择
|
||||
while true; do
|
||||
# 显示步骤状态
|
||||
show_steps
|
||||
|
||||
# 显示菜单标题
|
||||
printf "%s%s选择目标 Git 仓库%s\n\n" "${BOLD}" "${CYAN}" "${NC}"
|
||||
|
||||
# 显示Git仓库列表
|
||||
for i in "${!git_dirs[@]}"; do
|
||||
# 检查当前索引是否已在选中列表中
|
||||
local is_selected=false
|
||||
for idx in "${selected_indices[@]}"; do
|
||||
if [[ $i -eq $idx ]]; then
|
||||
is_selected=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $i -eq $cursor_index ]]; then
|
||||
# 当前光标位置项
|
||||
if [[ "$is_selected" == "true" ]]; then
|
||||
# 选中项
|
||||
printf "%s%s❯ %s[✓] %s%s\n" \
|
||||
"${BOLD}" "${CYAN}" "${GREEN}" "${git_dirs[$i]}" "${NC}"
|
||||
else
|
||||
# 未选中项
|
||||
printf "%s%s❯ %s[ ] %s%s\n" \
|
||||
"${BOLD}" "${CYAN}" "${DIM}" "${git_dirs[$i]}" "${NC}"
|
||||
fi
|
||||
else
|
||||
# 非光标位置项
|
||||
if [[ "$is_selected" == "true" ]]; then
|
||||
# 选中项
|
||||
printf " %s[✓] %s%s\n" \
|
||||
"${GREEN}" "${git_dirs[$i]}" "${NC}"
|
||||
else
|
||||
# 未选中项
|
||||
printf " %s[ ] %s%s\n" \
|
||||
"${DIM}" "${git_dirs[$i]}" "${NC}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# 显示操作提示
|
||||
printf "\n%s%s使用上下箭头选择,数字键1选中/0取消,回车确认,q键退出%s\n" \
|
||||
"${BOLD}" "${CYAN}" "${NC}"
|
||||
|
||||
# 读取用户输入 - 统一处理方式
|
||||
local key_pressed=""
|
||||
local key
|
||||
read -r -n 1 key
|
||||
|
||||
# 获取ASCII码用于调试
|
||||
if [[ -z "$key" ]]; then
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "空字符,可能是回车键\n"
|
||||
key_pressed="ENTER" # 空字符通常是回车键
|
||||
elif [[ "$key" == "1" ]]; then
|
||||
printf "检测到数字键1,执行选中操作\n" # 始终输出,不依赖DEBUG_MODE
|
||||
key_pressed="SELECT" # 选中
|
||||
elif [[ "$key" == "0" ]]; then
|
||||
printf "检测到数字键0,执行取消选中操作\n" # 始终输出,不依赖DEBUG_MODE
|
||||
key_pressed="DESELECT" # 取消选中
|
||||
else
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "按键ASCII码: %d\n" "'$key"
|
||||
|
||||
# 处理其他按键
|
||||
case "$key" in
|
||||
$'\x1b') # ESC 序列,包括方向键
|
||||
read -r -n 2 seq
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "ESC序列: %s\n" "$seq"
|
||||
case "$seq" in
|
||||
"[A") key_pressed="UP" ;; # 上箭头
|
||||
"[B") key_pressed="DOWN" ;; # 下箭头
|
||||
*) key_pressed="ESC" ;; # 其他ESC序列
|
||||
esac
|
||||
;;
|
||||
"q"|"Q") # q键退出
|
||||
key_pressed="QUIT"
|
||||
;;
|
||||
*) # 其他按键忽略
|
||||
key_pressed="OTHER"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# 调试信息
|
||||
[[ "$DEBUG_MODE" == "true" ]] && log_debug "按键被解析为: $key_pressed"
|
||||
|
||||
# 处理操作
|
||||
case "$key_pressed" in
|
||||
"UP") # 上箭头
|
||||
if [[ $cursor_index -gt 0 ]]; then
|
||||
cursor_index=$((cursor_index-1))
|
||||
else
|
||||
# 如果已经是第一项,跳到最后一项
|
||||
cursor_index=$max_index
|
||||
fi
|
||||
;;
|
||||
"DOWN") # 下箭头
|
||||
if [[ $cursor_index -lt $max_index ]]; then
|
||||
cursor_index=$((cursor_index+1))
|
||||
else
|
||||
# 如果已经是最后一项,回到第一项
|
||||
cursor_index=0
|
||||
fi
|
||||
;;
|
||||
"SELECT") # 数字键1 - 选中当前项
|
||||
printf "处理SELECT操作 - 选中当前项: ${cursor_index}\n"
|
||||
# 检查当前索引是否已在选中列表中
|
||||
local found=false
|
||||
for idx in "${selected_indices[@]}"; do
|
||||
if [[ $idx -eq $cursor_index ]]; then
|
||||
found=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# 如果未选中,则添加到选中列表
|
||||
if [[ "$found" == "false" ]]; then
|
||||
selected_indices+=($cursor_index)
|
||||
printf "已添加索引 ${cursor_index} 到选中列表\n"
|
||||
# 对选中项排序
|
||||
if [[ ${#selected_indices[@]} -gt 0 ]]; then
|
||||
IFS=$'\n'
|
||||
selected_indices=($(sort -n <<<"${selected_indices[*]}"))
|
||||
unset IFS
|
||||
fi
|
||||
else
|
||||
printf "索引 ${cursor_index} 已在选中列表中\n"
|
||||
fi
|
||||
;;
|
||||
"DESELECT") # 数字键0 - 取消选中当前项
|
||||
printf "处理DESELECT操作 - 取消选中当前项: ${cursor_index}\n"
|
||||
# 检查当前索引是否已在选中列表中
|
||||
local found=false
|
||||
local new_indices=()
|
||||
|
||||
# 创建新数组,排除当前索引
|
||||
for idx in "${selected_indices[@]}"; do
|
||||
if [[ $idx -ne $cursor_index ]]; then
|
||||
new_indices+=($idx)
|
||||
else
|
||||
found=true # 标记找到了要删除的索引
|
||||
fi
|
||||
done
|
||||
|
||||
# 只有在找到并删除了索引的情况下才更新选中列表
|
||||
if [[ "$found" == "true" ]]; then
|
||||
selected_indices=("${new_indices[@]}")
|
||||
printf "已从选中列表中移除索引 ${cursor_index}\n"
|
||||
else
|
||||
printf "索引 ${cursor_index} 不在选中列表中\n"
|
||||
fi
|
||||
;;
|
||||
"ENTER") # 回车 - 确认选择
|
||||
if [[ ${#selected_indices[@]} -eq 0 ]]; then
|
||||
log_error "请至少选择一个 Git 仓库"
|
||||
sleep 2 # 暂停显示错误信息
|
||||
continue
|
||||
fi
|
||||
|
||||
# 根据选中的索引获取对应的映射信息
|
||||
SYNC_MAPPINGS=()
|
||||
for idx in "${selected_indices[@]}"; do
|
||||
SYNC_MAPPINGS+=("${all_mappings[$idx]}")
|
||||
done
|
||||
|
||||
# 更新步骤状态
|
||||
STEP_GIT_REPOS="${#selected_indices[@]} 个仓库"
|
||||
CURRENT_STEP=3
|
||||
|
||||
return 0
|
||||
;;
|
||||
"QUIT") # 退出
|
||||
log_error "操作已取消"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# 读取工作区配置
|
||||
read_workspace_config() {
|
||||
local workspace="$1"
|
||||
|
||||
if ! command -v yq &> /dev/null; then
|
||||
log_warn "未安装 yq,将使用默认配置"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 使用 yq 解析 YAML
|
||||
local mappings
|
||||
mappings=$(yq e ".workspaces.$workspace.sync_mappings" "$SYNC_CONFIG_FILE")
|
||||
if [[ "$mappings" != "null" ]]; then
|
||||
# 解析每个映射
|
||||
local count
|
||||
count=$(yq e ".workspaces.$workspace.sync_mappings | length" "$SYNC_CONFIG_FILE")
|
||||
for ((i=0; i<count; i++)); do
|
||||
local git_url
|
||||
local branch
|
||||
local sync_dir
|
||||
local git_dir
|
||||
local alias
|
||||
|
||||
git_url=$(yq e ".workspaces.$workspace.sync_mappings[$i].source.git_url" "$SYNC_CONFIG_FILE")
|
||||
branch=$(yq e ".workspaces.$workspace.sync_mappings[$i].source.branch" "$SYNC_CONFIG_FILE")
|
||||
sync_dir=$(yq e ".workspaces.$workspace.sync_mappings[$i].target.sync_dir" "$SYNC_CONFIG_FILE")
|
||||
git_dir=$(yq e ".workspaces.$workspace.sync_mappings[$i].target.git_dir" "$SYNC_CONFIG_FILE")
|
||||
alias=$(yq e ".workspaces.$workspace.sync_mappings[$i].source.alias" "$SYNC_CONFIG_FILE")
|
||||
|
||||
if [[ -n "$git_url" && -n "$sync_dir" ]]; then
|
||||
# 存储映射信息,添加别名
|
||||
SYNC_MAPPINGS+=("$git_url|$branch|$sync_dir|$git_dir|$alias")
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# 更新工作区配置
|
||||
update_workspace_config() {
|
||||
local workspace="$1"
|
||||
|
||||
if ! command -v yq &> /dev/null; then
|
||||
log_warn "未安装 yq,无法更新配置"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 创建备份
|
||||
if [[ -f "$SYNC_CONFIG_FILE" ]]; then
|
||||
cp "$SYNC_CONFIG_FILE" "${SYNC_CONFIG_FILE}.bak"
|
||||
fi
|
||||
|
||||
# 清空现有映射
|
||||
yq e -i ".workspaces.$workspace.sync_mappings = []" "$SYNC_CONFIG_FILE"
|
||||
|
||||
# 添加新的映射
|
||||
for mapping in "${SYNC_MAPPINGS[@]}"; do
|
||||
IFS='|' read -r git_url branch sync_dir git_dir alias <<< "$mapping"
|
||||
yq e -i ".workspaces.$workspace.sync_mappings += [{\"source\": {\"git_url\": \"$git_url\", \"branch\": \"$branch\", \"alias\": \"$alias\"}, \"target\": {\"sync_dir\": \"$sync_dir\", \"git_dir\": \"$git_dir\"}}]" "$SYNC_CONFIG_FILE"
|
||||
done
|
||||
|
||||
# 删除备份
|
||||
rm -f "${SYNC_CONFIG_FILE}.bak"
|
||||
log_info "工作区配置已更新"
|
||||
return 0
|
||||
}
|
||||
|
||||
# 读取配置
|
||||
read_config() {
|
||||
if [[ -z "$SYNC_CONFIG_FILE" ]]; then
|
||||
log_error "配置文件未初始化,请确保已找到项目根目录"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -f "$SYNC_CONFIG_FILE" ]]; then
|
||||
# 使用 yq 解析 YAML(如果安装了的话)
|
||||
if command -v yq &> /dev/null; then
|
||||
SELECTED_WORKSPACE=$(yq e '.config.workspace' "$SYNC_CONFIG_FILE")
|
||||
TARGET_GIT_DIR=$(yq e '.config.target_git_dir' "$SYNC_CONFIG_FILE")
|
||||
BRANCH=$(yq e '.config.branch' "$SYNC_CONFIG_FILE")
|
||||
SYNC_STRUCTURE=$(yq e '.config.sync_structure' "$SYNC_CONFIG_FILE")
|
||||
PARALLEL_BUILD=$(yq e '.config.parallel_build' "$SYNC_CONFIG_FILE")
|
||||
DRY_RUN=$(yq e '.config.dry_run' "$SYNC_CONFIG_FILE")
|
||||
else
|
||||
log_warn "未安装 yq,将使用默认配置"
|
||||
fi
|
||||
else
|
||||
log_error "配置文件不存在: $SYNC_CONFIG_FILE"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 保存配置
|
||||
save_config() {
|
||||
if [[ -z "$SYNC_CONFIG_FILE" ]]; then
|
||||
log_error "配置文件未初始化,请确保已找到项目根目录"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! command -v yq &> /dev/null; then
|
||||
log_warn "未安装 yq,无法保存配置"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 创建备份
|
||||
if [[ -f "$SYNC_CONFIG_FILE" ]]; then
|
||||
cp "$SYNC_CONFIG_FILE" "${SYNC_CONFIG_FILE}.bak"
|
||||
fi
|
||||
|
||||
# 保存配置
|
||||
if ! yq e -i ".config.workspace = \"$SELECTED_WORKSPACE\"" "$SYNC_CONFIG_FILE" \
|
||||
&& yq e -i ".config.target_git_dir = \"$TARGET_GIT_DIR\"" "$SYNC_CONFIG_FILE" \
|
||||
&& yq e -i ".config.branch = \"$BRANCH\"" "$SYNC_CONFIG_FILE" \
|
||||
&& yq e -i ".config.sync_structure = $SYNC_STRUCTURE" "$SYNC_CONFIG_FILE" \
|
||||
&& yq e -i ".config.parallel_build = $PARALLEL_BUILD" "$SYNC_CONFIG_FILE" \
|
||||
&& yq e -i ".config.dry_run = $DRY_RUN" "$SYNC_CONFIG_FILE"; then
|
||||
log_error "保存配置失败"
|
||||
# 恢复备份
|
||||
if [[ -f "${SYNC_CONFIG_FILE}.bak" ]]; then
|
||||
mv "${SYNC_CONFIG_FILE}.bak" "$SYNC_CONFIG_FILE"
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 删除备份
|
||||
rm -f "${SYNC_CONFIG_FILE}.bak"
|
||||
log_info "配置已保存"
|
||||
return 0
|
||||
}
|
||||
|
||||
# 导出函数
|
||||
export -f prepare_git_repo
|
||||
export -f get_source_commit_info
|
||||
export -f commit_changes
|
||||
export -f push_changes
|
||||
export -f select_git_dirs
|
||||
export -f read_workspace_config
|
||||
export -f update_workspace_config
|
||||
export -f read_config
|
||||
export -f save_config
|
||||
306
frontend/scripts/temp/sync-project.sh
Normal file
306
frontend/scripts/temp/sync-project.sh
Normal file
@@ -0,0 +1,306 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===================================================
|
||||
# 项目同步脚本 - sync-project.sh
|
||||
# 用于同步 Turborepo 项目工作区的编译结果到 Git 仓库
|
||||
# ===================================================
|
||||
|
||||
# 脚本目录
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# 全局变量
|
||||
PROJECT_ROOT="" # 项目根目录
|
||||
SELECTED_WORKSPACE="" # 选中的工作区
|
||||
PARALLEL_BUILD=false # 是否并行编译
|
||||
DRY_RUN=false # 是否干运行
|
||||
OS="" # 操作系统类型
|
||||
DEBUG_MODE=false # 调试模式
|
||||
|
||||
# 相关文件和目录变量(初始化为空,后续赋值)
|
||||
SYNC_DIR="" # 同步配置目录
|
||||
GIT_DIR="" # Git 仓库目录
|
||||
SYNC_CONFIG_FILE="" # 同步配置文件
|
||||
HISTORY_FILE="" # 历史记录文件
|
||||
PLUGINS_DIR="" # 插件目录
|
||||
WORKSPACE_CONFIG_DIR="" # 工作区配置目录
|
||||
|
||||
# 步骤状态变量
|
||||
CURRENT_STEP=1
|
||||
STEP_WORKSPACE=""
|
||||
STEP_GIT_REPOS=""
|
||||
STEP_SYNC_MODE=""
|
||||
|
||||
# 操作历史相关
|
||||
MAX_HISTORY=10
|
||||
|
||||
# 加载拆分后的脚本
|
||||
source "$SCRIPT_DIR/file-operations.sh"
|
||||
source "$SCRIPT_DIR/git-operations.sh"
|
||||
source "$SCRIPT_DIR/build-operations.sh"
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
# 检查参数
|
||||
if [[ $# -gt 0 ]]; then
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" == "--help" || "$arg" == "-h" ]]; then
|
||||
show_help
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# 初始化
|
||||
detect_os
|
||||
check_dependencies # 检查依赖,包括 yq
|
||||
|
||||
# 首先查找项目根目录
|
||||
find_project_root || exit 1
|
||||
|
||||
# 初始化同步目录结构
|
||||
init_sync_dirs || exit 1
|
||||
|
||||
# 在找到项目根目录后,初始化插件系统
|
||||
init_plugins
|
||||
load_plugins
|
||||
|
||||
# 读取配置
|
||||
read_config
|
||||
|
||||
# 解析命令行参数
|
||||
parse_args "$@"
|
||||
|
||||
# 运行前置钩子
|
||||
run_hook "pre_main"
|
||||
|
||||
# 如果是干运行模式,只显示将要执行的操作
|
||||
if [[ "$DRY_RUN" == "true" ]]; then
|
||||
log_info "干运行模式 - 将显示将要执行的操作"
|
||||
log_info "工作区: $SELECTED_WORKSPACE"
|
||||
log_info "并行编译: $PARALLEL_BUILD"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 解析工作区(如果未通过参数指定)
|
||||
if [[ -z "$SELECTED_WORKSPACE" ]]; then
|
||||
parse_workspaces || {
|
||||
log_error "工作区选择失败"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# 验证工作区是否有效
|
||||
if [[ -z "$SELECTED_WORKSPACE" ]]; then
|
||||
log_error "未选择有效的工作区"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 验证工作区目录是否存在
|
||||
if [[ ! -d "$PROJECT_ROOT/apps/$SELECTED_WORKSPACE" ]]; then
|
||||
log_error "工作区目录不存在: $PROJECT_ROOT/apps/$SELECTED_WORKSPACE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "当前选择的工作区: $SELECTED_WORKSPACE"
|
||||
|
||||
# 编译工作区
|
||||
build_workspace || {
|
||||
log_error "编译失败"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 检查编译结果
|
||||
check_build_result || {
|
||||
log_error "编译结果检查失败"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 选择 Git 项目目录
|
||||
select_git_dirs || {
|
||||
log_error "Git 仓库选择失败"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 询问是否同步源码
|
||||
show_title "同步选项"
|
||||
printf "%s%s%s\n" "${DIM}" "选择要执行的操作" "${NC}"
|
||||
show_separator
|
||||
|
||||
local sync_options=(
|
||||
"仅同步编译结果"
|
||||
"同步编译结果和源码"
|
||||
)
|
||||
|
||||
local selected_index=0
|
||||
local max_index=$((${#sync_options[@]}-1))
|
||||
local padding=2
|
||||
|
||||
# 设置当前步骤
|
||||
CURRENT_STEP=3
|
||||
|
||||
while true; do
|
||||
# 显示步骤状态
|
||||
show_steps
|
||||
|
||||
# 显示选项列表标题
|
||||
printf "%s%s选择同步方式%s\n\n" "${BOLD}" "${CYAN}" "${NC}"
|
||||
|
||||
# 显示同步选项
|
||||
for i in "${!sync_options[@]}"; do
|
||||
if [[ $i -eq $selected_index ]]; then
|
||||
printf "%s%s❯ %s%s\n" \
|
||||
"${BOLD}" "${GREEN}" "${sync_options[$i]}" "${NC}"
|
||||
else
|
||||
printf " %s%s%s\n" \
|
||||
"${DIM}" "${sync_options[$i]}" "${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
# 显示操作提示
|
||||
printf "\n%s%s使用上下箭头选择,回车确认,q键退出%s\n" \
|
||||
"${BOLD}" "${CYAN}" "${NC}"
|
||||
|
||||
# 读取用户输入 - 统一处理方式
|
||||
local key_pressed=""
|
||||
local key
|
||||
read -r -n 1 key
|
||||
|
||||
# 获取ASCII码用于调试
|
||||
if [[ -z "$key" ]]; then
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "空字符,可能是回车键\n"
|
||||
key_pressed="ENTER" # 空字符通常是回车键
|
||||
else
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "按键ASCII码: %d\n" "'$key"
|
||||
|
||||
# 处理其他按键
|
||||
case "$key" in
|
||||
$'\x1b') # ESC 序列,包括方向键
|
||||
read -r -n 2 seq
|
||||
[[ "$DEBUG_MODE" == "true" ]] && printf "ESC序列: %s\n" "$seq"
|
||||
case "$seq" in
|
||||
"[A") key_pressed="UP" ;; # 上箭头
|
||||
"[B") key_pressed="DOWN" ;; # 下箭头
|
||||
*) key_pressed="ESC" ;; # 其他ESC序列
|
||||
esac
|
||||
;;
|
||||
"q"|"Q") # q键退出
|
||||
key_pressed="QUIT"
|
||||
;;
|
||||
"") # 回车键
|
||||
key_pressed="ENTER"
|
||||
;;
|
||||
*) # 其他按键
|
||||
key_pressed="OTHER"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# 调试信息
|
||||
[[ "$DEBUG_MODE" == "true" ]] && log_debug "按键被解析为: $key_pressed"
|
||||
|
||||
# 处理操作
|
||||
case "$key_pressed" in
|
||||
"UP") # 上箭头
|
||||
if [[ $selected_index -gt 0 ]]; then
|
||||
selected_index=$((selected_index-1))
|
||||
else
|
||||
# 如果已经是第一项,跳到最后一项
|
||||
selected_index=$max_index
|
||||
fi
|
||||
;;
|
||||
"DOWN") # 下箭头
|
||||
if [[ $selected_index -lt $max_index ]]; then
|
||||
selected_index=$((selected_index+1))
|
||||
else
|
||||
# 如果已经是最后一项,回到第一项
|
||||
selected_index=0
|
||||
fi
|
||||
;;
|
||||
"ENTER") # 回车
|
||||
case $selected_index in
|
||||
0) # 仅同步编译结果
|
||||
STEP_SYNC_MODE="仅同步编译结果"
|
||||
CURRENT_STEP=4
|
||||
sync_files || {
|
||||
log_error "同步编译结果失败"
|
||||
exit 1
|
||||
}
|
||||
;;
|
||||
1) # 同步编译结果和源码
|
||||
STEP_SYNC_MODE="同步编译结果和源码"
|
||||
CURRENT_STEP=4
|
||||
sync_files || {
|
||||
log_error "同步编译结果失败"
|
||||
exit 1
|
||||
}
|
||||
sync_source_code || {
|
||||
log_error "同步源码失败"
|
||||
exit 1
|
||||
}
|
||||
;;
|
||||
esac
|
||||
break
|
||||
;;
|
||||
"QUIT") # 退出
|
||||
log_error "操作已取消"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# 运行工作区选择后钩子
|
||||
run_hook "post_workspace_select" "$SELECTED_WORKSPACE"
|
||||
|
||||
# 设置当前步骤
|
||||
CURRENT_STEP=4
|
||||
|
||||
# 显示当前步骤
|
||||
show_steps
|
||||
printf "%s%s正在执行同步操作,请稍候...%s\n\n" "${BOLD}" "${CYAN}" "${NC}"
|
||||
|
||||
# 准备 Git 仓库
|
||||
for mapping in "${SYNC_MAPPINGS[@]}"; do
|
||||
IFS='|' read -r git_url branch sync_dir git_dir alias <<< "$mapping"
|
||||
prepare_git_repo "$git_url" "$branch" "$alias" || {
|
||||
log_error "准备 Git 仓库失败"
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
# 提交和推送
|
||||
for mapping in "${SYNC_MAPPINGS[@]}"; do
|
||||
IFS='|' read -r git_url branch sync_dir git_dir alias <<< "$mapping"
|
||||
local repo_dir="$GIT_DIR/${alias:-$(basename "$git_url" .git)}"
|
||||
cd "$repo_dir" || {
|
||||
log_error "无法切换到 Git 仓库目录"
|
||||
exit 1
|
||||
}
|
||||
|
||||
commit_changes || {
|
||||
log_error "提交更改失败"
|
||||
exit 1
|
||||
}
|
||||
|
||||
push_changes || {
|
||||
log_error "推送更改失败"
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
# 保存配置
|
||||
save_config || log_warn "保存配置失败,但操作已完成"
|
||||
|
||||
# 记录操作历史
|
||||
record_history "同步工作区 $SELECTED_WORKSPACE"
|
||||
|
||||
# 运行完成钩子
|
||||
run_hook "post_main"
|
||||
|
||||
# 设置最后步骤状态,显示完成
|
||||
CURRENT_STEP=5
|
||||
show_steps
|
||||
printf "%s%s所有操作已完成!%s\n" "${BOLD}" "${GREEN}" "${NC}"
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user