背景
java依赖包工程每次打包都需要半小时左右,但每次开发只修改里面的几个小模块,需要实现只编译变更模块的功能,来提升编译的效率。
设计思路
根据git pull的输出来获取变更文件的绝对路径,通过mvn validate获取所有子模块的编译顺序,查找有变更文件的子模块,并执行mvn deploy
流程图
mvn_module.sh
#!/bin/bash
# vim:sw=4:ts=4:et
<<INFO
AUTHOR:运维@小兵
DATE:2022-04-30
DESCRIBE:mvn根据git变更文件编译子模块
SYSTEM:CentOS 7.6.1810
WARNING:警告信息
MODIFY:
INFO
set -e
[[ $# -ne 2 ]] && echo "ERROR:Invalid Param!!!,Please Excute:bash $0 java的git工程路径 java父工程目录" && exit 1
#检查环境
Check_Env() {
if ! command -v mvn &> /dev/null;then
echo "ERROR:mvn Command Not Found" && exit 1
fi
}
#编译命令
Mvn_Build_Cmd() {
set -e
local mvn_project=$1
echo "[INFO] Begin Mvn ${mvn_project}..."
mvn -q clean deploy -Dmaven.test.skip=true
echo "[INFO] Mvn ${mvn_project} Success"
set +e
}
#根据git变更文件编译子模块
Mvn_Child_Module() {
local project_dir=$1 #git工程路径,如${WORKSPACE}/java_code
local mvn_dir=$2 #java父工程目录,如demo
[[ ! -d ${project_dir}/${mvn_dir} ]] && echo "[ERROR] ${project_dir} Not Found" && return
cd ${project_dir}/${mvn_dir}
if [[ -f git_pull.log ]];then
if [[ ${mvn_dir} != "platform" ]];then
git pull &> git_pull.log
fi
#处理长路径的情况,如.../java/com/epoch/entmall/common/annotation/MallListenerClass.java
sed -n '/^Fast-forward/,$p' git_pull.log | egrep '^ \.{3}/' | egrep '[\+-]+$' | awk '{print $1}' | uniq > simple_file.txt #存放长路径文件
#通过文件名获取完整的文件路径
if [[ -s simple_file.txt ]];then
local file_path=""
while read line
do
file_name=$(echo ${line##*/}) #获取文件名
[[ -z ${file_name} ]] && echo "[ERROR] ${line} Is Bad Format" && exit 1
for file_path in $(find ./ -name "${file_name}" -type f)
do
echo "${file_path}" >> update_file.txt #存放git变更文件路径,如./com.epoch.autoregister/t.txt
done
done < simple_file.txt
fi
sed -ri '/^ \.{3}\//d' git_pull.log
sed -n '/^Fast-forward/,$p' git_pull.log | egrep '^ (create|delete)' | awk '{print $4}' | grep "^${mvn_dir}/" | uniq > tmp.txt
sed -n '/^Fast-forward/,$p' git_pull.log | egrep '[\+-]+$' | awk '{print $1}' | grep "^${mvn_dir}/" | uniq >> tmp.txt
sed -n '/^Fast-forward/,$p' git_pull.log | grep '^ rename' | awk -F'[ {]' '{print $3}' | grep "^${mvn_dir}/" | uniq >> tmp.txt
sed -i "s|${mvn_dir}/|\./|" tmp.txt
sort -rn tmp.txt | uniq >> update_file.txt #存放git变更文件路径
rm -f tmp.txt
cat update_file.txt | sort -u -o update_file.txt #去重
if [[ -s update_file.txt ]];then
mkdir -p update_logs #存放历史更新记录
cp update_file.txt update_logs/${TIME}_update_file.txt
#如果父目录下的pom.xml有更新,则全量编译
if grep "\./pom.xml" update_file.txt &> /dev/null;then
Mvn_Build_Cmd "${project_dir}/${mvn_dir}"
> update_file.txt
return
fi
#获取java工程所有模块编译顺序
mvn validate | egrep '(\[pom\]$|\[jar\]$)' | awk '{print $2}' > module_list.txt
#如果没有子模块,则全量编译
if [[ ! -s module_list.txt ]];then
Mvn_Build_Cmd "${project_dir}/${mvn_dir}"
> update_file.txt
return
fi
#遍历子模块,根据update_file.txt进行编译
local module_name=""
for module_name in $(cat module_list.txt)
do
cd ${project_dir}/${mvn_dir}
local path=$(egrep "(/${module_name}/($|pom.xml$|src/))" update_file.txt | sed -n '1p') #当前模块下变更文件路径
if [[ -z ${path} ]];then
echo "[INFO] ${module_name} Module Is Latest" #该模块不需要编译
continue
else
local module_path=$(find ./ -name "${module_name}" -type d)
if [[ -z ${module_path} ]];then
echo "[ERROR]:${module_name} Module Dir Is Error" && exit 1
else
cd ${module_path}
if [[ ! -f mvn_flag ]];then
Mvn_Build_Cmd ${module_path}
touch mvn_flag #表示该模块已编译,防止后面重复编译
else
echo "[INFO] ${module_name} Already mvn"
fi
#从update_file.txt删除已编译成功模块的变更记录
sed -ri "s#(.*)${module_name}/(.*)##g" ${project_dir}/${mvn_dir}/update_file.txt
sed -i '/^$/d' ${project_dir}/${mvn_dir}/update_file.txt
fi
fi
done #module_list.txt循环
find ${project_dir}/${mvn_dir}/ -name 'mvn_flag' -type f | xargs rm -f
echo "[INFO] mvn ${project_dir}/${mvn_dir} Success"
else
echo "[INFO] ${project_dir}/${mvn_dir} Not Update File"
fi
else
Mvn_Build_Cmd "${project_dir}/${mvn_dir}"
touch git_pull.log
fi
}
Check_Env
Mvn_Child_Module $@
执行脚本
bash mvn_module.sh ${WORKSPACE}/java_code demo