modified version of jenkins debian glue (https://github.com/mika/jenkins-debian-glue) for devuan
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.
 
 
 
 
 

426 lines
14 KiB

  1. #!/bin/sh
  2. set -x
  3. set -u
  4. # make sure cowbuilder/pbuilder/... are available
  5. PATH='/bin:/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin'
  6. checks_and_defaults() {
  7. if [ -r /etc/jenkins/debian_glue ] ; then
  8. . /etc/jenkins/debian_glue
  9. fi
  10. if [ -z "${JOB_NAME:-}" ] ; then
  11. echo "No JOB_NAME defined, please run it in jenkins." >&2
  12. exit 1
  13. fi
  14. if [ -z "${architecture:-}" ] ; then
  15. echo "*** No architecture defined. Consider running it with matrix configuration. ***"
  16. architecture="$(dpkg-architecture -qDEB_HOST_ARCH)"
  17. echo "*** Falling back to default, using host architecture ${architecture}. ***"
  18. fi
  19. if [ -z "${REPOSITORY:-}" ] ; then
  20. REPOSITORY='/srv/repository'
  21. fi
  22. }
  23. clean_workspace() {
  24. echo "*** The following files have been noticed in the workspace [$(pwd)]: ***"
  25. ls -la ./
  26. # echo "*** Cleaning workspace in $(pwd) to make sure we're building from scratch. ***"
  27. # rm -f ./* || true
  28. }
  29. # make sure we don't leave files for next run
  30. bailout() {
  31. [ -n "${1:-}" ] && EXIT="${1}" || EXIT=0
  32. [ -n "${2:-}" ] && echo "$2" >&2
  33. # only relevant when not using the "ArtifactDeployer Plugin"
  34. if [ -n "${sources:-}" ] && [ "${sources:-}" != "unset" ] ; then
  35. echo "*** Removing sources file. ***"
  36. rm -f "${sources}/"*
  37. fi
  38. echo "*** Getting rid of files in $WORKSPACE/binaries/ to avoid problems in next run. ***"
  39. rm -f "$WORKSPACE"/binaries/*
  40. exit $EXIT
  41. }
  42. identify_package_name() {
  43. PACKAGE=${JOB_NAME%-binaries*}
  44. BINARY_PACKAGE=${PACKAGE%-test*}
  45. if [ -z "${PACKAGE:-}" ] ; then
  46. bailout 1 "Error: could not identify Debian package name based on job name ${JOB_NAME:-}."
  47. else
  48. echo "*** Building binary package $BINARY_PACKAGE ***"
  49. fi
  50. }
  51. set_base_path() {
  52. # when BASE_PATH is set in the build step then don't assume a default,
  53. # this is useful when building on slave nodes, being used like:
  54. # export BASE_PATH="$WORKSPACE/${JOB_NAME%-binaries/*}-source/"
  55. if [ -n "${BASE_PATH:-}" ] ; then
  56. echo "*** Using provided ${BASE_PATH} as BASE_PATH ***"
  57. else
  58. echo "*** No BASE_PATH set. ***"
  59. if [ -z "${distribution:-}" ]; then
  60. BASE_PATH="${JENKINS_HOME}/userContent/${PACKAGE}-source/"
  61. echo "*** No BASE_PATH set but \$distribution is set, using $BASE_PATH as BASE_PATH ***"
  62. else
  63. BASE_PATH="${JENKINS_HOME}/userContent/${PACKAGE}-source/distribution=${distribution}/"
  64. echo "*** Neither BASE_PATH nor \$distribution set, using $BASE_PATH as BASE_PATH ***"
  65. fi
  66. fi
  67. }
  68. build_info() {
  69. if [ -n "${REPOS:-}" ] ; then
  70. echo "*** Using supplied repository name $REPOS ***"
  71. else
  72. REPOS="${JOB_NAME%-binaries*}"
  73. if [ -z "${distribution:-}" ]; then
  74. echo "*** No repository supplied, using repository name $REPOS ***"
  75. else
  76. REPOS="${REPOS}-${distribution}"
  77. echo "*** No repository supplied but distribution has been set, using repository name $REPOS ***"
  78. fi
  79. fi
  80. }
  81. identify_sourcefile() {
  82. if [ -n "${sources:-}" ]; then
  83. echo "*** Variable \$sources set. Consider switching to ArtifactDeployer plugin setup. ***"
  84. if [ -z "${distribution:-}" ]; then
  85. sourcefile=$(echo "${sources}/"*.dsc)
  86. else
  87. sourcefile=$(echo "${sources}/distribution=${distribution}/"*.dsc)
  88. fi
  89. if [ "$sourcefile" = 'sources/*.dsc' ] ; then
  90. bailout 1 "Error: no sourcefile (*.dsc) found. Exiting."
  91. fi
  92. case "$sourcefile" in
  93. *\ *) echo "*** Multiple source files (*.dsc) present in $(pwd): ***"
  94. ls -la "${sources}/"
  95. bailout 1 "Error: Please re-run source job to force clean rebuild."
  96. ;;
  97. esac
  98. p="$(basename $sourcefile .dsc)"
  99. newest_version="${p#*_}"
  100. else
  101. sources="unset"
  102. echo "*** Identifying newest package version ***"
  103. newest_version="0"
  104. for file in "${BASE_PATH}/"*.dsc ; do
  105. SOURCE_PACKAGE="$(awk '/^Source: / {print $2}' $file)"
  106. p="$(basename $file .dsc)"
  107. if [ "$p" = '*' ] ; then
  108. bailout 1 "Error: No source package found (forgot to configure source files deployment?)"
  109. fi
  110. cur_version="${p#*_}"
  111. if dpkg --compare-versions "${cur_version}" gt "${newest_version}" ; then
  112. newest_version="${cur_version}"
  113. else
  114. base_version="${cur_version}"
  115. fi
  116. done
  117. echo "*** Found package version $newest_version ***"
  118. sourcefile="${BASE_PATH}/${SOURCE_PACKAGE}"_*"${newest_version}".dsc
  119. fi
  120. echo "*** Using $sourcefile (version: ${newest_version}) [sources: $sources]"
  121. }
  122. dist_and_arch_settings() {
  123. if [ -z "${distribution:-}" ]; then
  124. echo "*** No distribution set, using sid for base.cow if it does not exist yet. ***"
  125. COWBUILDER_DIST="sid"
  126. else
  127. echo "*** Using cowbuilder base for distribution ${distribution} ***"
  128. DIST="-${distribution}"
  129. COWBUILDER_DIST="${distribution}"
  130. fi
  131. if [ -z "${architecture:-}" ] || [ "${architecture:-}" = "all" ] ; then
  132. echo "*** No architecture set or architecture set to 'all', using system arch for cowbuilder ***"
  133. ARCH="$(dpkg-architecture -qDEB_HOST_ARCH)"
  134. BASE="/var/cache/pbuilder/base${DIST:-}.cow"
  135. else
  136. echo "*** Using cowbuilder base for architecture ${architecture} ***"
  137. ARCH="${architecture}"
  138. BASE="/var/cache/pbuilder/base${DIST:-}-${architecture}.cow"
  139. fi
  140. }
  141. cowbuilder_init() {
  142. if [ ! -d "${BASE}" ]; then
  143. echo "*** Creating cowbuilder base $BASE for arch $ARCH and distribution $COWBUILDER_DIST ***"
  144. sudo cowbuilder --create --basepath "${BASE}" --distribution "${COWBUILDER_DIST}" \
  145. --debootstrapopts --arch --debootstrapopts "$ARCH" \
  146. --debootstrapopts --variant=buildd
  147. [ $? -eq 0 ] || bailout 1 "Error: Failed to create cowbuilder base ${BASE}."
  148. else
  149. echo "*** Updating cowbuilder cow base ***"
  150. sudo cowbuilder --update --basepath "${BASE}"
  151. [ $? -eq 0 ] || bailout 1 "Error: Failed to update cowbuilder base ${BASE}."
  152. fi
  153. }
  154. identify_build_type() {
  155. # -b -> binary-only build, no source files are to be built and/or distributed
  156. DEBBUILDOPTS="-b" # default
  157. SKIP_ARCH_BUILD=false # default
  158. if [ "${architecture:-}" = "all" ] ; then
  159. echo "*** \$architecture is set to 'all', skipping further identify_build_type checks. ***"
  160. echo "*** Consider setting \$architecture to amd64, i386,... instead. ***"
  161. return 0
  162. fi
  163. if [ -z "${MAIN_ARCHITECTURE:-}" ] ; then
  164. if [ "$(dpkg-architecture -qDEB_HOST_ARCH)" = "${architecture:-}" ] ; then
  165. echo "*** MAIN_ARCHITECTURE is unset. ***"
  166. echo "*** Host architecture matches \$architecture, using default ${DEBBUILDOPTS} buildoption ***"
  167. return 0
  168. fi
  169. else
  170. if [ "${MAIN_ARCHITECTURE:-}" = "${architecture:-}" ] ;then
  171. echo "*** MAIN_ARCHITECTURE matches architecture [${architecture}], using default ${DEBBUILDOPTS} buildoption ***"
  172. return 0
  173. else
  174. echo "*** MAIN_ARCHITECTURE does not match ${architecture:-}, continuing with identify_build_type ***"
  175. fi
  176. fi
  177. local TMPDIR=$(mktemp -d)
  178. cd "$TMPDIR"
  179. for file in ${BASE_PATH}/${SOURCE_PACKAGE}_*.tar.* ; do
  180. if tar atf "$file" 2>/dev/null | grep -q debian/control ; then
  181. # might be source/debian/control - so let's identify the path to debian/control
  182. local control_file=$(tar atf "$file" 2>/dev/null | grep 'debian/control$')
  183. tar axf "$file" "$control_file" || bailout 1 "Error while looking at debian/control in source archive."
  184. if grep -q '^Architecture: all' "$control_file" ; then
  185. if grep -q '^Architecture: any' "$control_file" ; then
  186. echo "*** Package provides arch 'all' + 'any', enabling -B buildoption for this architecture. ***"
  187. # -B -> binary-only build, limited to architecture dependent packages
  188. DEBBUILDOPTS="-B"
  189. break
  190. else
  191. # only "Architecture: all", so no arch specific packages since
  192. # we aren't building for $MAIN_ARCHITECTURE
  193. SKIP_ARCH_BUILD=true
  194. break
  195. fi
  196. fi
  197. fi
  198. done
  199. rm -rf "${TMPDIR}"
  200. }
  201. cowbuilder_run() {
  202. echo "*** cowbuilder build phase for arch $architecture ***"
  203. mkdir -p "$WORKSPACE"/binaries/
  204. # make sure we build arch specific packages only when necessary
  205. identify_build_type
  206. if $SKIP_ARCH_BUILD ; then
  207. bailout 0 "Nothing to do, architecture all binary packages only for non-primary architecture."
  208. fi
  209. case "$architecture" in
  210. i386)
  211. linux32 sudo cowbuilder --buildresult "$WORKSPACE"/binaries/ \
  212. --build $sourcefile \
  213. --basepath $BASE --debbuildopts "$DEBBUILDOPTS"
  214. [ $? -eq 0 ] || bailout 1 "Error: Failed to build with cowbuilder."
  215. ;;
  216. amd64|all)
  217. sudo cowbuilder --buildresult "$WORKSPACE"/binaries/ \
  218. --build $sourcefile \
  219. --basepath $BASE --debbuildopts "$DEBBUILDOPTS"
  220. [ $? -eq 0 ] || bailout 1 "Error: Failed to build with cowbuilder."
  221. ;;
  222. *)
  223. bailout 1 "Error: Unsupported architecture: $architecture"
  224. ;;
  225. esac
  226. }
  227. remove_packages() {
  228. echo "*** Removing previous versions from repository ***"
  229. for p in $(dcmd "${WORKSPACE}/binaries/"*"${newest_version}_${ARCH}.changes") ; do
  230. file="$(basename $p)"
  231. binpackage="${file%%_*}"
  232. binary_list="${binary_list:-} ${binpackage}"
  233. # note: "removesrc" would remove foreign arch files (of different builds)
  234. echo "*** Removing existing package ${binpackage} from repository ${REPOS} ***"
  235. ${SUDO_CMD:-} reprepro -v -b "${REPOSITORY}" --waitforlock 1000 remove "${REPOS}" "${binpackage}"
  236. done
  237. }
  238. remove_missing_binary_packages() {
  239. for p in $(${SUDO_CMD:-} reprepro -v -b "${REPOSITORY}" --waitforlock 1000 listmatched "${REPOS}" '*' | awk '{print $2}' | sort -u); do
  240. echo "$binary_list" | grep -q "$p" || missing_packages="${missing_packages:-} $p"
  241. done
  242. if echo "${missing_packages:-}" | grep -q '[a-z0-9]' ; then
  243. echo "*** Binary package(s) found, missing in build version: ${missing_packages:-} ***"
  244. for p in $missing_packages ; do
  245. echo "*** Removing $p from $REPOS to avoid out-of-date data ***"
  246. ${SUDO_CMD:-} reprepro -v -b "${REPOSITORY}" --waitforlock 1000 remove "${REPOS}" "${p}"
  247. done
  248. fi
  249. }
  250. reprepro_wrapper() {
  251. if ! [ -d "$REPOSITORY" ] ; then
  252. bailout 1 "Error: repository ${REPOSITORY} does not exist."
  253. fi
  254. remove_packages
  255. remove_missing_binary_packages
  256. archall=false
  257. case $architecture in
  258. all) archall=true
  259. architecture='*' # support as file expansion in reprepro cmdline
  260. ;;
  261. esac
  262. echo "*** Including binary packages in repository $REPOS ***"
  263. ${SUDO_CMD:-} reprepro -v -b "${REPOSITORY}" --waitforlock 1000 --ignore=wrongdistribution \
  264. include "${REPOS}" "${WORKSPACE}/binaries/"*"${newest_version}"_${architecture}.changes
  265. [ $? -eq 0 ] || bailout 1 "Error: Failed to include binary package in $REPOS repository."
  266. # include the source package only in *one* architecture, being amd64
  267. if [ "$architecture" = "amd64" ] || $archall ; then
  268. echo "*** Including source package in repository $REPOS ***"
  269. RC=0
  270. if ! ${SUDO_CMD:-} reprepro -v -b "${REPOSITORY}" --waitforlock 1000 --ignore=wrongdistribution \
  271. includedsc "${REPOS}" ${sourcefile} ; then
  272. RC=1
  273. # iff section/priority is empty then reprepro will complain
  274. # about "No section and no priority for" and error out in the
  275. # cmdline above, therefore we retry with -S and -P being set
  276. ${SUDO_CMD:-} reprepro -v -S unstable -P extra -b "${REPOSITORY}" --waitforlock 1000 \
  277. --ignore=wrongdistribution \
  278. includedsc "${REPOS}" ${sourcefile}
  279. RC=$?
  280. fi
  281. [ $RC -eq 0 ] || bailout 1 "Error: Failed to include source package in $REPOS repository."
  282. fi
  283. }
  284. trunk_release() {
  285. # setting TRUNK_RELEASE=true enables release-trunk repository,
  286. # to always get a copy of the package(s) to a central place
  287. if [ -n "${TRUNK_RELEASE:-}" ] ; then
  288. generate-reprepro-codename "$TRUNK_RELEASE"
  289. ${SUDO_CMD:-} reprepro -v -b "${REPOSITORY}" --waitforlock 1000 --ignore=wrongdistribution copymatched "$TRUNK_RELEASE" "$REPOS" '*'
  290. [ $? -eq 0 ] || bailout 1 "Error: Failed to copy packages from ${REPOS} to ${TRUNK_RELEASE}."
  291. fi
  292. }
  293. release_repos() {
  294. echo "*** Environment variable 'release' is set, running through release steps. ***"
  295. mkdir -p "${REPOSITORY}/incoming/${release}"
  296. mkdir -p "${REPOSITORY}/conf"
  297. if [ -n "${SUDO_CMD:-}" ] ; then
  298. ${SUDO_CMD:-} mkdir -p "${REPOSITORY}/incoming/${release}"
  299. ${SUDO_CMD:-} mkdir -p "${REPOSITORY}/conf"
  300. ${SUDO_CMD:-} chown -R "$(id -un)" "${REPOSITORY}/conf"
  301. ${SUDO_CMD:-} chown -R "$(id -un)" "${REPOSITORY}/incoming/${release}"
  302. fi
  303. cp "${WORKSPACE}/binaries/"* "${REPOSITORY}/incoming/${release}/"
  304. [ $? -eq 0 ] || bailout 1 "Error: Failed to copy binary packages to release directory."
  305. REPOSITORY=$REPOSITORY generate-reprepro-codename "${release}"
  306. if ! grep -q "^Name: $release$" "${REPOSITORY}/conf/incoming" 2>/dev/null ; then
  307. cat >> "${REPOSITORY}/conf/incoming" << EOF
  308. Name: $release
  309. IncomingDir: incoming/$release
  310. TempDir: tmp
  311. LogDir: log
  312. MorgueDir: ${REPOSITORY}/morgue
  313. Allow: unstable>$release
  314. Cleanup: unused_files on_deny on_error
  315. EOF
  316. fi
  317. ${SUDO_CMD:-} reprepro -v -b "${REPOSITORY}" processincoming "${release}"
  318. local RC=$?
  319. echo "*** Gettind rid of *.tar.* and *.dsc files in incoming directory to avoid data leakage. ***"
  320. rm -f ${REPOSITORY}/incoming/$release/*.tar.*
  321. rm -f ${REPOSITORY}/incoming/$release/*.dsc
  322. if [ $RC -ne 0 ] ; then
  323. bailout 1 "Error: Failed to execute processincoming for release ${release}."
  324. fi
  325. }
  326. deploy_to_releases() {
  327. if [ "${REMOTE_REPOS:-}" = "true" ] ; then
  328. echo "*** Config variable 'REMOTE_REPOS' is set, ignoring request to use local repository. ***"
  329. elif [ -n "${release:-}" ] && [ "$release" != "none" ] && [ "$release" != "trunk" ] ; then
  330. release_repos
  331. else
  332. reprepro_wrapper
  333. trunk_release
  334. fi
  335. }
  336. # make them available for the Jenkin's 'Archiving artifacts'
  337. binaries_to_workspace() {
  338. echo "*** Moving binaries files to workspace. ***"
  339. mv "${WORKSPACE}/binaries/"* "${WORKSPACE}/"
  340. rmdir "${WORKSPACE}/binaries/"
  341. }
  342. # main execution
  343. trap bailout 1 2 3 3 6 9 14 15
  344. checks_and_defaults
  345. clean_workspace
  346. identify_package_name
  347. set_base_path
  348. build_info
  349. identify_sourcefile
  350. dist_and_arch_settings
  351. cowbuilder_init
  352. cowbuilder_run
  353. deploy_to_releases
  354. binaries_to_workspace
  355. bailout 0
  356. # vim:foldmethod=marker ts=2 ft=sh ai expandtab sw=2