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="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"
211 pushd "$JENKINS_DIR/package-build-dockerfiles"
212 make "$TARGET/generated"
215 GOVERSION=$(grep 'const goversion =' $WORKSPACE/lib/install/deps.go |awk -F'"' '{print $2}')
219 time docker build --tag "$IMAGE" \
220 --build-arg HOSTTYPE=$HOSTTYPE \
221 --build-arg BRANCH=$(git rev-parse HEAD) \
222 --build-arg GOVERSION=$GOVERSION --no-cache .
226 if test -z "$packages" ; then
227 packages="arvados-api-server
230 arvados-dispatch-cloud
232 arvados-docker-cleaner
240 crunch-dispatch-local
241 crunch-dispatch-slurm
251 python3-arvados-cwl-runner
253 python3-arvados-python-client
254 python3-arvados-user-activity
255 python3-crunchstat-summary"
262 mkdir -p "$WORKSPACE/services/api/vendor/cache-$TARGET"
265 -v "$JENKINS_DIR:/jenkins"
266 -v "$WORKSPACE:/arvados"
267 --tmpfs /arvados/services/api/.bundle:rw,noexec,nosuid,size=1m
268 --tmpfs /arvados/services/api/vendor:rw,exec,nosuid,size=1g
269 -v "$WORKSPACE/services/api/vendor/cache-$TARGET:/arvados/services/api/vendor/cache"
272 if [[ -n "$test_packages" ]]; then
273 for p in $packages ; do
274 if [[ -n "$ONLY_BUILD" ]] && [[ "$p" != "$ONLY_BUILD" ]]; then
277 if [[ -e "${WORKSPACE}/packages/.last_test_${TARGET}" ]] && [[ -z "$FORCE_TEST" ]]; then
278 MATCH=`find ${WORKSPACE}/packages/ -newer ${WORKSPACE}/packages/.last_test_${TARGET} -regex .*${TARGET}/$p.*`
279 if [[ "$MATCH" == "" ]]; then
280 # No new package has been built that needs testing
281 echo "Skipping $p test because no new package was built since the last test."
285 # If we're testing all packages, we should not error out on packages that don't exist.
286 # If we are testing one specific package only (i.e. --only-test was given), we should
287 # error out if that package does not exist.
288 if [[ -z "$testing_one_package" ]]; then
289 MATCH=`find ${WORKSPACE}/packages/ -regextype posix-extended -regex .*${TARGET}/$p.*\\(deb\\|rpm\\)`
290 if [[ "$MATCH" == "" ]]; then
291 # No new package has been built that needs testing
292 echo "Skipping $p test because no package file is available to test."
297 echo "START: $p test on $IMAGE" >&2
300 "${docker_volume_args[@]}" \
301 --env ARVADOS_DEBUG=$ARVADOS_DEBUG \
302 --env "TARGET=$TARGET" \
303 --env "WORKSPACE=/arvados" \
306 echo "OK: $p test on $IMAGE succeeded" >&2
309 package_fails="$package_fails $p"
310 echo "ERROR: $p test on $IMAGE failed with exit status $FINAL_EXITCODE" >&2
314 if [[ "$FINAL_EXITCODE" == "0" ]]; then
315 touch ${WORKSPACE}/packages/.last_test_${TARGET}
319 echo "START: build packages on $IMAGE" >&2
320 # Move existing packages and other files into the processed/ subdirectory
321 if [[ ! -e "${WORKSPACE}/packages/${TARGET}/processed" ]]; then
322 mkdir -p "${WORKSPACE}/packages/${TARGET}/processed"
325 mv -f ${WORKSPACE}/packages/${TARGET}/* ${WORKSPACE}/packages/${TARGET}/processed/ 2>/dev/null
327 # give bundle (almost) all the cores. See also the MAKE env var that is passed into the
328 # docker run command below.
329 # Cf. https://build.betterup.com/one-weird-trick-that-will-speed-up-your-bundle-install/
330 tmpfile=$(mktemp /tmp/run-build-packages-one-target.XXXXXX)
331 cores=$(let a=$(grep -c processor /proc/cpuinfo )-1; echo $a)
332 printf -- "---\nBUNDLE_JOBS: \"$cores\"" > $tmpfile
336 "${docker_volume_args[@]}" \
337 -v $tmpfile:/root/.bundle/config \
338 --env ARVADOS_BUILDING_VERSION="$ARVADOS_BUILDING_VERSION" \
339 --env ARVADOS_BUILDING_ITERATION="$ARVADOS_BUILDING_ITERATION" \
340 --env ARVADOS_DEBUG=$ARVADOS_DEBUG \
341 --env "ONLY_BUILD=$ONLY_BUILD" \
342 --env "FORCE_BUILD=$FORCE_BUILD" \
344 --env "MAKE=make --jobs $cores" \
348 echo "OK: build packages on $IMAGE succeeded" >&2
351 echo "ERROR: build packages on $IMAGE failed with exit status $FINAL_EXITCODE" >&2
353 # Clean up the bundle config file
357 if test -n "$package_fails" ; then
358 echo "Failed package tests:$package_fails" >&2