C++ Library containing a lot of needful things: Stack Trace, Command Line Parser, Resource Handling, Configuration Files, Unix Command Execution, Directories, Regular Expressions, Tokenizer, Function Trace, Standard Extensions.
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.

build-in-docker.sh 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. #! /bin/bash -e
  2. set -o errtrace
  3. # build and test everything in a fresh docker installation
  4. myarch=$(dpkg --print-architecture)
  5. if test "${arch}" = "amd64"; then
  6. myarch="amd64|i386"
  7. fi
  8. mode=
  9. img=
  10. repos=()
  11. keys=()
  12. dns=()
  13. envs=("-e LANG=${LANG}" "-e HOME=${HOME}" "-e TERM=xterm" "-e DEBIAN_FRONTEND=noninteractive" "-e DEBCONF_NONINTERACTIVE_SEEN=true")
  14. dirs=("-v $(pwd):/workdir" "-v ${HOME}/.gnupg:${HOME}/.gnupg")
  15. packages=()
  16. targets="all check distcheck"
  17. commands=()
  18. arch=$((which dpkg > /dev/null 2> /dev/null && dpkg --print-architecture) || echo amd64)
  19. host=
  20. flags=()
  21. wait=0
  22. if test -e ./build-in-docker.conf; then
  23. # you can preconfigure the variables in file build-in-docker.conf
  24. # if you do so, add the file to EXTRA_DIST in makefile.am
  25. source ./build-in-docker.conf
  26. fi
  27. while test $# -gt 0; do
  28. case "$1" in
  29. (-h|--help)
  30. echo "$0 [OPTIONS]"
  31. echo
  32. echo "OPTIONS:"
  33. echo
  34. echo " -h, --help show this help"
  35. echo " -m, --mode <type> mode: deb, rpm, win, default: ${mode}"
  36. echo " -i, --image <image> use given docker image instead of ${img}"
  37. echo " -a, --arch <arch> build for given hardware architecture"
  38. echo " -t, --targets targets specify build targets, default: ${targets}"
  39. echo " --host <target-arch> host for cross compiling, e.g. i686-w64-mingw32"
  40. echo " -f, --flag <flag> add flag to ./bootstrap.sh or ./configure"
  41. echo " -r, --repo <url> add given apt repository"
  42. echo " -k, --key <url> add public key from url"
  43. echo " -n, --dns <ip> add ip as dns server"
  44. echo " -e, --env <var>=<val> set environment variable in docker"
  45. echo " -d, --dir <dir> access given directory read only"
  46. echo " -p, --package <pkg> install extra debian packages"
  47. echo " -c, --cmd <command> execute commands as root in docker"
  48. echo " -w, --wait on error keep docker container and wait for enter"
  49. echo
  50. echo " The option -i must be after -m, because mode sets a new default image"
  51. echo " The option -m must be after -t, because mode may be auto detected from targets"
  52. echo " The option -m must be after -h, because mode may set a host"
  53. echo " If target is either deb or rpm, mode is set to the same value"
  54. echo " If target is win, host is set to i686-w64-mingw32"
  55. echo
  56. echo " The options -r -k -e -d -p -c can be repeated several times."
  57. echo
  58. echo " The options -r -p -c allow an if-then-else contruct"
  59. echo " depending on the operating system:"
  60. echo " <os>:::<A>:::<B>"
  61. echo " <os>:::<A>"
  62. echo " Read as: On linux type <os> use <A> else use <B>"
  63. echo " That means: If the distributer ID or codename in lsb_release"
  64. echo " matches regular expression <os>, then <A> is replaced, else <B> is replaced."
  65. echo " The three colons are for splitting <os> from <A> and <B> part."
  66. echo " E.g.: Install package curl on wheezy and npm on olter systems:"
  67. echo " $0 -p Debian|precise:::curl:::npm"
  68. echo
  69. echo "EXAMPLE:"
  70. echo
  71. echo "$0 -i mwaeckerlin/ubuntu:trusty-i386 \\"
  72. echo " -t deb \\"
  73. echo " -e ANDROID_HOME=/opt/local/android \\"
  74. echo " -d /opt/local/android \\"
  75. echo " -r universe \\"
  76. echo " -r https://repository.mrw.sh \\"
  77. echo " -k https://repository.mrw.sh/PublicKey \\"
  78. echo " -p mrw-c++"
  79. echo
  80. exit 0
  81. ;;
  82. (-m|--mode)
  83. shift;
  84. mode="$1"
  85. if test -z "$img"; then
  86. case "$mode" in
  87. (deb|apt) img="mwaeckerlin/debbuildenv";;
  88. (rpm|zypper) img="opensuse:latest";;
  89. (yum) img="centos:latest";;
  90. (dnf) img="fedora:latest";;
  91. (win)
  92. img="mwaeckerlin/debbuildenv"; host="${host:---host=i686-w64-mingw32}"
  93. targets="all install"
  94. flags+=("--prefix=/workdir/usr")
  95. packages+=("mingw-w64")
  96. ;;
  97. (*)
  98. echo "**** ERROR: unknown mode '$1', try --help" 1>&2
  99. exit 1
  100. ;;
  101. esac
  102. fi
  103. ;;
  104. (-i|--image) shift;
  105. img="$1"
  106. ;;
  107. (-a|--arch) shift;
  108. arch="$1"
  109. ;;
  110. (-t|--targets) shift;
  111. targets="$1"
  112. if test "$1" = "deb" -o "$1" = "rpm"; then
  113. # set mode to same value
  114. set -- "-m" "$@"
  115. continue
  116. fi
  117. ;;
  118. (--host) shift;
  119. host="--host=$1"
  120. ;;
  121. (-f|--flag) shift;
  122. flags+=("$1")
  123. ;;
  124. (-r|--repo) shift;
  125. echo "OPTION: $1"
  126. repos+=("$1")
  127. ;;
  128. (-k|--key) shift;
  129. keys+=("$1")
  130. ;;
  131. (-e|--env) shift;
  132. envs+=("-e $1")
  133. ;;
  134. (-n|--dns) shift;
  135. dns+=("--dns $1")
  136. ;;
  137. (-d|--dirs) shift;
  138. dirs+=("-v $1:$1:ro")
  139. ;;
  140. (-p|--package) shift;
  141. packages+=("$1")
  142. ;;
  143. (-c|--cmd) shift;
  144. commands+=("$1")
  145. ;;
  146. (-w|--wait)
  147. wait=1
  148. ;;
  149. (*)
  150. echo "**** ERROR: unknown option '$1', try --help" 1>&2
  151. exit 1
  152. ;;
  153. esac
  154. if test $# -eq 0; then
  155. echo "**** ERROR: missing value, try --help" 2>61
  156. exit 1
  157. fi
  158. shift
  159. done
  160. function traperror() {
  161. set +x
  162. local DOCKER_ID="$1"
  163. local err=($2) # error status
  164. local line="$3" # LINENO
  165. local linecallfunc="$4"
  166. local command="$5"
  167. local funcstack="$6"
  168. for e in ${err[@]}; do
  169. if test -n "$e" -a "$e" != "0"; then
  170. echo "<---"
  171. echo "ERROR: line $line - command '$command' exited with status: $e (${err[@]})"
  172. if [ "${funcstack}" != "main" -o "$linecallfunc" != "0" ]; then
  173. echo -n " ... Error at ${funcstack} "
  174. if [ "$linecallfunc" != "" ]; then
  175. echo -n "called at line $linecallfunc"
  176. fi
  177. echo
  178. fi
  179. if [ "$wait" -eq 1 ]; then
  180. echo " ... now you can access the docker container as root or user:"
  181. echo " docker exec -it ${DOCKER_ID} bash"
  182. echo " docker exec -u $(id -u) -it ${DOCKER_ID} bash"
  183. echo -n " ... press enter to cleanup: "
  184. read
  185. fi
  186. echo -n " ... cleanup docker: "
  187. docker stop "${DOCKER_ID}" || true
  188. docker rm "${DOCKER_ID}"
  189. echo "returning status: $e"
  190. echo "--->"
  191. exit $e
  192. fi
  193. done
  194. echo -n "SUCCESS ... cleanup docker: "
  195. docker rm -f "${DOCKER_ID}"
  196. exit 0
  197. }
  198. function ifthenelse() {
  199. arg="$1"
  200. shift
  201. cmd="$*"
  202. DISTRIBUTOR=$(docker exec ${DOCKER_ID} lsb_release -si | sed 's, .*,,;s,.*,\L&,g')
  203. CODENAME=$(docker exec ${DOCKER_ID} lsb_release -cs)
  204. ARCH=$((docker exec ${DOCKER_ID} which dpkg > /dev/null 2> /dev/null && docker exec ${DOCKER_ID} dpkg --print-architecture) || echo amd64)
  205. case "$DISTRIBUTOR" in
  206. (opensuse) # code name may be not available, then set leap or tumbleweed
  207. if test "$CODENAME" = "n/a"; then
  208. CODENAME=$(docker exec ${DOCKER_ID} lsb_release -ds | sed "s,\($(docker exec ${DOCKER_ID} lsb_release -si | sed 's, ,\\|,g')\) *,,"';s, .*,,g;s,",,g;s,.*,\L&,g')
  209. fi
  210. ;;
  211. (fedora|mageia) # numeric code name
  212. CODENAME=$(docker exec ${DOCKER_ID} lsb_release -rs)
  213. ;;
  214. (centos) # only look at major number in centos
  215. CODENAME=$(docker exec ${DOCKER_ID} lsb_release -rs | sed 's,\..*,,')
  216. ;;
  217. esac
  218. if test "${arg/:::/}" = "${arg}"; then
  219. cmd_tmp="${cmd//ARG/${arg//@DISTRIBUTOR@/${DISTRIBUTOR}}}"
  220. docker exec ${DOCKER_ID} bash -c "${cmd_tmp//@CODENAME@/${CODENAME}}"
  221. else
  222. os="${arg%%:::*}"
  223. thenpart="${arg#*:::}"
  224. elsepart=
  225. if test "${thenpart/:::/}" != "${thenpart}"; then
  226. elsepart="${thenpart##*:::}"
  227. thenpart="${thenpart%%:::*}"
  228. fi
  229. if [[ "${DISTRIBUTOR}-${CODENAME}-${ARCH}" =~ ${os} ]]; then
  230. if test -n "${thenpart}"; then
  231. cmd_tmp="${cmd//ARG/${thenpart//@DISTRIBUTOR@/${DISTRIBUTOR}}}"
  232. docker exec ${DOCKER_ID} bash -c "${cmd_tmp//@CODENAME@/${CODENAME}}"
  233. fi
  234. else
  235. if test -n "${elsepart}"; then
  236. cmd_tmp="${cmd//ARG/${elsepart//@DISTRIBUTOR@/${DISTRIBUTOR}}}"
  237. docker exec ${DOCKER_ID} bash -c "${cmd_tmp//@CODENAME@/${CODENAME}}"
  238. fi
  239. fi
  240. fi
  241. }
  242. set -x
  243. if test -z "$img"; then
  244. img="mwaeckerlin/debbuildenv"
  245. fi
  246. docker pull $img
  247. DOCKER_ID=$(docker create ${dns[@]} ${dirs[@]} ${envs[@]} -w /workdir $img sleep infinity)
  248. trap 'traperror '"${DOCKER_ID}"' "$? ${PIPESTATUS[@]}" $LINENO $BASH_LINENO "$BASH_COMMAND" "${FUNCNAME[@]}" "${FUNCTION}"' SIGINT INT TERM EXIT
  249. if ! [[ $arch =~ $myarch ]]; then
  250. docker cp "/usr/bin/qemu-${arch}-static" "${DOCKER_ID}:/usr/bin/qemu-${arch}-static"
  251. fi
  252. docker start "${DOCKER_ID}"
  253. if ! docker exec ${DOCKER_ID} getent group $(id -g) > /dev/null 2>&1; then
  254. docker exec ${DOCKER_ID} groupadd -g $(id -g) $(id -gn)
  255. fi
  256. if ! docker exec ${DOCKER_ID} getent passwd $(id -u) > /dev/null 2>&1; then
  257. docker exec ${DOCKER_ID} useradd -m -u $(id -u) -g $(id -g) -d"${HOME}" $(id -un)
  258. fi
  259. docker exec ${DOCKER_ID} chown $(id -u):$(id -g) "${HOME}"
  260. if test -z "$mode"; then
  261. case "$targets" in
  262. (*deb*) mode=deb;;
  263. (*rpm*) mode=rpm;;
  264. (*) case "$img" in
  265. (*deb*|*ubuntu*|*debian*|*mint*) mode=deb;;
  266. (*rpm*|*fedora*|*centos*|*mageia*) mode=rpm;;
  267. (*mingw*|*win*) mode=win;;
  268. (*) mode=deb;;
  269. esac;;
  270. esac
  271. fi
  272. case "$mode" in
  273. (deb|apt|win)
  274. OPTIONS='-o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confnew -y --force-yes --no-install-suggests --no-install-recommends'
  275. PREVENT='libpam-systemd policykit.* colord dconf-service'
  276. docker exec ${DOCKER_ID} apt-get update ${OPTIONS}
  277. docker exec ${DOCKER_ID} apt-mark hold ${PREVENT}
  278. #docker exec ${DOCKER_ID} apt-get upgrade ${OPTIONS}
  279. docker exec ${DOCKER_ID} apt-get install ${OPTIONS} ${PREVENT// /- }- python-software-properties software-properties-common apt-transport-https dpkg-dev lsb-release wget || \
  280. docker exec ${DOCKER_ID} apt-get install ${OPTIONS} ${PREVENT// /- }- software-properties-common apt-transport-https dpkg-dev lsb-release wget || \
  281. docker exec ${DOCKER_ID} apt-get install ${OPTIONS} ${PREVENT// /- }- python-software-properties apt-transport-https dpkg-dev lsb-release wget;
  282. if [[ "${img}" =~ "ubuntu" ]]; then
  283. docker exec ${DOCKER_ID} apt-get install ${OPTIONS} ${PREVENT// /- }- locales
  284. docker exec ${DOCKER_ID} locale-gen ${LANG}
  285. docker exec ${DOCKER_ID} update-locale LANG=${LANG}
  286. fi
  287. for f in ${PREVENT}; do
  288. docker exec ${DOCKER_ID} bash -c "echo 'Package: ${f}' >> /etc/apt/preferences"
  289. docker exec ${DOCKER_ID} bash -c "echo 'Pin-Priority: -100' >> /etc/apt/preferences"
  290. docker exec ${DOCKER_ID} bash -c "echo >> /etc/apt/preferences"
  291. done
  292. if test -n "${keys[*]}"; then # fix dependency bug in cosmic and stretch
  293. docker exec ${DOCKER_ID} apt-get install ${OPTIONS} ${PREVENT// /- }- gnupg
  294. for key in "${keys[@]}"; do
  295. wget -O- "$key" \
  296. | docker exec -i ${DOCKER_ID} apt-key add -
  297. done
  298. fi
  299. for repo in "${repos[@]}"; do
  300. ifthenelse "${repo}" "apt-add-repository 'ARG'"
  301. done
  302. docker exec ${DOCKER_ID} apt-get update ${OPTIONS}
  303. for package in "${packages[@]}"; do
  304. ifthenelse "${package}" "apt-get install ${OPTIONS} ${PREVENT// /- }- ARG"
  305. done
  306. for command in "${commands[@]}"; do
  307. ifthenelse "${command}" "ARG"
  308. done
  309. docker exec ${DOCKER_ID} ./resolve-debbuilddeps.sh
  310. ;;
  311. (rpm|yum|dnf|zypper|urpmi)
  312. if [[ "$img" =~ "centos" ]]; then
  313. docker exec ${DOCKER_ID} yum install -y redhat-lsb epel-release
  314. docker exec -i ${DOCKER_ID} bash -c 'cat > /etc/yum.repos.d/wandisco-svn.repo' <<EOF
  315. [WandiscoSVN]
  316. name=Wandisco SVN Repo
  317. EOF
  318. docker exec -i ${DOCKER_ID} bash -c 'echo "baseurl=http://opensource.wandisco.com/centos/$(lsb_release -sr | sed '"'"'s,[^0-9].*,,'"'"')/svn-'$(svn --version | head -1 | sed 's,[^0-9]*\([0-9]\+\.[0-9]\+\).*,\1,')'/RPMS/$(uname -i)/" >> /etc/yum.repos.d/wandisco-svn.repo'
  319. docker exec -i ${DOCKER_ID} bash -c 'cat >> /etc/yum.repos.d/wandisco-svn.repo' <<EOF
  320. enabled=1
  321. gpgcheck=0
  322. EOF
  323. fi
  324. INSTALL_TOOL=$((docker exec ${DOCKER_ID} test -x /usr/bin/zypper && echo zypper install -y) || (docker exec ${DOCKER_ID} test -x /usr/bin/dnf && echo dnf install -y) || (docker exec ${DOCKER_ID} test -x /usr/bin/yum && echo yum install -y) || (docker exec ${DOCKER_ID} test -x /usr/sbin/urpmi && echo urpmi --auto))
  325. if test "$INSTALL_TOOL" = "urpmi --auto" -o "$INSTALL_TOOL" = "zypper install -y"; then
  326. LSB_RELEASE=lsb-release
  327. else
  328. LSB_RELEASE=/usr/bin/lsb_release
  329. fi
  330. docker exec ${DOCKER_ID} ${INSTALL_TOOL} rpm-build automake libtool subversion gcc-c++ pkgconfig wget $LSB_RELEASE
  331. if docker exec ${DOCKER_ID} test -x /usr/bin/dnf; then
  332. docker exec ${DOCKER_ID} dnf install -y 'dnf-command(config-manager)'
  333. fi
  334. i=0
  335. for key in "${keys[@]}"; do
  336. docker exec -i ${DOCKER_ID} wget -Orpm-key "$key"
  337. docker exec -i ${DOCKER_ID} rpm --import rpm-key
  338. docker exec -i ${DOCKER_ID} rm rpm-key
  339. done
  340. for repo in "${repos[@]}"; do
  341. INSTALL_REPO=$((docker exec ${DOCKER_ID} test -x /usr/bin/zypper && echo zypper ar) || (docker exec ${DOCKER_ID} test -x /usr/bin/dnf && echo dnf config-manager --add-repo) || (docker exec ${DOCKER_ID} test -x /usr/bin/yum && echo yum-config-manager --add-repo) || (docker exec ${DOCKER_ID} test -x /usr/sbin/urpmi && echo false))
  342. ifthenelse "${repo}" "${INSTALL_REPO} ARG"
  343. ((++i))
  344. done
  345. for package in "${packages[@]}"; do
  346. ifthenelse "${package}" "${INSTALL_TOOL} ARG"
  347. done
  348. for command in "${commands[@]}"; do
  349. ifthenelse "${command}" "ARG"
  350. done
  351. docker exec ${DOCKER_ID} ./resolve-rpmbuilddeps.sh
  352. ;;
  353. esac
  354. FLAGS=()
  355. for f in "${flags[@]}"; do
  356. FLAGS+=($(ifthenelse "$f" "echo 'ARG'"))
  357. done
  358. docker exec -u $(id -u):$(id -g) ${DOCKER_ID} ./bootstrap.sh -t "${targets}" ${host} "${FLAGS[@]}"
  359. # last check: try to install built deb or rpm files (if not already cleaned up)
  360. # not supported in trusty and jessie
  361. if test "$mode" = deb -a "${img//trusty/}" = "${img}" -a "${img//jessie/}" = "${img}"; then
  362. if test "${targets//deb/}" != "${targets}" && ls *.deb > /dev/null 2> /dev/null; then
  363. docker exec ${DOCKER_ID} bash -c "apt-get install ${OPTIONS} ${PREVENT// /- }- /workdir/*.deb"
  364. fi
  365. fi
  366. if test "$mode" = rpm -a "${targets//rpm/}" != "${targets}"; then
  367. if ls *.rpm > /dev/null 2> /dev/null; then
  368. docker exec ${DOCKER_ID} bash -c "${INSTALL_TOOL} /workdir/*.rpm"
  369. fi
  370. fi
  371. echo "done."