2 # Copyright (C) The Arvados Authors. All rights reserved.
4 # SPDX-License-Identifier: AGPL-3.0
6 read -rd "\000" helpmessage <<EOF
7 $(basename $0): Orchestrate run-build-packages.sh for one target
10 WORKSPACE=/path/to/arvados $(basename $0) --target <target> [options]
13 Distribution to build packages for
15 Build command to execute (default: use built-in Docker image command)
17 Run package install test script "test-packages-[target].sh"
19 Output debug information (default: false)
20 --only-build <package>
21 Build only a specific package
23 Test only a specific package
25 Build a specific architecture (amd64 or arm64, defaults to native architecture)
27 Build even if the package exists upstream or if it has already been
30 Test even if there is no new untested package
31 --build-version <string>
32 Version to build (default:
33 \$ARVADOS_BUILDING_VERSION-\$ARVADOS_BUILDING_ITERATION or
34 0.1.timestamp.commithash)
36 Don't try to build Docker images
38 WORKSPACE=path Path to the Arvados source tree to build packages from
44 if ! [[ -n "$WORKSPACE" ]]; then
45 echo >&2 "$helpmessage"
47 echo >&2 "Error: WORKSPACE environment variable not set"
52 if ! [[ -d "$WORKSPACE" ]]; then
53 echo >&2 "$helpmessage"
55 echo >&2 "Error: $WORKSPACE is not a directory"
60 PARSEDOPTS=$(getopt --name "$0" --longoptions \
61 help,debug,test-packages,target:,command:,only-test:,force-test,only-build:,force-build,arch:,build-version:,skip-docker-build \
72 eval set -- "$PARSEDOPTS"
73 while [ $# -gt 0 ]; do
76 echo >&2 "$helpmessage"
95 ONLY_BUILD="$2"; shift
111 if [[ -z "$2" ]]; then
113 elif ! [[ "$2" =~ (.*)-(.*) ]]; then
114 echo >&2 "FATAL: --build-version '$2' does not include an iteration. Try '${2}-1'?"
116 elif ! [[ "$2" =~ ^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+|)(~rc[0-9]+|~dev[0-9]+|)-[0-9]+$ ]]; then
117 echo >&2 "FATAL: --build-version '$2' is invalid, must match pattern ^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+|)(~rc[0-9]+|~dev[0-9]+|)-[0-9]+$"
120 [[ "$2" =~ (.*)-(.*) ]]
121 ARVADOS_BUILDING_VERSION="${BASH_REMATCH[1]}"
122 ARVADOS_BUILDING_ITERATION="${BASH_REMATCH[2]}"
130 if [ $# -gt 1 ]; then
131 echo >&2 "$0: unrecognized argument '$2'. Try: $0 --help"
140 orig_umask="$(umask)"
142 if [[ -z "$TARGET" ]]; then
143 echo "FATAL: --target must be specified" >&2
145 elif [[ ! -d "$WORKSPACE/build/package-build-dockerfiles/$TARGET" ]]; then
146 echo "FATAL: unknown build target '$TARGET'" >&2
150 if [[ -n "$ARVADOS_BUILDING_VERSION" ]]; then
151 echo "build version='$ARVADOS_BUILDING_VERSION', package iteration='$ARVADOS_BUILDING_ITERATION'"
154 if [[ -n "$test_packages" ]]; then
155 # Packages are built world-readable, so package indexes should be too,
156 # especially because since 2022 apt uses an unprivileged user `_apt` to
157 # retrieve everything. Ensure it has permissions to read the packages
158 # when mounted as a volume inside the Docker container.
159 chmod a+rx "$WORKSPACE" "$WORKSPACE/packages" "$WORKSPACE/packages/$TARGET"
161 if [[ -n "$(find $WORKSPACE/packages/$TARGET -name '*.rpm')" ]] ; then
162 CREATEREPO="$(command -v createrepo createrepo_c | tail -n1)"
163 if [[ -z "$CREATEREPO" ]]; then
165 echo >&2 "Error: please install createrepo. E.g. sudo apt install createrepo-c"
169 "$CREATEREPO" $WORKSPACE/packages/$TARGET
172 if [[ -n "$(find $WORKSPACE/packages/$TARGET -name '*.deb')" ]] ; then
174 /usr/bin/which dpkg-scanpackages >/dev/null
175 if [[ "$?" != "0" ]]; then
177 echo >&2 "Error: please install dpkg-dev. E.g. sudo apt-get install dpkg-dev"
181 /usr/bin/which apt-ftparchive >/dev/null
182 if [[ "$?" != "0" ]]; then
184 echo >&2 "Error: please install apt-utils. E.g. sudo apt-get install apt-utils"
189 (cd $WORKSPACE/packages/$TARGET
190 dpkg-scanpackages --multiversion . 2> >(grep -v 'warning' 1>&2) | tee Packages | gzip -c > Packages.gz
191 apt-ftparchive -o APT::FTPArchive::Release::Origin=Arvados release . > Release
195 COMMAND="/jenkins/package-testing/test-packages-$TARGET.sh"
196 IMAGE="arvados/package-test:$TARGET"
199 IMAGE="arvados/build:$TARGET"
200 if [[ "$COMMAND" != "" ]]; then
201 COMMAND="/usr/local/rvm/bin/rvm-exec default bash /jenkins/$COMMAND --target $TARGET$DEBUG"
205 JENKINS_DIR=$(dirname "$(readlink -e "$0")")
207 if [[ "$SKIP_DOCKER_BUILD" != 1 ]] ; then
208 if [[ -n "$test_packages" ]]; then
209 pushd "$JENKINS_DIR/package-test-dockerfiles"
210 make "$TARGET/generated"
212 pushd "$JENKINS_DIR/package-build-dockerfiles"
213 make "$TARGET/generated"
216 GOVERSION=$(grep 'const goversion =' $WORKSPACE/lib/install/deps.go |awk -F'"' '{print $2}')
220 time docker build --tag "$IMAGE" \
221 --build-arg HOSTTYPE=$HOSTTYPE \
222 --build-arg BRANCH=$(git rev-parse HEAD) \
223 --build-arg GOVERSION=$GOVERSION --no-cache .
227 if test -z "$packages" ; then
228 packages="arvados-api-server
231 arvados-dispatch-cloud
233 arvados-docker-cleaner
242 crunch-dispatch-local
243 crunch-dispatch-slurm
253 python3-arvados-cwl-runner
255 python3-arvados-python-client
256 python3-arvados-user-activity
257 python3-crunchstat-summary
265 mkdir -p "$WORKSPACE/services/api/vendor/cache-$TARGET"
268 -v "$JENKINS_DIR:/jenkins"
269 -v "$WORKSPACE:/arvados"
270 -v /arvados/services/api/vendor/bundle
271 -v "$WORKSPACE/services/api/vendor/cache-$TARGET:/arvados/services/api/vendor/cache"
274 if [[ -n "$test_packages" ]]; then
275 for p in $packages ; do
276 if [[ -n "$ONLY_BUILD" ]] && [[ "$p" != "$ONLY_BUILD" ]]; then
279 if [[ -e "${WORKSPACE}/packages/.last_test_${TARGET}" ]] && [[ -z "$FORCE_TEST" ]]; then
280 MATCH=`find ${WORKSPACE}/packages/ -newer ${WORKSPACE}/packages/.last_test_${TARGET} -regex .*${TARGET}/$p.*`
281 if [[ "$MATCH" == "" ]]; then
282 # No new package has been built that needs testing
283 echo "Skipping $p test because no new package was built since the last test."
287 # If we're testing all packages, we should not error out on packages that don't exist.
288 # If we are testing one specific package only (i.e. --only-test was given), we should
289 # error out if that package does not exist.
290 if [[ -z "$testing_one_package" ]]; then
291 MATCH=`find ${WORKSPACE}/packages/ -regextype posix-extended -regex .*${TARGET}/$p.*\\(deb\\|rpm\\)`
292 if [[ "$MATCH" == "" ]]; then
293 # No new package has been built that needs testing
294 echo "Skipping $p test because no package file is available to test."
299 echo "START: $p test on $IMAGE" >&2
302 "${docker_volume_args[@]}" \
303 --env ARVADOS_DEBUG=$ARVADOS_DEBUG \
304 --env "TARGET=$TARGET" \
305 --env "WORKSPACE=/arvados" \
308 echo "OK: $p test on $IMAGE succeeded" >&2
311 package_fails="$package_fails $p"
312 echo "ERROR: $p test on $IMAGE failed with exit status $FINAL_EXITCODE" >&2
316 if [[ "$FINAL_EXITCODE" == "0" ]]; then
317 touch ${WORKSPACE}/packages/.last_test_${TARGET}
321 echo "START: build packages on $IMAGE" >&2
322 # Move existing packages and other files into the processed/ subdirectory
323 if [[ ! -e "${WORKSPACE}/packages/${TARGET}/processed" ]]; then
324 mkdir -p "${WORKSPACE}/packages/${TARGET}/processed"
327 mv -f ${WORKSPACE}/packages/${TARGET}/* ${WORKSPACE}/packages/${TARGET}/processed/ 2>/dev/null
329 # give bundle (almost) all the cores. See also the MAKE env var that is passed into the
330 # docker run command below.
331 # Cf. https://build.betterup.com/one-weird-trick-that-will-speed-up-your-bundle-install/
332 tmpfile=$(mktemp /tmp/run-build-packages-one-target.XXXXXX)
333 cores=$(let a=$(grep -c processor /proc/cpuinfo )-1; echo $a)
334 printf -- "---\nBUNDLE_JOBS: \"$cores\"" > $tmpfile
338 "${docker_volume_args[@]}" \
339 -v $tmpfile:/root/.bundle/config \
340 --env ARVADOS_BUILDING_VERSION="$ARVADOS_BUILDING_VERSION" \
341 --env ARVADOS_BUILDING_ITERATION="$ARVADOS_BUILDING_ITERATION" \
342 --env ARVADOS_DEBUG=$ARVADOS_DEBUG \
343 --env "ONLY_BUILD=$ONLY_BUILD" \
344 --env "FORCE_BUILD=$FORCE_BUILD" \
346 --env "MAKE=make --jobs $cores" \
350 echo "OK: build packages on $IMAGE succeeded" >&2
353 echo "ERROR: build packages on $IMAGE failed with exit status $FINAL_EXITCODE" >&2
355 # Clean up the bundle config file
359 if test -n "$package_fails" ; then
360 echo "Failed package tests:$package_fails" >&2