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
257 python3-arvados-python-client
258 python3-arvados-cwl-runner
259 python3-crunchstat-summary
260 python3-arvados-user-activity"
267 mkdir -p "$WORKSPACE/services/api/vendor/cache-$TARGET"
270 -v "$JENKINS_DIR:/jenkins"
271 -v "$WORKSPACE:/arvados"
272 -v /arvados/services/api/vendor/bundle
273 -v "$WORKSPACE/services/api/vendor/cache-$TARGET:/arvados/services/api/vendor/cache"
276 if [[ -n "$test_packages" ]]; then
277 for p in $packages ; do
278 if [[ -n "$ONLY_BUILD" ]] && [[ "$p" != "$ONLY_BUILD" ]]; then
281 if [[ -e "${WORKSPACE}/packages/.last_test_${TARGET}" ]] && [[ -z "$FORCE_TEST" ]]; then
282 MATCH=`find ${WORKSPACE}/packages/ -newer ${WORKSPACE}/packages/.last_test_${TARGET} -regex .*${TARGET}/$p.*`
283 if [[ "$MATCH" == "" ]]; then
284 # No new package has been built that needs testing
285 echo "Skipping $p test because no new package was built since the last test."
289 # If we're testing all packages, we should not error out on packages that don't exist.
290 # If we are testing one specific package only (i.e. --only-test was given), we should
291 # error out if that package does not exist.
292 if [[ -z "$testing_one_package" ]]; then
293 MATCH=`find ${WORKSPACE}/packages/ -regextype posix-extended -regex .*${TARGET}/$p.*\\(deb\\|rpm\\)`
294 if [[ "$MATCH" == "" ]]; then
295 # No new package has been built that needs testing
296 echo "Skipping $p test because no package file is available to test."
301 echo "START: $p test on $IMAGE" >&2
304 "${docker_volume_args[@]}" \
305 --env ARVADOS_DEBUG=$ARVADOS_DEBUG \
306 --env "TARGET=$TARGET" \
307 --env "WORKSPACE=/arvados" \
310 echo "OK: $p test on $IMAGE succeeded" >&2
313 package_fails="$package_fails $p"
314 echo "ERROR: $p test on $IMAGE failed with exit status $FINAL_EXITCODE" >&2
318 if [[ "$FINAL_EXITCODE" == "0" ]]; then
319 touch ${WORKSPACE}/packages/.last_test_${TARGET}
323 echo "START: build packages on $IMAGE" >&2
324 # Move existing packages and other files into the processed/ subdirectory
325 if [[ ! -e "${WORKSPACE}/packages/${TARGET}/processed" ]]; then
326 mkdir -p "${WORKSPACE}/packages/${TARGET}/processed"
329 mv -f ${WORKSPACE}/packages/${TARGET}/* ${WORKSPACE}/packages/${TARGET}/processed/ 2>/dev/null
331 # give bundle (almost) all the cores. See also the MAKE env var that is passed into the
332 # docker run command below.
333 # Cf. https://build.betterup.com/one-weird-trick-that-will-speed-up-your-bundle-install/
334 tmpfile=$(mktemp /tmp/run-build-packages-one-target.XXXXXX)
335 cores=$(let a=$(grep -c processor /proc/cpuinfo )-1; echo $a)
336 printf -- "---\nBUNDLE_JOBS: \"$cores\"" > $tmpfile
340 "${docker_volume_args[@]}" \
341 -v $tmpfile:/root/.bundle/config \
342 --env ARVADOS_BUILDING_VERSION="$ARVADOS_BUILDING_VERSION" \
343 --env ARVADOS_BUILDING_ITERATION="$ARVADOS_BUILDING_ITERATION" \
344 --env ARVADOS_DEBUG=$ARVADOS_DEBUG \
345 --env "ONLY_BUILD=$ONLY_BUILD" \
346 --env "FORCE_BUILD=$FORCE_BUILD" \
348 --env "MAKE=make --jobs $cores" \
352 echo "OK: build packages on $IMAGE succeeded" >&2
355 echo "ERROR: build packages on $IMAGE failed with exit status $FINAL_EXITCODE" >&2
357 # Clean up the bundle config file
361 if test -n "$package_fails" ; then
362 echo "Failed package tests:$package_fails" >&2