Files
root/build-tools/build-wheels/docker/docker-build-wheel.sh
Don Penney 492b5b218d Retries for certain wheel and image build commands
The wheel and image build tools hit intermittent issues such as:
* Network or server issues that cause file download failures
* Repo access failures due to repo updates or other issues

To avoid formal build failures on such issues, this update adds
retries around specific commands, like wget and docker build.

Change-Id: Ifafdc6201872f43b2dd77efd4dcb033456477c2e
Closes-Bug: 1823986
Signed-off-by: Don Penney <don.penney@windriver.com>
2019-04-09 16:23:02 -04:00

356 lines
9.1 KiB
Bash
Executable File

#!/bin/bash
#
# Copyright (c) 2018-2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This utility builds a set of python wheels for upstream packages,
# reading a source list from wheels.cfg
#
CFGFILE=/wheels.cfg
OUTPUTDIR=/wheels
FAILED_LOG=$OUTPUTDIR/failed.lst
declare -i MAX_ATTEMPTS=5
#
# Function to log the start of a build
#
function startlog {
cat <<EOF
############################################################
Building $1
############################################################
EOF
}
#
# Function to find the line number for the first import
function first_import_line {
grep -nE '^(from|import)' setup.py \
| grep -v __future__ \
| head -1 \
| sed 's/:.*//'
}
#
# Function to update the python module to use setuptools.setup,
# in order to support building the wheel.
# This function is only called if fix_setup is specified for the
# module in wheels.cfg
#
function fix_setup {
echo "########### Running fix_setup"
# bugtrack_url is not supported by setuptools.setup
grep -q '^[[:space:]]*bugtrack_url=' setup.py
if [ $? -eq 0 ]; then
sed -i '/^[[:space:]]*bugtrack_url=/d' setup.py
fi
# If setuptools.setup is already being imported, nothing to do.
grep -q '^from setuptools import setup' setup.py
if [ $? -eq 0 ]; then
return
fi
# Look for various ways distutils.core.setup is being imported,
# and replace it with setuptools.setup, inserting the new import
# ahead of the first existing import.
grep -q '^from distutils.core import .*setup,' setup.py
if [ $? -eq 0 ]; then
cp setup.py setup.py.orig
sed -i 's/^\(from distutils.core import .*\)setup,/\1/' setup.py
line=$(first_import_line)
sed -i "${line}i from setuptools import setup" setup.py
return
fi
grep -q '^from distutils.core import setup' setup.py
if [ $? -eq 0 ]; then
cp setup.py setup.py.orig
line=$(first_import_line)
sed -i '/^from distutils.core import setup/d' setup.py
sed -i "${line}i from setuptools import setup" setup.py
return
fi
grep -q '^from distutils.core import .*setup' setup.py
if [ $? -eq 0 ]; then
cp setup.py setup.py.orig
line=$(first_import_line)
sed -i 's/^\(from distutils.core import .*\), setup/\1/' setup.py
sed -i "${line}i from setuptools import setup" setup.py
return
fi
grep -q '^import distutils.core as duc' setup.py
if [ $? -eq 0 ]; then
cp setup.py setup.py.orig
line=$(first_import_line)
sed -i "${line}i from setuptools import setup" setup.py
sed -i 's/duc.setup/setup/' setup.py
return
fi
# Insert it
cp setup.py setup.py.orig
line=$(first_import_line)
sed -i 's/^\(from distutils.core import .*\), setup/\1/' setup.py
sed -i "${line}i from setuptools import setup" setup.py
}
#
# Function to call a command, with support for retries
#
function with_retries {
local max_attempts=$1
local cmd=$2
# Pop the first two arguments off the list,
# so we can pass additional args to the command safely
shift 2
local -i attempt=0
while :; do
let -i attempt++
echo "Running: ${cmd} $@"
${cmd} "$@"
if [ $? -eq 0 ]; then
return 0
fi
echo "Command (${cmd}) failed, attempt ${attempt} of ${max_attempts}."
if [ ${attempt} -lt ${max_attempts} ]; then
local delay=5
echo "Waiting ${delay} seconds before retrying..."
sleep ${delay}
continue
else
echo "Max command attempts reached. Aborting..."
return 1
fi
done
}
#
# Function to use git to clone the module source and build a wheel.
#
function from_git {
sed 's/#.*//' $CFGFILE | awk -F '|' '$2 == "git" { print $0; }' | \
while IFS='|' read wheelname stype gitrepo basedir branch fix; do
startlog $wheelname
if [ -f $OUTPUTDIR/$wheelname ]; then
echo "$wheelname already exists"
continue
fi
git clone $gitrepo
if [ $? -ne 0 ]; then
echo "Failure running: git clone $gitrepo"
echo $wheelname >> $FAILED_LOG
continue
fi
pushd $basedir
if [ $? -ne 0 ]; then
echo "Failure running: pushd $basedir"
echo $wheelname >> $FAILED_LOG
continue
fi
git checkout $branch
if [ $? -ne 0 ]; then
echo "Failure running: git checkout $branch"
echo $wheelname >> $FAILED_LOG
continue
fi
if [ "$fix" == "fix_setup" ]; then
fix_setup
fi
# Build the wheel
python setup.py bdist_wheel
if [ -f dist/$wheelname ]; then
cp dist/$wheelname $OUTPUTDIR || echo $wheelname >> $FAILED_LOG
else
echo $wheelname >> $FAILED_LOG
echo "Could not find dist/$wheelname"
echo "Searching for wheel:"
find dist/ -name '*.whl'
fi
popd
done
}
#
# Function to download a source tarball and build a wheel.
#
function from_tar {
sed 's/#.*//' $CFGFILE | awk -F '|' '$2 == "tar" { print $0; }' | \
while IFS='|' read wheelname stype wgetsrc basedir fix; do
startlog $wheelname
if [ -f $OUTPUTDIR/$wheelname ]; then
echo "$wheelname already exists"
continue
fi
tarball=$(basename $wgetsrc)
if [[ $tarball =~ gz$ ]]; then
taropts="xzf"
elif [[ $tarball =~ bz2$ ]]; then
taropts="xjf"
else
taropts="xf"
fi
with_retries ${MAX_ATTEMPTS} wget $wgetsrc
if [ $? -ne 0 ]; then
echo $wheelname >> $FAILED_LOG
continue
fi
tar $taropts $(basename $wgetsrc)
if [ $? -ne 0 ]; then
echo "Failure running: tar $taropts $(basename $wgetsrc)"
echo $wheelname >> $FAILED_LOG
continue
fi
pushd $basedir
if [ $? -ne 0 ]; then
echo "Failure running: pushd $basedir"
echo $wheelname >> $FAILED_LOG
continue
fi
if [ "$fix" == "fix_setup" ]; then
fix_setup
fi
# Build the wheel
python setup.py bdist_wheel
if [ -f dist/$wheelname ]; then
cp dist/$wheelname $OUTPUTDIR || echo $wheelname >> $FAILED_LOG
else
echo $wheelname >> $FAILED_LOG
echo "Could not find dist/$wheelname"
echo "Searching for wheel:"
find dist/ -name '*.whl'
fi
popd
done
}
#
# Function to download a source zip file and build a wheel.
#
function from_zip {
sed 's/#.*//' $CFGFILE | awk -F '|' '$2 == "zip" { print $0; }' | \
while IFS='|' read wheelname stype wgetsrc basedir fix; do
startlog $wheelname
if [ -f $OUTPUTDIR/$wheelname ]; then
echo "$wheelname already exists"
continue
fi
with_retries ${MAX_ATTEMPTS} wget $wgetsrc
if [ $? -ne 0 ]; then
echo $wheelname >> $FAILED_LOG
continue
fi
unzip $(basename $wgetsrc)
if [ $? -ne 0 ]; then
echo "Failure running: unzip $(basename $wgetsrc)"
echo $wheelname >> $FAILED_LOG
continue
fi
pushd $basedir
if [ $? -ne 0 ]; then
echo "Failure running: pushd $basedir"
echo $wheelname >> $FAILED_LOG
continue
fi
if [ "$fix" == "fix_setup" ]; then
fix_setup
fi
# Build the wheel
python setup.py bdist_wheel
if [ -f dist/$wheelname ]; then
cp dist/$wheelname $OUTPUTDIR || echo $wheelname >> $FAILED_LOG
else
echo $wheelname >> $FAILED_LOG
echo "Could not find dist/$wheelname"
echo "Searching for wheel:"
find dist/ -name '*.whl'
fi
popd
done
}
#
# Function to download an existing wheel from pypi.
#
function from_pypi {
sed 's/#.*//' $CFGFILE | awk -F '|' '$2 == "pypi" { print $0; }' | \
while IFS='|' read wheelname stype wgetsrc; do
startlog $wheelname
if [ -f $OUTPUTDIR/$wheelname ]; then
echo "$wheelname already exists"
continue
fi
with_retries ${MAX_ATTEMPTS} wget $wgetsrc
if [ $? -ne 0 ]; then
echo $wheelname >> $FAILED_LOG
continue
fi
cp $wheelname $OUTPUTDIR || echo $wheelname >> $FAILED_LOG
done
}
rm -f $FAILED_LOG
mkdir -p /build-wheels
cd /build-wheels
from_git
from_tar
from_zip
from_pypi
if [ -f $FAILED_LOG ]; then
let -i failures=$(cat $FAILED_LOG | wc -l)
cat <<EOF
############################################################
The following module(s) failed to build:
$(cat $FAILED_LOG)
Summary:
${failures} build failure(s).
EOF
exit 1
fi
cat <<EOF
############################################################
All wheels have been successfully built.
EOF
exit 0