rpmbuild多进程批量编译脚本

脚本用法

使用手册

bash spec.sh --help
Please ensure the directory ~/rpmbuild exists, And the script can execute in any directory.Usage: bash spec.sh [OPTION]... [*.spec]... [OPTION]...or:  bash spec.sh [*.spec]... [OPTION]... [*.spec]...
rpmbuild all specfiles in the arguments, if it's empty, rpmbuild all specfiles in the SPECS directoryArguments description-f, --force         skip existence check, force rpmbuild--thread=NUM        set the maximum number of executing processes--result_fix=char   set the output result symbol-* or --*           support all options in the rpmbuild

强制编译

编译会存在已编译检查,脚本已编译检查只写了简易校验(无语法解析),校验准确度一般,校验不准确通过 -f 触发强制编译即可。

bash spec.sh SPECS/qt.spec -f

设置执行线程数量

修改脚本代码中默认值或通过命令行参数 --thread 动态修改。

bash spec.sh --thread=3

设置输出结果标记

修改脚本代码中默认值或通过命令行参数 --result_fix 动态修改。

bash spec.sh --result_fix=#

修改rpmbuild单位宏定义

按需增删。

编译日志文件

log_file: 每次执行编译日志;log_file_history: 所有历史执行编译日志。

编译成功二进制包保存目录

其它

脚本代码其余参数范围(4 - 65)行有兴趣按需调整。

脚本代码

