mirror of the now-defunct rocklinux.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

504 lines
15 KiB

  1. #!/bin/bash
  2. #
  3. # --- ROCK-COPYRIGHT-NOTE-BEGIN ---
  4. #
  5. # This copyright note is auto-generated by ./scripts/Create-CopyPatch.
  6. # Please add additional copyright information _after_ the line containing
  7. # the ROCK-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by
  8. # the ./scripts/Create-CopyPatch script. Do not edit this copyright text!
  9. #
  10. # ROCK Linux: rock-src/scripts/Build-Target
  11. # ROCK Linux is Copyright (C) 1998 - 2006 Clifford Wolf
  12. #
  13. # This program is free software; you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License as published by
  15. # the Free Software Foundation; either version 2 of the License, or
  16. # (at your option) any later version. A copy of the GNU General Public
  17. # License can be found at Documentation/COPYING.
  18. #
  19. # Many people helped and are helping developing ROCK Linux. Please
  20. # have a look at http://www.rocklinux.org/ and the Documentation/TEAM
  21. # file for details.
  22. #
  23. # --- ROCK-COPYRIGHT-NOTE-END ---
  24. #
  25. # Run this command from the ROCK directory as ./scripts/Build-Target
  26. # after running the ./scripts/Config and ./scripts/Download commands.
  27. #
  28. # It compiles/builds all the packages and stores them as tar balls suitable
  29. # for distribution.
  30. #
  31. # This script is the ROCK work-horse. It builds in a chroot environment
  32. # (stage 3..9) and goes through a number of build stages:
  33. #
  34. config=default
  35. build_only_this_job=
  36. stages=0123456789
  37. daemon_mode=0
  38. options="$*"
  39. tasks=0
  40. while [ "$1" ] ; do
  41. case "$1" in
  42. -cfg) config=$2 ; shift ; shift ;;
  43. -stages) stages=$2 ; shift ; shift ;;
  44. -tasks) tasks=$2 ; shift ; shift ;;
  45. -job) build_only_this_job=$2 ; shift ; shift ;;
  46. -daemon) daemon_mode=1 ; shift ;;
  47. -nodaemon) daemon_mode=0 ; shift ;;
  48. *) echo "Usage: $0 [ -daemon ] [ -tasks <N> ] [ -cfg <config> ]" \
  49. "[ -stages <list> ] [ -job <stage>-<package> ]"
  50. echo
  51. echo " Compile/build all packages for a given configuration and store them as tar"
  52. echo " balls suitable for distribution."
  53. echo " This script is the ROCK work-horse. It builds in a chroot environment"
  54. echo " (stage 2..9) and goes through a number of build stages."
  55. echo " Run this command from the ROCK directory as ./scripts/Build-Target after"
  56. echo " running the ./scripts/Config and ./scripts/Download commands."
  57. echo
  58. echo " -cfg <config> the build configuration to use; defaults to 'default'"
  59. echo " -tasks <N> run <N> Build-Job daemons (for cluster builds)"
  60. echo " -daemon run as daemon in the background"
  61. echo " -stages <list> only build the stages listed in the parameter"
  62. echo " -job <stage>-<package> build only one job: the given package"
  63. echo " in the given stage"
  64. exit 1 ;;
  65. esac
  66. done
  67. if [ $tasks -gt 1 ] ; then
  68. . config/$config/config
  69. if [ "$ROCKCFG_PARALLEL" = 0 ] ; then
  70. echo_error "You have not configured this to be a cluster build!"
  71. echo_error "Please remove -tasks $tasks or configure this for cluster build"
  72. exit 1
  73. fi
  74. fi
  75. if [ "$daemon_mode" = 1 ] ; then
  76. . config/$config/config
  77. echo "Running $0 in the background (messages go to logfile only).."
  78. echo "Logfile: build/$ROCKCFG_ID/ROCK/logs/build_target.log"
  79. nohup $0 $options -nodaemon > /dev/null 2> /dev/null < /dev/null &
  80. exit 0
  81. fi
  82. . scripts/parse-config
  83. . scripts/functions
  84. # so we can disable stuff not available in Build-Target
  85. export ROCK_BUILD_TARGET=1
  86. build_root="$base/build/$ROCKCFG_ID"
  87. # Set permissions and ownership of $build_root; $base/build might have different ones.
  88. mkdir -p "${build_root}" ; chmod 700 "${build_root}" ; chown 0:0 "${build_root}"
  89. build_rock="$base/build/$ROCKCFG_ID/ROCK"
  90. build_logs="$build_rock/logs" ; mkdir -p "${build_logs}"
  91. build_pkgs="$build_rock/pkgs" ; mkdir -p "${build_pkgs}"
  92. if [ "$ROCKCFG_PARANOIA_CHECK" = 1 ] ; then
  93. ./scripts/Check-System -paranoia || exit 1
  94. else
  95. ./scripts/Check-System || exit 1
  96. fi
  97. # Package Build loop - executed by build-target
  98. #
  99. pkgloop() {
  100. if [ "$ROCKCFG_NOBROKENDEPS" = 1 ]; then
  101. nobrokendeps="-nobrokendeps"
  102. else
  103. nobrokendeps=""
  104. fi
  105. if [ "$ROCKCFG_RETRY_BROKEN" -eq 1 -a \
  106. -z "$build_only_this_job" -a \
  107. "`ls ${build_root}/var/adm/logs/*.err 2> /dev/null`" ] ; then
  108. echo_header "Removing old error logs ..."
  109. for x in ${build_root}/var/adm/logs/*.err ; do
  110. echo_status "Removing ${x#$build_root/} ..."
  111. rm -f $x
  112. done
  113. fi
  114. if [ -z "$build_only_this_job" -a \
  115. "`ls ${build_root}/var/adm/logs/*.out 2> /dev/null`" ] ; then
  116. echo_header "Removing old output logs ..."
  117. for x in ${build_root}/var/adm/logs/*.out ; do
  118. echo_status "Removing ${x#$build_root/} ..."
  119. rm -f $x
  120. done
  121. fi
  122. if [ "$ROCKCFG_PARALLEL" = 1 -a -z "$build_only_this_job" ]
  123. then
  124. qdir="$base/build/$ROCKCFG_ID/ROCK/queue"
  125. mkdir -p $qdir; rm -f $qdir/*
  126. newqueue=1 ; printstatus=1 ; printstatus_counter=30
  127. finished=0 ; touch $qdir/queue.txt
  128. if [ -z "$ROCKCFG_PARALLEL_ADDJOB" ] ; then
  129. touch $qdir/use_build_job_daemon
  130. if [ $tasks = 0 ]; then
  131. echo "
  132. Job Queue for parallel (cluster) build created.
  133. You have not configured a command for adding jobs. So you need to use the
  134. ROCK Linux built-in job queue. To do so, you need to login to your build
  135. nodes and execute the command:
  136. ./scripts/Build-Job -cfg $config -daemon
  137. "
  138. else
  139. echo "
  140. Job Queue for parallel (cluster) build created. Now creating worker tasks..
  141. "
  142. for ((n=0; n<tasks; n++)); do
  143. echo -n "[$n] "
  144. ./scripts/Build-Job -cfg $config -daemon
  145. done
  146. echo "
  147. Parallel (cluster) build running...
  148. "
  149. fi
  150. else
  151. echo "
  152. Job Queue for parallel (cluster) build created.
  153. You have configured a command for adding jobs. So if everything is configured
  154. in the right way, the nodes will automatically start building the jobs.
  155. "
  156. rm -f $qdir/use_build_job_daemon
  157. fi
  158. while
  159. if [ -f $qdir/print_status ] ; then
  160. rm -f $qdir/print_status
  161. printstatus=1 ; printstatus_counter=0
  162. fi
  163. if [ "$printstatus" = 1 ] ; then
  164. if [ $printstatus_counter -le 0 ] ; then
  165. ./scripts/Create-ParaStatus -cfg "$config"
  166. printstatus=0 ; printstatus_counter=300
  167. else
  168. printstatus_counter=$(($printstatus_counter - 1))
  169. fi
  170. fi
  171. for x in $qdir/*.msg ; do
  172. if [ -f "$x" ] ; then
  173. expand -t20 < $x ; rm -f $x
  174. printstatus=1 ; newqueue=1
  175. fi
  176. done
  177. if [ "$newqueue" = 1 ] ; then
  178. ./scripts/Create-PkgQueue \
  179. -cfg $config -stages $stages \
  180. $nobrokendeps | sort -r -n -k2 | \
  181. if [ $ROCKCFG_PARALLEL_MAX -gt 0 ]
  182. then head -n $ROCKCFG_PARALLEL_MAX
  183. else cat ; fi > $qdir/queue.new
  184. mv $qdir/queue.new $qdir/queue.txt
  185. newqueue=0
  186. while read next ; do
  187. set $next ; qid="$1-$6"
  188. if [ ! -f $qdir/$qid.job ] ; then
  189. date "+%H:%M %Y-%m-%d: creating new job '$qid'" | expand -t20
  190. echo "Job $qid waiting in the job queue (priority $2)" > $qdir/$qid.todo
  191. printstatus=1
  192. # we need to remove some variables that should be uniqe per node
  193. dump_env | grep -v HOSTNAME= > $qdir/$qid.new
  194. mv $qdir/$qid.new $qdir/$qid.job
  195. if [ "$ROCKCFG_PARALLEL_ADDJOB" ] ; then
  196. x="${ROCKCFG_PARALLEL_ADDJOB//\{\}/.\/scripts\/Build-Job -cfg $config $qid}" ; sh -c "$x"
  197. fi
  198. fi
  199. done < $qdir/queue.txt
  200. fi
  201. if [ -s $qdir/queue.txt ] || \
  202. [ "`ls $qdir/*.job 2>/dev/null`" ]
  203. then
  204. finished=0
  205. else
  206. finished=$(( $finished + 1 ))
  207. newqueue=1
  208. fi
  209. [ $finished -le 3 ]
  210. do
  211. sleep 1
  212. done
  213. echo "All packages built."
  214. sleep 2; rm -rf $qdir
  215. else
  216. if [ "$build_only_this_job" ] ; then
  217. rm -f "${build_root}"/var/adm/logs/${build_only_this_job}.log
  218. rm -f "${build_root}"/var/adm/logs/${build_only_this_job}.err
  219. next="$( awk 'BEGIN { FS=" "; }
  220. $0 ~ /[ =]'${build_only_this_job#*-}' / && \
  221. $2 ~ /'${build_only_this_job%%-*}'/ \
  222. { $1="'${build_only_this_job%%-*}' 0";
  223. print; exit; }' < config/$config/packages )"
  224. [ "$next" ] && pkgloop_package $next
  225. exit 0
  226. else
  227. while
  228. next="`./scripts/Create-PkgQueue \
  229. -cfg "$config" -stages $stages -single $nobrokendeps`"
  230. [ "$next" ]
  231. do
  232. pkgloop_package $next
  233. done
  234. fi
  235. fi
  236. local pkglst=`mktemp` errors=0; rm -f src/invalid-files.lst
  237. echo_header "Searching for old lingering files ..."
  238. grep "^X" config/$config/packages | cut -d' ' -f5 | sed 's,.*=,,' |
  239. if [ $ROCKCFG_PKGFILE_VER = 1 ] ; then
  240. while read p; do
  241. v=$( grep -h '^Package Name and Version:' build/$ROCKCFG_ID/var/adm/packages/$p:* \
  242. build/$ROCKCFG_ID/var/adm/packages/$p 2> /dev/null | cut -f6,7 -d' ' | tr ' ' - | head -n1 )
  243. echo "$p-$v"
  244. done
  245. else
  246. cat
  247. fi > $pkglst
  248. for file in $( ls build/$ROCKCFG_ID/ROCK/pkgs/ ) ; do
  249. x="$file"
  250. [ "$x" = packages.db ] && continue
  251. [ "$x" = packages.db.md5 ] && continue
  252. [ "$x" = packages_stripped.db ] && continue
  253. [ "$x" = packages_stripped.db.md5 ] && continue
  254. [ $ROCKCFG_CREATE_GEM = 0 ] || x=${x%.gem}
  255. [ $ROCKCFG_CREATE_TARBZ2 = 0 ] || x=${x%.tar.bz2}
  256. y=$( echo $x | sed 's,:[^-]*,,' )
  257. if ! grep -qx "$y" $pkglst; then
  258. file="build/$ROCKCFG_ID/ROCK/pkgs/$file"
  259. echo_error "$file [$x $y] should not be present" \
  260. "(now in src/invalid-files.lst)!"
  261. mkdir -p src; echo "$file" >> src/invalid-files.lst
  262. errors=1
  263. fi
  264. done
  265. for dir in build/$ROCKCFG_ID/var/adm/{cache,cksums,dependencies,descs,flists,md5sums,packages} ; do
  266. for file in $( ls $dir ) ; do
  267. if [ $ROCKCFG_PKGFILE_VER = 1 ] ; then x="${file%:*}-.*"; else x="${file%:*}"; fi
  268. if ! grep -xq "$x" $pkglst ; then
  269. echo_error "$dir/$file should not be present (now in src/invalid-files.lst)!"
  270. mkdir -p src; echo "$dir/$file" >> src/invalid-files.lst
  271. errors=1
  272. fi
  273. done
  274. done
  275. for file in $( ls build/$ROCKCFG_ID/var/adm/logs/ ) ; do
  276. x="`echo $file | sed -e 's/^.-//' -e 's/\.log//' -e 's/\.err//' -e s'/\.out//'`"
  277. if [ $ROCKCFG_PKGFILE_VER = 1 ] ; then x="$x-.*"; else x="$x"; fi
  278. if ! grep -xq "$x" $pkglst ; then
  279. file="build/$ROCKCFG_ID/var/adm/logs/$file"
  280. echo_error "$file should not be present (now in src/invalid-files.lst)!"
  281. mkdir -p src; echo "$file" >> src/invalid-files.lst
  282. errors=1
  283. fi
  284. done
  285. [ $errors = 0 ] && echo_status "No errors found."
  286. rm $pkglst
  287. }
  288. # Process one line of output generated by Create-PkgQueue
  289. #
  290. pkgloop_package() {
  291. for x in stagelevel pkg_depnr pkg_stages pkg_pri pkg_tree \
  292. pkg_name pkg_ver pkg_extraver pkg_extra
  293. do eval "$x=\$1" ; shift ; done
  294. # Maybe this is a forked package
  295. pkg_basename="${pkg_name%=*}"
  296. pkg_name="${pkg_name#*=}"
  297. [ "$build_only_this_job" -a \
  298. "$stagelevel-$pkg_name" != "$build_only_this_job" ] && return
  299. [ $(expr "$pkg_stages" : ".*$stagelevel.*") -eq 0 ] && return
  300. pkg_laststage=$(echo "$pkg_stages" | sed "s,-,,g; s,.*\(.\),\1,")
  301. cmd_root="-root auto"
  302. [ $stagelevel -ge 3 ] && cmd_root="$cmd_root -chroot"
  303. cmd_buildpkg="./scripts/Build-Pkg -$stagelevel -cfg $config -nopostinst"
  304. cmd_buildpkg="$cmd_buildpkg $cmd_root $pkg_basename=$pkg_name"
  305. # Execute action handler
  306. pkgloop_action || [ "$ROCKCFG_ABORT_ON_ERROR" != 1 ] || exit 1
  307. if [ -f ${build_root}/var/adm/logs/$stagelevel-$pkg_name.err -a \
  308. "$ROCKCFG_SENDMAIL" = 1 ]
  309. then
  310. {
  311. cat << EOT
  312. Subject: [ROCK Build-Target] $stagelevel-$pkg_name in $config failed
  313. Building package $pkg_name failed in stage $stagelevel:
  314. ----
  315. EOT
  316. echo; tail -n 200 ${build_root}/var/adm/logs/$stagelevel-$pkg_name.err; echo
  317. } | $ROCKCFG_SENDMAIL_BIN $ROCKCFG_SENDMAIL_TO
  318. fi
  319. if [ -f ${build_root}/var/adm/logs/$stagelevel-$pkg_name.err -a \
  320. "$ROCKCFG_HTTP" = 1 ]
  321. then
  322. {
  323. query=${ROCKCFG_HTTP_SITE}
  324. query=${query//PACKAGE/$pkg_name}
  325. query=${query//STAGE/$stagelevel}
  326. query=${query//CONFIG/$config}
  327. query=${query//STATUS/failed}
  328. curl "${query}" > /dev/null 2>&1
  329. }
  330. fi
  331. if [ ! -f ${build_root}/var/adm/logs/$stagelevel-$pkg_name.log -a \
  332. ! -f ${build_root}/var/adm/logs/$stagelevel-$pkg_name.err ]
  333. then
  334. echo_header "Package build ended abnormally!"
  335. echo_error "Usually a package build creates eighter a *.log"
  336. echo_error "or a *.err file. Neither the 1st nor the 2nd is"
  337. echo_error "there. So I'm going to create a *.err file now"
  338. echo_error "and abort the build process."
  339. touch ${build_root}/var/adm/logs/$stagelevel-$pkg_name.err
  340. exit 1
  341. fi
  342. if [ "${ROCKCFG_HTTP}" = "1" -a -f ${build_root}/var/adm/logs/$stagelevel-$pkg_name.log ]
  343. then
  344. {
  345. query=${ROCKCFG_HTTP_SITE}
  346. query=${query//PACKAGE/$pkg_name}
  347. query=${query//STAGE/$stagelevel}
  348. query=${query//CONFIG/$config}
  349. query=${query//STATUS/finished}
  350. curl "${query}" > /dev/null 2>&1
  351. }
  352. fi
  353. if [ $pkg_laststage -eq $stagelevel ] && \
  354. [ "$ROCKCFG_CREATE_TARBZ2" = 1 -o "$ROCKCFG_CREATE_GEM" = 1 ]
  355. then
  356. if [ -f ${build_root}/var/adm/logs/$stagelevel-$pkg_name.err ]
  357. then echo_error "Creation of binary package isn't possible,"
  358. echo_error "because the package was not successfully"
  359. echo_error "built in (at least) the current stage."
  360. else
  361. for spkg in $( cd ${build_root}/var/adm/packages/; ls ${pkg_name} ${pkg_name}:* 2>/dev/null )
  362. do
  363. echo_header "Creating binary package file for ${spkg}."
  364. mkdir -p "${build_pkgs}"
  365. if [ "$ROCKCFG_PKGFILE_VER" = 1 ]
  366. then
  367. v="-$( grep '^Package Name and Version:' \
  368. ${build_root}/var/adm/packages/$spkg | cut -f6,7 -d' ' | tr ' ' - )"
  369. else
  370. v=""
  371. fi
  372. echo_status "Building build/.../pkgs/`
  373. `${spkg}${v}.tar.bz2"
  374. ( cd "$build_root/"
  375. cut -f2- -d' ' var/adm/flists/$spkg | \
  376. tar -cf- --no-recursion --files-from=- | bzip2
  377. ) > "${build_pkgs}/${spkg}${v}.tar.bz2.tmp"
  378. if [ "$ROCKCFG_CREATE_GEM" = 1 ] ; then
  379. echo_status "Building build/.../pkgs/`
  380. `${spkg}${v}.gem"
  381. mine -C "$build_root/var/adm" \
  382. "${build_pkgs}/${spkg}${v}.tar.bz2.tmp" \
  383. $spkg "$build_pkgs/${spkg}${v}.gem"
  384. fi
  385. if [ "$ROCKCFG_CREATE_TARBZ2" = 1 ] ; then
  386. mv "$build_pkgs/${spkg}${v}.tar.bz2.tmp" \
  387. "$build_pkgs/${spkg}${v}.tar.bz2"
  388. else
  389. echo_status "Removing temporary tar.bz2."
  390. rm -f "$build_pkgs/${spkg}${v}.tar.bz2.tmp"
  391. fi
  392. done
  393. fi
  394. fi
  395. }
  396. # Action executed by pkgloop(). This function may be redefined
  397. # before calling pkgloop().
  398. #
  399. pkgloop_action() {
  400. $cmd_buildpkg
  401. }
  402. # Try to umount any directories mounted by Build-Pkg -chroot
  403. # if we are the last process using them.
  404. #
  405. build_target_exit() {
  406. exec 201> /dev/null
  407. exec 1>&0 2>&0
  408. echo_header "Running Build-Target cleanup procedure"
  409. echo_status "Killing lingering processes and removing parallel build queue."
  410. rm -rf $build_rock/queue
  411. fuser -k ${build_logs}/*.log &> /dev/null
  412. sleep 2
  413. echo_status "Umounting lingering mounts in build/$ROCKCFG_ID."
  414. umount -d -f $build_rock/{loop,config,download} 2> /dev/null
  415. umount -d -f -l $build_rock/{loop,config,download} 2> /dev/null
  416. umount -d -f $build_root/proc 2> /dev/null
  417. umount -d -f -l $build_root/proc 2> /dev/null
  418. umount -d -f $build_root/dev 2> /dev/null
  419. umount -d -f -l $build_root/dev 2> /dev/null
  420. echo_status "READY."
  421. echo
  422. }
  423. # must trap outside the group command
  424. trap 'build_target_exit' EXIT
  425. {
  426. ln -sf build_target_$$.log ${build_logs}/build_target.log
  427. ./scripts/Build-Tools -1 -cfg $config
  428. . ./target/$ROCKCFG_TARGET/build.sh
  429. echo_header "Finished building this target."
  430. echo_status "Going to run cleanup procedure now.."
  431. } 2>&1 201>> "${build_logs}/build_target_$$.log" | \
  432. tee -a "${build_logs}/build_target_$$.log"
  433. if [ "${ROCKCFG_HTTP}" = "1" ] ; then
  434. {
  435. query=${ROCKCFG_HTTP_SITE}
  436. query=${query//PACKAGE/}
  437. query=${query//STAGE/}
  438. query=${query//CONFIG/$config}
  439. query=${query//STATUS/finished}
  440. curl "${query}" > /dev/null 2>&1
  441. }
  442. fi
  443. if [ "$ROCKCFG_SENDMAIL" = 1 ]; then
  444. $ROCKCFG_SENDMAIL_BIN $ROCKCFG_SENDMAIL_TO << EOT
  445. Subject: [ROCK Build-Target] $config finished.
  446. Finished building $config.
  447. EOT
  448. fi