243 lines
6.6 KiB
Bash
243 lines
6.6 KiB
Bash
#!/bin/bash
|
|
|
|
# 配置文件
|
|
CONFIG_FILE="submodule_config.ini"
|
|
|
|
# 定义颜色常量
|
|
RED='\033[31mi'
|
|
BLUE='\033[34m'
|
|
YELLOW='\033[33m'
|
|
GREEN='\033[32m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# 函数:显示帮助信息
|
|
show_help() {
|
|
echo "Usage: $0 [-h] [-i] [-up]"
|
|
echo " -h 显示帮助信息"
|
|
echo " -i 根据.gitmodules初始化子模块"
|
|
echo " -up 根据配置文件更新子模块"
|
|
}
|
|
|
|
# 检查配置文件是否存在
|
|
if [[ ! -f "$CONFIG_FILE" ]]; then
|
|
echo -e "${RED}配置文件 $CONFIG_FILE 不存在!${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
# 检查 .gitmodules 文件是否存在
|
|
if [[ ! -f ".gitmodules" ]]; then
|
|
touch .gitmodules
|
|
fi
|
|
|
|
# 普通数组和模拟的关联数组
|
|
module_list=() # 用来存储模块名列表
|
|
config_array=() # 用来存储键值对
|
|
|
|
# 函数:从 INI 文件中读取所有字段并存储在普通数组中
|
|
parse_ini_all() {
|
|
local section=""
|
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
# 去除前后空格
|
|
line="${line#"${line%%[![:space:]]*}"}" # 去掉前面的空格
|
|
line="${line%"${line##*[![:space:]]}"}" # 去掉后面的空格
|
|
|
|
# 跳过注释和空行
|
|
[[ "$line" =~ ^\s*(#|$) ]] && continue
|
|
|
|
# 如果是新的 section
|
|
if [[ "$line" =~ ^\[(.*)\]$ ]]; then
|
|
section="${BASH_REMATCH[1]}"
|
|
module_list+=("$section") # 添加 module 名到 module_list 数组中
|
|
elif [[ "$line" =~ ^([^=]+)=(.*)$ ]]; then
|
|
key="${BASH_REMATCH[1]//[[:space:]]/}" # 去掉键的空格
|
|
value="${BASH_REMATCH[2]//[[:space:]]/}" # 去掉值的空格
|
|
|
|
# 构造键值对并存储在数组中
|
|
config_array+=("$section.$key=$value")
|
|
fi
|
|
done < "$CONFIG_FILE"
|
|
}
|
|
|
|
# 函数:根据键获取值
|
|
get_value() {
|
|
local key=$1
|
|
for entry in "${config_array[@]}"; do
|
|
if [[ "$entry" == "$key="* ]]; then
|
|
echo "${entry#*=}" # 输出值
|
|
return
|
|
fi
|
|
done
|
|
echo ""
|
|
}
|
|
|
|
# 函数:检查远程仓库是否包含指定版本标签
|
|
check_tag_exists() {
|
|
local repo_url=$1
|
|
local version_tag=$2
|
|
|
|
git ls-remote --tags "$repo_url" | grep -q "refs/tags/$version_tag"
|
|
if [[ $? -ne 0 ]]; then
|
|
echo -e "${RED}仓库: $repo_url 版本标签 $version_tag 不存在!${NC}"
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# 函数:获取当前子模块的版本标签
|
|
get_current_version() {
|
|
local target_dir=$1
|
|
cd "$target_dir" || return 1
|
|
|
|
# 尝试获取当前HEAD指向的标签名
|
|
current_version=$(git tag --points-at HEAD)
|
|
|
|
# 如果没有标签名,则返回commit的SHA
|
|
if [[ -z "$current_version" ]]; then
|
|
current_version=$(git rev-parse HEAD)
|
|
fi
|
|
|
|
cd - > /dev/null || return 1
|
|
echo "$current_version"
|
|
}
|
|
|
|
# 函数:初始化子模块
|
|
init_submodule() {
|
|
local module=$1
|
|
local repo_url=$2
|
|
local target_dir=$3
|
|
local version_tag=$4
|
|
|
|
# 检查子模块路径是否已经存在
|
|
if [[ -f "$target_dir/.git" ]]; then
|
|
# 存在子模块,获取当前版本
|
|
current_version=$(get_current_version "$target_dir")
|
|
|
|
# 如果当前版本和目标版本相同,直接返回
|
|
if [[ "$current_version" == "$version_tag" ]]; then
|
|
echo -e "${GREEN}子模块: $module 已经是版本: $version_tag 无需更新${NC}"
|
|
return 0
|
|
else
|
|
if ! check_tag_exists "$repo_url" "$version_tag"; then
|
|
return 1
|
|
fi
|
|
fi
|
|
else
|
|
# 子模块不存在,检查远程版本标签
|
|
echo -e "${YELLOW}子模块: $module 不存在,添加子模块...${NC}"
|
|
if ! check_tag_exists "$repo_url" "$version_tag"; then
|
|
return 1
|
|
fi
|
|
|
|
# 添加子模块
|
|
git submodule add --force "$repo_url" "$target_dir"
|
|
if [[ $? -ne 0 ]]; then
|
|
echo -e "${RED}子模块: $module($target_dir) 添加失败!${NC}"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# 子模块已存在或成功添加,尝试切换到指定版本
|
|
cd "$target_dir" || return 1
|
|
echo "子模块: $module 切换到版本: $version_tag"
|
|
|
|
# 更新标签并切换到指定的版本标签
|
|
git fetch --tags > /dev/null 2>&1
|
|
git checkout "tags/$version_tag" > /dev/null 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo -e "${RED}$module 版本切换失败: $version_tag${NC}"
|
|
cd - > /dev/null || return 1
|
|
return 1
|
|
fi
|
|
|
|
cd - > /dev/null || return 1
|
|
echo -e "${GREEN}子模块: $module($target_dir) 初始化完成,版本: $version_tag\n${NC}"
|
|
return 0
|
|
}
|
|
|
|
# 函数:删除配置文件中已经不存在的子模块
|
|
remove_deleted_submodules() {
|
|
# 获取当前子模块列表
|
|
current_submodules=$(git config --file .gitmodules --name-only --get-regexp path | sed 's/^submodule\.//;s/\.path$//')
|
|
|
|
for submodule in $current_submodules; do
|
|
# 获取当前子模块的路径
|
|
submodule_path=$(git config --file .gitmodules --get submodule."$submodule".path)
|
|
|
|
# 标志:是否在配置文件中找到该子模块
|
|
found_in_config=false
|
|
|
|
# 遍历配置文件中的模块,检查是否存在
|
|
for module in "${module_list[@]}"; do
|
|
if [[ "$submodule_path" == "$(get_value "$module.target_dir")" ]]; then
|
|
found_in_config=true
|
|
break
|
|
fi
|
|
done
|
|
|
|
# 如果在配置文件中没有找到子模块,则删除它
|
|
if [[ "$found_in_config" == false ]]; then
|
|
echo -e "${YELLOW}子模块: $submodule_path 已从配置文件中删除,正在删除...${NC}"
|
|
git submodule deinit -f "$submodule_path" > /dev/null 2>&1
|
|
git rm -f "$submodule_path" > /dev/null 2>&1
|
|
rm -rf .git/modules/"$submodule_path"
|
|
echo -e "${GREEN}子模块: $submodule_path 已成功删除!${NC}"
|
|
fi
|
|
done
|
|
}
|
|
|
|
update_submodule(){
|
|
# 调用 parse_ini_all 函数,读取所有配置
|
|
parse_ini_all
|
|
|
|
# 调用删除函数,清理已删除的子模块
|
|
remove_deleted_submodules
|
|
|
|
# 遍历所有模块的 section
|
|
for module in "${module_list[@]}"; do
|
|
repo_url=$(get_value "$module.repo_url")
|
|
target_dir=$(get_value "$module.target_dir")
|
|
version_tag=$(get_value "$module.version_tag")
|
|
|
|
if [[ -z "$repo_url" || -z "$target_dir" || -z "$version_tag" ]]; then
|
|
echo -e "${YELLOW}跳过无效配置:$module${NC}"
|
|
continue
|
|
fi
|
|
|
|
init_submodule "$module" "$repo_url" "$target_dir" "$version_tag"
|
|
if [[ $? -ne 0 ]]; then
|
|
echo -e "${RED}子模块 $target_dir 初始化失败,退出...${NC}"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
echo -e "${GREEN}所有子模块已成功同步到指定版本!${NC}"
|
|
}
|
|
|
|
# 解析脚本参数
|
|
case "$1" in
|
|
-h )
|
|
show_help
|
|
exit 0
|
|
;;
|
|
-i )
|
|
echo -e "${BLUE}根据.gitmodules初始化子模块...${NC}"
|
|
|
|
git submodule update --init --recursive
|
|
|
|
git submodule status
|
|
echo -e "${GREEN}初始化子模块成功!${NC}"
|
|
exit 0
|
|
;;
|
|
-up )
|
|
echo -e "${BLUE}根据配置文件更新子模块...${NC}"
|
|
|
|
update_submodule
|
|
|
|
exit 0
|
|
;;
|
|
* )
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|