root/build-tools/build-wheels/build-wheel-tarball.sh
Davlet Panech 2cea530c51 wheels: support extra wheels in tarball
build-wheel-tarball.sh: new option "--extra-wheels-dir": allow user to
pass an additional directory containing wheels files to be included in
the tarball. This lets users add arbitrary wheels in their privbate
builds when troubleshooting an image build.

Story: 2010294
Task: 46278

Signed-off-by: Davlet Panech <davlet.panech@windriver.com>
Change-Id: I090723e95b91b90d0092b9692b33d382e7bbd6cf
2022-09-14 12:57:11 +00:00

432 lines
12 KiB
Bash
Executable File

#!/bin/bash
#
# Copyright (c) 2018-2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This utility builds the StarlingX wheel tarball
#
MY_SCRIPT_DIR=$(dirname $(readlink -f $0))
source ${MY_SCRIPT_DIR}/utils.sh
# Required env vars
if [ -z "${MY_WORKSPACE}" -o -z "${MY_REPO}" ]; then
echo "Environment not setup for builds" >&2
exit 1
fi
SUPPORTED_OS_ARGS=('centos' 'debian')
OS=
OS_VERSION=
BUILD_STREAM=stable
VERSION=$(date --utc '+%Y.%m.%d.%H.%M') # Default version, using timestamp
PUSH=no
HTTP_PROXY=""
HTTPS_PROXY=""
NO_PROXY=""
CLEAN=no
KEEP_IMAGE=no
DOCKER_USER=${USER}
declare -i MAX_ATTEMPTS=1
PYTHON2=no
USE_DOCKER_CACHE=no
EXTRA_WHEELS_DIR=
# Requirement/constraint URLs -- these will be read from openstack.cfg
STABLE_OPENSTACK_REQ_URL=
MASTER_OPENSTACK_REQ_URL=
STABLE_OPENSTACK_REQ_URL_PY2=
MASTER_OPENSTACK_REQ_URL_PY2=
# List of top-level services for images, which should not be listed in upper-constraints.txt
SKIP_CONSTRAINTS=(
ceilometer
cinder
glance
gnocchi
heat
horizon
ironic
keystone
magnum
murano
neutron
nova
panko
)
SKIP_CONSTRAINTS_PY2=("${SKIP_CONSTRAINTS_PY[@]}")
function usage {
cat >&2 <<EOF
Usage:
$(basename $0)
Options:
--os: Specify base OS (valid options: ${SUPPORTED_OS_ARGS[@]})
--os-version: Specify OS version
--stream: Build stream, stable or dev (default: stable)
--push: Push to docker repo
--http_proxy: Set http proxy <URL>:<PORT>, urls splitted by ","
--https_proxy: Set https proxy <URL>:<PORT>, urls splitted by ","
--no_proxy: Set bypass list for proxy <URL>, urls splitted by ","
--user: Docker repo userid
--version: Version for pushed image (if used with --push)
--attempts: Max attempts, in case of failure (default: 1)
--python2: Build a python2 tarball
--extra-wheels-dir: Directory containing additional .whl files
--keep-image: Don't delete wheel builder image at the end
--cache: Allow docker to use filesystem cache when building
CAUTION: this option may ignore locally-generated
packages and is meant for debugging the build
scripts.
EOF
}
OPTS=$(getopt -o h -l help,os:,os-version:,push,clean,user:,release:,stream:,http_proxy:,https_proxy:,no_proxy:,version:,attempts:,python2,extra-wheels-dir:,keep-image,cache -- "$@")
if [ $? -ne 0 ]; then
usage
exit 1
fi
eval set -- "${OPTS}"
while true; do
case $1 in
--)
# End of getopt arguments
shift
break
;;
--os)
OS=$2
shift 2
;;
--os-version)
OS_VERSION=$2
shift 2
;;
--push)
PUSH=yes
shift
;;
--clean)
CLEAN=yes
shift
;;
--user)
DOCKER_USER=$2
shift 2
;;
--stream)
BUILD_STREAM=$2
shift 2
;;
--release) # Temporarily keep --release support as an alias for --stream
BUILD_STREAM=$2
shift 2
;;
--http_proxy)
HTTP_PROXY=$2
shift 2
;;
--https_proxy)
HTTPS_PROXY=$2
shift 2
;;
--no_proxy)
NO_PROXY=$2
shift 2
;;
--version)
VERSION=$2
shift 2
;;
--attempts)
MAX_ATTEMPTS=$2
shift 2
;;
--python2)
PYTHON2=yes
shift
;;
--extra-wheels-dir)
EXTRA_WHEELS_DIR="$2"
shift 2
;;
--keep-image)
KEEP_IMAGE=yes
shift
;;
--cache)
USE_DOCKER_CACHE=yes
shift
;;
-h | --help )
usage
exit 1
;;
*)
usage
exit 1
;;
esac
done
# Validate the OS option
if [ -z "$OS" ] ; then
OS="$(ID= && source /etc/os-release 2>/dev/null && echo $ID || true)"
if ! [ -n "$OS" ]; then
echo "Unable to determine OS" >&2
echo "Re-run with \"--os\" option" >&2
exit 1
fi
fi
VALID_OS=1
for supported_os in ${SUPPORTED_OS_ARGS[@]}; do
if [ "$OS" = "${supported_os}" ]; then
VALID_OS=0
break
fi
done
if [ ${VALID_OS} -ne 0 ]; then
echo "Unsupported OS specified: ${OS}" >&2
echo "Supported OS options: ${SUPPORTED_OS_ARGS[@]}" >&2
exit 1
fi
# Read openstack URLs
OPENSTACK_CFG="${MY_SCRIPT_DIR}/$OS/openstack.cfg"
source "$OPENSTACK_CFG" || exit 1
# Set python version-specific variables
if [ "${PYTHON2}" = "yes" ]; then
SKIP_CONSTRAINTS=("${SKIP_CONSTRAINTS_PY2[@]}")
PY_SUFFIX="-py2"
fi
# Resolve $EXTRA_WHEELS_DIR
if [[ -n "$EXTRA_WHEELS_DIR" ]] ; then
EXTRA_WHEELS_DIR="$(readlink -ev "$EXTRA_WHEELS_DIR")" || exit 1
fi
# Build the base wheels and retrieve the StarlingX wheels
declare -a BUILD_BASE_WL_ARGS
BUILD_BASE_WL_ARGS+=(--os ${OS} --stream ${BUILD_STREAM})
if [ -n "$OS_VERSION" ]; then
BUILD_BASE_WL_ARGS+=(--os-version "${OS_VERSION}")
fi
if [ ! -z "$HTTP_PROXY" ]; then
BUILD_BASE_WL_ARGS+=(--http_proxy ${HTTP_PROXY})
fi
if [ ! -z "$HTTPS_PROXY" ]; then
BUILD_BASE_WL_ARGS+=(--https_proxy ${HTTPS_PROXY})
fi
if [ ! -z "$NO_PROXY" ]; then
BUILD_BASE_WL_ARGS+=(--no_proxy ${NO_PROXY})
fi
if [ "$KEEP_IMAGE" = "yes" ]; then
BUILD_BASE_WL_ARGS+=(--keep-image)
fi
if [[ "$USE_DOCKER_CACHE" == "yes" ]] ; then
BUILD_BASE_WL_ARGS+=(--cache)
fi
${MY_SCRIPT_DIR}/build-base-wheels.sh ${BUILD_BASE_WL_ARGS[@]} --attempts ${MAX_ATTEMPTS}
if [ $? -ne 0 ]; then
echo "Failure running build-base-wheels.sh" >&2
exit 1
fi
${MY_SCRIPT_DIR}/get-stx-wheels.sh --os ${OS} --stream ${BUILD_STREAM}
if [ $? -ne 0 ]; then
echo "Failure running get-stx-wheels.sh" >&2
exit 1
fi
BUILD_OUTPUT_PATH=${MY_WORKSPACE}/std/build-wheels-${OS}-${BUILD_STREAM}/tarball${PY_SUFFIX}
if [ -d ${BUILD_OUTPUT_PATH} ]; then
# Wipe out the existing dir to ensure there are no stale files
rm -rf ${BUILD_OUTPUT_PATH}
fi
mkdir -p ${BUILD_OUTPUT_PATH}
cd ${BUILD_OUTPUT_PATH}
IMAGE_NAME=stx-${OS}-${BUILD_STREAM}-wheels${PY_SUFFIX}
TARBALL_FNAME=${MY_WORKSPACE}/std/build-wheels-${OS}-${BUILD_STREAM}/${IMAGE_NAME}.tar
if [ -f ${TARBALL_FNAME} ]; then
rm -f ${TARBALL_FNAME}
fi
# Download the global-requirements.txt and upper-constraints.txt files
if [ "${PYTHON2}" = "yes" ]; then
if [ "${BUILD_STREAM}" = "dev" -o "${BUILD_STREAM}" = "master" ]; then
OPENSTACK_REQ_URL="${MASTER_OPENSTACK_REQ_URL_PY2}"
else
OPENSTACK_REQ_URL="${STABLE_OPENSTACK_REQ_URL_PY2}"
fi
else
if [ "${BUILD_STREAM}" = "dev" -o "${BUILD_STREAM}" = "master" ]; then
OPENSTACK_REQ_URL="${MASTER_OPENSTACK_REQ_URL}"
else
OPENSTACK_REQ_URL="${STABLE_OPENSTACK_REQ_URL}"
fi
fi
for url in "${OPENSTACK_REQ_URL}/global-requirements.txt" "${OPENSTACK_REQ_URL}/upper-constraints.txt" ; do
if echo "$url" | grep -q -E '^(https?|ftp):' >/dev/null ; then
with_retries ${MAX_ATTEMPTS} wget "$url"
if [ $? -ne 0 ]; then
echo "Failed to download $url" >&2
exit 1
fi
else
# Remove "file:" from url and treat what remains as a file name.
# Local files should be relative to the location of openstack.cfg,
# so leading slashes are menaingless, remove them as well.
url="$(echo "$url" | sed -r 's,^(file:)?/*,,')"
\cp "$(dirname "$OPENSTACK_CFG")"/"$url" ./ || exit 1
fi
done
# Delete $SKIP_CONSTRAINTS from upper-constraints.txt, if any present
for name in ${SKIP_CONSTRAINTS[@]}; do
grep -q "^${name}===" upper-constraints.txt
if [ $? -eq 0 ]; then
# Delete the module
sed -i "/^${name}===/d" upper-constraints.txt
fi
done
# Set nullglob so wildcards will return empty string if no match
shopt -s nullglob
# Copy the base and stx wheels, updating upper-constraints.txt as necessary
# FIXME: debian packages install *.whl files under /usr/share/..., rather than
# /wheels. Do a deep search on that platform
if [ "${OS}" == "debian" ]; then
stx_find_wheels_cmd=(find ../stx -name '*.whl')
else
stx_find_wheels_cmd=(find ../stx/wheels -mindepth 1 -maxdepth 1 -name '*.whl')
fi
if [[ -d "$EXTRA_WHEELS_DIR" ]] ; then
find_extra_wheels_cmd=(find "$EXTRA_WHEELS_DIR" -mindepth 1 -maxdepth 1 -name '*.whl')
else
find_extra_wheels_cmd=()
fi
for wheel in ../base${PY_SUFFIX}/*.whl $("${stx_find_wheels_cmd[@]}") $("${find_extra_wheels_cmd[@]}") ; do
if [[ ! -f "$wheel" ]] ; then
echo "WARNING: $wheel doesn't exist or is not a regular file" >&2
continue
fi
# Get the wheel name and version from the METADATA
METADATA=$(unzip -p ${wheel} '*/METADATA')
name=$(echo "${METADATA}" | grep '^Name:' | awk '{print $2}')
version=$(echo "${METADATA}" | grep '^Version:' | awk '{print $2}')
if [ -z "${name}" -o -z "${version}" ]; then
echo "Failed to parse name or version from $(readlink -f ${wheel})" >&2
exit 1
fi
echo "Adding ${name}-${version}..."
cp ${wheel} .
if [ $? -ne 0 ]; then
echo "Failed to copy $(readlink -f ${wheel})" >&2
exit 1
fi
# Update the upper-constraints file, if necessary
skip_constraint=1
for skip in ${SKIP_CONSTRAINTS[@]}; do
if [ "${name}" = "${skip}" ]; then
skip_constraint=0
continue
fi
done
if [ ${skip_constraint} -eq 0 ]; then
continue
fi
grep -q "^${name}===${version}\(;.*\)*$" upper-constraints.txt
if [ $? -eq 0 ]; then
# This version already exists in the upper-constraints.txt
continue
fi
grep -q "^${name}===" upper-constraints.txt
if [ $? -eq 0 ]; then
# Update the version
sed -i "s/^${name}===.*/${name}===${version}/" upper-constraints.txt
else
# Add the module
echo "${name}===${version}" >> upper-constraints.txt
fi
done
shopt -u nullglob
echo "Creating $(basename ${TARBALL_FNAME})..."
tar cf ${TARBALL_FNAME} *
if [ $? -ne 0 ]; then
echo "Failed to create the tarball" >&2
exit 1
fi
echo "Done."
if [ "${PUSH}" = "yes" ]; then
#
# Push generated wheels tarball to docker registry
#
docker import ${TARBALL_FNAME} ${DOCKER_USER}/${IMAGE_NAME}:${VERSION}
if [ $? -ne 0 ]; then
echo "Failed command:" >&2
echo "docker import ${TARBALL_FNAME} ${DOCKER_USER}/${IMAGE_NAME}:${VERSION}" >&2
exit 1
fi
docker tag ${DOCKER_USER}/${IMAGE_NAME}:${VERSION} ${DOCKER_USER}/${IMAGE_NAME}:latest
if [ $? -ne 0 ]; then
echo "Failed command:" >&2
echo "docker tag ${DOCKER_USER}/${IMAGE_NAME}:${VERSION} ${DOCKER_USER}/${IMAGE_NAME}:latest" >&2
exit 1
fi
docker push ${DOCKER_USER}/${IMAGE_NAME}:${VERSION}
if [ $? -ne 0 ]; then
echo "Failed command:" >&2
echo "docker push ${DOCKER_USER}/${IMAGE_NAME}:${VERSION}" >&2
exit 1
fi
docker push ${DOCKER_USER}/${IMAGE_NAME}:latest
if [ $? -ne 0 ]; then
echo "Failed command:" >&2
echo "docker import ${TARBALL_FNAME} ${DOCKER_USER}/${IMAGE_NAME}:${VERSION}" >&2
exit 1
fi
if [ "${CLEAN}" = "yes" ]; then
echo "Deleting docker images ${DOCKER_USER}/${IMAGE_NAME}:${VERSION} ${DOCKER_USER}/${IMAGE_NAME}:latest"
docker image rm ${DOCKER_USER}/${IMAGE_NAME}:${VERSION} ${DOCKER_USER}/${IMAGE_NAME}:latest
if [ $? -ne 0 ]; then
echo "Failed command:" >&2
echo "docker image rm ${DOCKER_USER}/${IMAGE_NAME}:${VERSION} ${DOCKER_USER}/${IMAGE_NAME}:latest" >&2
exit 1
fi
fi
fi
exit 0