#!/bin/bash
script_start_time=$(date +%s)# 日志文件
log_file=~/rpmbuild/compiled.log
log_file_history=~/rpmbuild/compiled.log.history
# 日志开关
log_switch=true
log_history_switch=true
# 执行最大进程数
thread_max_num=8
# 自定义宏,按公司需求定义
custom_define_arr=(--define='dist .test'--define='packager ****'--define='host ****'--define='vendor ****'--define='distribution ****'
)
# 编译完成rpm保存目录
success_dir=~/rpmbuild/success
# 编译完成rpm本地源目录
rpm_source=~/rpmbuild/RPMS/source
# dnf配置文件
dnf_config=/etc/dnf/dnf.conf
# rpmbuild参数
rpmbdf='-bb'
rpmbds=''
declare -a rpmbdo
# 管道文件绑定
lock_switch=false
lock_file=~/.spec.lock
lock_fd=''
builddep_lock_file=~/.builddep_spec.lock
builddep_lock_fd=''
global_lock_file=~/.global_spec.lock
global_lock_fd=''
# spec文件统计
declare -a arr
spec_count_file=~/.spec_count_file.log
spec_count=0
success_spec_count=0
already_spec_count=0
error_spec_count=0
missing_spec_count=0
declare -a success_spec_count_arr
declare -a already_spec_count_arr
declare -a error_spec_count_arr
declare -a missing_spec_count_arr
# 编译退出码
SUCCESS=1
ALREADY=2
MISSING=3
ERROR=4
SUCCESS_MESSAGE='编译成功'
ALREADY_MESSAGE='已编译'
MISSING_MESSAGE='缺少依赖'
ERROR_MESSAGE='编译失败'
# 输出结果
result_width=100
result_fix='='
result_prefix_num=10
result_postfix_num=15
# 输出结果顺序
result_sequence=("$SUCCESS" "$ERROR" "$MISSING" "$ALREADY")#------------------------------------------------function define start------------------------------------------------
# 使用手册
function manual() {echo "Please ensure the directory ~/rpmbuild exists, And the script can execute in any directory."echo -e "\nUsage: bash spec.sh [OPTION]... [*.spec]... [OPTION]..."echo "  or:  bash spec.sh [*.spec]... [OPTION]... [*.spec]..."echo "rpmbuild all specfiles in the arguments, if it's empty, rpmbuild all specfiles in the SPECS directory"echo -e "\nArguments description"echo "  -f, --force         skip existence check, force rpmbuild"echo "  --thread=NUM        set the maximum number of executing processes"echo "  --result_fix=char   set the output result symbol"echo "  -* or --*           support all options in the rpmbuild"
}# 命令行参数解析
function arr_spec_organize() {local ri=0local oi=0if [ $# -gt 0 ]; thenfor p in "$@"; docase $p in*.spec)arr[ri]=${p##*/}((ri++));;-b[a-z])rpmbdf=$p;;-f | --force)rpmbds=$p;;--help)manual && exit;;--thread=*)local _thread=${p##*=}if [[ $_thread =~ [0-9]+$ ]]; thenwhile [[ $_thread = [0]* ]]; do_thread=${_thread#*0}doneif [[ $_thread != '' && $_thread -gt 0 && $_thread -lt $thread_max_num ]]; thenthread_max_num=$_threadfifi;;--result_fix=*)local _symbol="${p#*=}"[[ $_symbol =~ ^.$ ]] && result_fix=$_symbol;;*)rpmbdo[oi]=$p((oi++));;esacdonefi# 命令行未传入spec文件则编译SPECS目录下所有spec文件if [ $ri -eq 0 ]; thenfor r in SPECS/*; dor=${r##*/}if [ "${r##*.}" = 'spec' ]; thenarr[ri]=$r((ri++))fidonefi
}# 自动判定锁
function decide_lock() {local _lockfd=$global_lock_fdif [[ -n "$2" ]]; then_lockfd=$2ficase "$1" in"lock")read -ru "$_lockfd";;"unlock")echo >&"$_lockfd";;esac
}# 加锁
function lock() {if $lock_switch; thendecide_lock "lock" "$1"fi
}# 解锁
function unlock() {if $lock_switch; thendecide_lock "unlock" "$1"fi
}# 已编译检查
function check_existence() {local name=''local version=''local _spec_detail=()while read -re line; doif [[ "$name" != '' && "$version" != '' ]]; thenbreakfiIFS=':' read -ra _spec_detail <<<"$line"if [ ${#_spec_detail[@]} -eq 2 ]; then_spec_detail[0]=${_spec_detail[0]//[ 	]/''}_spec_detail[1]=${_spec_detail[1]//[ 	]/''}if [[ ${_spec_detail[0]} = [nN][aA][mM][eE] ]]; thenname=${_spec_detail[1]}elif [[ ${_spec_detail[0]} = [vV][eE][rR][sS][iI][oO][nN] ]]; thenversion=${_spec_detail[1]}fifidone <"SPECS/$1"# version是宏暂不处理,存在版本号校验问题使用-f触发强制编译即可if [[ $version != [0-9]* ]]; thenversion=''fiif [[ "$name" != '' ]]; thenif [[ -n $(find ~/rpmbuild/RPMS -name "$name-$version*") || -n $(find ~/rpmbuild/RPMS -name "${name}[0-9]-$version*") ]]; thenreturn 0fifireturn 1
}# 编译执行
function exec_spec() {local src=$1# 查看是否已经编译完成 -> 源码编译不检查,强制编译不检查if [[ $rpmbdf != '-bs' && $rpmbds == '' ]] && check_existence "$src"; thenreturn $ALREADYfi# 加载rpm包所需依赖 -> 源码编译不加载if [[ $rpmbdf != '-bs' ]]; thenlock $builddep_lock_fdif ! dnf builddep "SPECS/$src"; thenunlock $builddep_lock_fdreturn $MISSINGfiunlock $builddep_lock_fdfi# 编译rpm二进制包if ! rpmbuild "$rpmbdf" "SPECS/$src" "${rpmbdo[@]}" "${custom_define_arr[@]}"; thenreturn $ERRORfireturn $SUCCESS
}# 编译执行调用
function exec_compile() {exec_spec "$1"local exit_code=$?if $lock_switch; then# 退出码写入统计文件lockecho "$exit_code $1" >>$spec_count_fileunlockelse# 统计spec文件编译结果spec_compile_result "$exit_code $1"fi
}# 编译rpm二进制包拷贝函数
function rpm_check_move() {if [ ! -e $success_dir ]; thenmkdir -p $success_dirfiif [ ! -e $rpm_source ]; thenmkdir -p $rpm_sourcecreaterepo_c $rpm_source --updatefi# 开始拷贝二进制rpm包,将编译路径中的二进制rpm包移动到source目录下for rd in ~/rpmbuild/RPMS/*; doif [[ "$rd" = "$rpm_source" || $(find "$rd" -type f | wc -l) -eq 0 ]]; thencontinuefiif [[ "$1" = 'end' ]]; thencp -f "$rd"/* $success_dirfimv -f "$rd"/* $rpm_sourcedone# 检查createrepo_c包是否存在if [[ "$1" = 'start' ]] && ! which createrepo_c; thendnf install createrepo_c# 查询配置文件是否存在本地源while read -re line; doif [[ "$line" = "[local1]" ]]; thencreaterepo_c $rpm_source --updatereturn 0fidone <$dnf_configecho -e "\n[local1] \nname=local1 \nbaseurl = file://$rpm_source \nenabled=1" >>$dnf_configcreaterepo_c $rpm_source --updatefi
}# 开启管道
function enable_fifo() {# 多进程管道文件绑定if [ -e "$lock_file" ]; thenrm $lock_filefimkfifo $lock_fileexec 100<>$lock_filelock_fd=100rm $lock_file# 依赖加载管道文件绑定if [ -e "$builddep_lock_file" ]; thenrm $builddep_lock_filefimkfifo $builddep_lock_fileexec 101<>$builddep_lock_filebuilddep_lock_fd=101rm $builddep_lock_fileecho >&$builddep_lock_fd# 通用管道文件绑定if [ -e "$global_lock_file" ]; thenrm $global_lock_filefimkfifo $global_lock_fileexec 102<>$global_lock_fileglobal_lock_fd=102rm $global_lock_fileecho >&$global_lock_fd# 创建令牌桶,限制并发数量if [ "$thread_max_num" -gt "$spec_count" ]; thenthread_max_num=$spec_countfifor ((i = 0; i < "$thread_max_num"; i++)); doecho >&$lock_fddone
}# 统计spec编译情况
function spec_compile_result() {local _spec_detail=()read -ra _spec_detail <<<"$1"case "${_spec_detail[0]}" in"$SUCCESS")success_spec_count_arr[success_spec_count]="${_spec_detail[1]}"((success_spec_count++));;"$ALREADY")already_spec_count_arr[already_spec_count]="${_spec_detail[1]}"((already_spec_count++));;"$MISSING")missing_spec_count_arr[missing_spec_count]="${_spec_detail[1]}"((missing_spec_count++));;"$ERROR")error_spec_count_arr[error_spec_count]="${_spec_detail[1]}"((error_spec_count++));;esac
}# 统计类型输出结果
function finish_result_by_type() {for t in "$@"; dolocal _print_arr=()local _print_arr_count=0local _print_arr_tittle=''case "$t" in"$SUCCESS")_print_arr=("${success_spec_count_arr[@]}")_print_arr_count=$success_spec_count_print_arr_tittle="$SUCCESS_MESSAGE";;"$ALREADY")_print_arr=("${already_spec_count_arr[@]}")_print_arr_count=$already_spec_count_print_arr_tittle="$ALREADY_MESSAGE";;"$MISSING")_print_arr=("${missing_spec_count_arr[@]}")_print_arr_count=$missing_spec_count_print_arr_tittle="$MISSING_MESSAGE";;"$ERROR")_print_arr=("${error_spec_count_arr[@]}")_print_arr_count=$error_spec_count_print_arr_tittle="$ERROR_MESSAGE";;esacif [ $_print_arr_count -gt 0 ]; then# 打印echo -ne "$result_content_background\r"echo "$result_prev_fix $_print_arr_tittle "# 写日志if $log_switch; thenecho "$_print_arr_tittle" >>$log_filefiif $log_history_switch; thenecho "$_print_arr_tittle" >>$log_file_historyfifor ((i = 0; i < _print_arr_count; i++)); do# 打印echo -ne "$result_content_background\r"echo "$result_prev_fix ${_print_arr[i]}"# 写日志if $log_switch; thenecho "${_print_arr[i]}" >>$log_filefiif $log_history_switch; thenecho "${_print_arr[i]}" >>$log_file_historyfidoneecho "$result_front_back"fidone
}# 输出结果
function finish_result() {for ((i = 0; i < result_prefix_num; i++)); doresult_prev_fix="$result_prev_fix$result_fix"doneresult_front_back=''result_content_background=''for ((i = 0; i < result_width; i++)); doresult_front_back="$result_front_back$result_fix"if [ $i -lt $((result_width - result_postfix_num)) ]; thenresult_content_background="$result_content_background "elseresult_content_background="$result_content_background$result_fix"fidone# 统计个数输出local _result_count_print=()for c in "${result_sequence[@]}"; docase "$c" in"$SUCCESS")_result_count_print+=("$SUCCESS_MESSAGE: $success_spec_count");;"$ALREADY")_result_count_print+=("$ALREADY_MESSAGE $already_spec_count");;"$MISSING")_result_count_print+=(" $MISSING_MESSAGE $missing_spec_count");;"$ERROR")_result_count_print+=("$ERROR_MESSAGE $error_spec_count");;esacdonefor ((i = 0; i < ${#_result_count_print[@]} - 1; i++)); do_result_count_print[i]="${_result_count_print[i]} ,"donespec_count_print="spec文件总计: $spec_count , ${_result_count_print[*]}"# 执行时间runtime=$(($(date +%s) - script_start_time))runtime_print=''if [ "$runtime" -le 60 ]; thenruntime_print="runtime $runtime 秒 "elif [ "$runtime" -le $((60 * 60)) ]; thenruntime_print="runtime $((runtime / 60)) 分 $((runtime % 60)) 秒 "elseruntime_print="runtime $((runtime / (60 * 60))) 时 $((runtime % (60 * 60) / 60)) 分 $((runtime % (60 * 60) % 60)) 秒 "fi# 输出结果echo -e "\n$result_front_back"echo -ne "$result_content_background\r"echo "$result_prev_fix $runtime_print"echo -ne "$result_content_background\r"echo "$result_prev_fix $spec_count_print"echo -e "$result_front_back"# 打印不同执行结果信息finish_result_by_type "${result_sequence[@]}"
}
#------------------------------------------------function define end-------------------------------------------------#------------------------------------------------code execute start-------------------------------------------------
if ! cd ~/rpmbuild; thenecho "cd ~/rpmbuild fail, Please ensure the directory ~/rpmbuild exists"exit
fi# 命令行参数处理
arr_spec_organize "$@"
spec_count=${#arr[@]}
echo "==== spec文件总计: $spec_count ===="
[ "$spec_count" -gt 0 ] || exit
[ "$spec_count" -eq 1 ] || lock_switch=true# rpm包路径检查和移动 -> 源码编译不检查
if [[ "$rpmbdf" != '-bs' ]]; thenrpm_check_move 'start'
fi# 刷新dnf缓存 -> 源码编译不刷新
if [[ "$rpmbdf" != '-bs' ]]; thenecho '刷新dnf缓存中.......'dnf makecache
fi# 开启管道
if $lock_switch; thenenable_fifo
fi# 清空统计记录
if $lock_switch; thenecho -n >$spec_count_file
fi# 日志写入日期头
if $log_switch; thendate >$log_file
fi
if $log_history_switch; thenecho >>$log_file_history && date >>$log_file_history
fi# 多进程开始编译
for ((i = 0; i < spec_count; i++)); doif $lock_switch; thenlock $lock_fd{exec_compile "${arr[i]}"unlock $lock_fd} &elseexec_compile "${arr[i]}"fi
done
wait# 统计spec文件编译结果
if $lock_switch; thenwhile read -re line; dospec_compile_result "$line"done <$spec_count_filerm $spec_count_file
fi# 如果有编译成功,拷贝并刷新 -> 源码编译不刷新
if [[ $success_spec_count -gt 0 && "$rpmbdf" != '-bs' ]]; thenrpm_check_move 'end'createrepo_c $rpm_source --update
fi# 记录日志并打印编译结果
finish_result
#------------------------------------------------code execute end--------------------------------------------------

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/20827.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习各个算法的优缺点!(上篇) 建议收藏。

下篇地址&#xff1a;机器学习各个算法的优缺点&#xff01;&#xff08;下篇&#xff09; 建议收藏。-CSDN博客 纯干货&#xff01;&#xff01; 回归 正则化算法 集成算法 决策树算法 支持向量机 降维算法 聚类算法 贝叶斯算法 人工神经网络 深度学习 感兴趣的朋友…

硬币检测电路设计

一、来源&#xff1a;凡亿教育 第一场&#xff1a;硬币检测装置原理分析、电路设计以及器件选型_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Zh4y1V7Px/?p1&vd_source43eb1cb50ad3175d7f3b9385905cd88f 二、开发软件&#xff1a;KEIL MDK 三、主控芯片&#…

PostgreSQL常用插件

PostgreSQL 拥有许多常用插件&#xff0c;这些插件可以大大增强其功能和性能。以下是一些常用的 PostgreSQL 插件&#xff1a; 性能监控和优化 pg_stat_statements 1.提供对所有 SQL 语句执行情况的统计信息。对调优和监控非常有用。 2.安装和使用&#xff1a; pg_stat_k…

数据库之函数、存储过程

函数、存储过程 1.函数 函数&#xff0c;常用于对一个或多个输入参数进行操作&#xff0c;主要目的是返回一个结果值&#xff0c;就是一种方法&#xff0c;在postgre里存放的位置叫function&#xff0c;比如创建一个计算长方面积的函数。 举例&#xff1a;建立一个计算长方形…

kali-搭建Pikachu漏洞练习平台

环境&#xff1a;kali 压缩包&#xff1a;pikachu-master.zip &#xff08;下载地址&#xff1a;GitHub - zhuifengshaonianhanlu/pikachu: 一个好玩的Web安全-漏洞测试平台&#xff09; 1.mysql 1.开启kali中自带的mysql systemctl restart mysql #重启MySQL服务 systemc…

Java面试题:Redis2_解决Redis缓存击穿问题

缓存击穿 当一个key过期时,需要对这个key进行数据重建 在重建的时间内如果有大量的并发请求进入,就会绕过缓存进入数据库,会瞬间击垮DB 重建时间可能因为数据是多个表的混合结果需要分头统计而延长,从而更容易出现缓存击穿问题 缓存击穿的解决方案 添加互斥锁 先查询缓存…

Ubuntu系统配置DDNS-GO【笔记】

DDNS-GO 是一个基于 Go 语言的动态 DNS (DDNS) 客户端&#xff0c;用于自动更新你的 IP 地址到 DNS 记录上。这对于经常变更 IP 地址的用户&#xff08;如使用动态 IP 的家庭用户或者小型服务器&#xff09;非常有用。 此文档实验环境为&#xff1a;ubuntu20.04.6。 在Ubuntu…

GIt快速入门(一文学会使用Git)

GIt快速入门 文章目录 GIt快速入门一、为什么要学习Git二、Git的安装1.安装Git2.下载GUI 三、Git的概念1、版本控制2、集中式控制3、分布式控制4、多人协作开发1.并行开发2.分支管理3.冲突解决4.代码审查5.分布式特性 四、Git客户端操作1.界面介绍2.提交操作3.创建分支4.合并分…

vscode编辑器创建分支注意事项?!

最近在公司开发项目时&#xff0c;不小心将自己分支的东西提交到公司的master的分支&#xff0c;大家看看是什么情况&#xff1f; 先上图&#xff1a; 从图上看&#xff0c;我这边用了GITLENS这个插件&#xff0c;在创建分支时&#xff0c;有个create branch from&#xff0c;有…

Zynq学习笔记--AXI4-Stream 图像数据从仿真输出到图像文件

目录 1. 简介 2. 构建工程 2.1 Vivado 工程 2.2 TestBench 代码 2.3 关键代码分析 3. VPG Background Pattern ID (0x0020) Register 4. 总结 1. 简介 使用 SystemVerilog 将 AXI4-Stream 图像数据从仿真输出到图像文件 (PPM)。 用到的函数包括 $fopen、$fwrite 和 $f…

2024 第三届 AIGC 中国开发者大会:多模态大模型的发展与趋势

引言 在2024年第三届AIGC中国开发者大会上&#xff0c;零一万物联合创始人潘欣分享了多模态大模型的发展与趋势。潘欣对多模态大模型的历史、现状和未来进行了详细回顾和深刻思考&#xff0c;为我们揭示了该领域的发展路径和技术前景。本文将详细解读潘欣的分享内容&#xff0…

Vue3实战笔记(56)—实战:DefineModel的使用方法细节

文章目录 前言一、实战DefineModel二、思考原理总结 前言 今天写个小例子&#xff0c;实战DefineModel的使用方法细节 一、实战DefineModel 上文官方说的挺清楚&#xff0c;实战验证一下&#xff0c;新建DefineModel.vue&#xff08;这是儿子&#xff09;&#xff1a; <te…

Facebook开户 | Facebook二不限户

Facebook二不限户的正确使用方法 Facebook 二不限是指 Facebook 国内二不限户&#xff0c;是通过代理开出来的一种特殊账户&#xff0c;️需要广告主准备主页。 其特点是&#xff1a;限主页、不限域名、额度没解限&#xff0c;解限后则不限额度。 相比于三不限户&#xff0c;…

Pycharm的基础设置+Pycharm与AutoDL服务器连接

一.pycharm的基础设置 1.下载pycharm profession版&#xff0c;配置之前博客里面的解释器mask2 2.run detect.py 3.终端的设置 &#xff08;1&#xff09;先直接在终端里面pip install 我们再创建一个测试python文件&#xff1a;terninal_test.py 虽然上面安装成功了包&#x…

GNU Radio创建qt time plot python OOT块

文章目录 前言一、创建自定义的 OOT 块1、安装相应依赖2、创建 OOT 块3、修改相关4、编译及安装 OOT 块 二、测试1、grc 图2、运行结果 三、资源自取 前言 官方提供的绘制时域波形的 block 名字叫做 QT GUI Time Sink&#xff0c;其底层实现是用 C 写的&#xff0c;但是我发现…

回归预测 | MATLAB实现基于GOOSE-LightGBM的多特征输入单输出数据回归预测(鹅优化算法)

回归预测 | MATLAB实现基于GOOSE-LightGBM的多特征输入单输出数据回归预测(鹅优化算法) 目录 回归预测 | MATLAB实现基于GOOSE-LightGBM的多特征输入单输出数据回归预测(鹅优化算法)效果一览基本介绍程序设计参考资料 效果一览 基本介绍 MATLAB实现基于LightGBM算法的数据回归预…

AI办公自动化:用通义千问Qwen-Long批量总结PDF长文档内容

Qwen-Long是在通义千问针对超长上下文处理场景的大语言模型&#xff0c;支持中文、英文等不同语言输入&#xff0c;支持最长1000万tokens(约1500万字或1.5万页文档)的超长上下文对话。配合同步上线的文档服务&#xff0c;可支持word、pdf、markdown、epub、mobi等多种文档格式的…

查看VUE3代理后真正请求的URL

在vite.config.ts中添加如下配置&#xff1a; server: {host: "0.0.0.0", // 指定服务器应该监听哪个 IP 地址port: 8848, // 指定开发服务器端口open: true, // 开发服务器启动时&#xff0c;自动在浏览器中打开应用程序cors: true,// Load proxy configuration fr…

无人售货机零售业务成功指南:从市场分析到创新策略

在科技驱动的零售新时代&#xff0c;无人售货机作为一种便捷购物解决方案&#xff0c;正逐步兴起&#xff0c;它不仅优化了消费者体验&#xff0c;还显著降低了人力成本&#xff0c;提升了运营效能。开展这项业务前&#xff0c;深入的市场剖析不可或缺&#xff0c;需聚焦消费者…

openresty(Nginx) 配置 特殊URL 密码访问 使用htpasswd 配置 Basic_Auth登录认证

1 使用htpasswd 生成密码文件.htpasswd是Apache附带的工具。如果没有可以安装。 #centos 8.5 系统 yum install httpd-tools #Ubuntu 24.04 系统 sudo apt update sudo apt-get install apache2-utils #生成密码文件,用户test sudo htpasswd -c /usr/local/openresty/nginx/…