diff --git a/.github/workflows/bare.yml b/.github/workflows/bare.yml index 953df83..64fb40b 100644 --- a/.github/workflows/bare.yml +++ b/.github/workflows/bare.yml @@ -12,12 +12,7 @@ name: Bare on: push: branches: [ master ] - paths: - - '**.py' pull_request: - branches: [ master ] - paths: - - '**.py' concurrency: group: ci-${{ github.ref }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 049e9ac..3795c13 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -9,12 +9,7 @@ name: Docker on: push: branches: [ master ] - paths: - - '**.py' pull_request: - branches: [ master ] - paths: - - '**.py' concurrency: @@ -41,11 +36,9 @@ jobs: - alpine:3.18 - amazonlinux:2 - amazonlinux:2022 - - centos:8.2.2004 - - centos-stream9-fips - oraclelinux:8 - - ubuntu:14.04 - - ubuntu:16.04 + - rockylinux:9 + - ubuntu:18.04 - ubuntu:22.04 # ubuntu-latest is GitHub's newest well-suported Linux distro. @@ -54,19 +47,16 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: - # On Alpine, OpenSSL must be updated to latest version for python-package. - name: Alpine setup if: startsWith(matrix.container, 'alpine') - run: | - apk upgrade -U - apk add git bash shadow sudo curl + run: apk add git bash shadow sudo curl - name: Amazon Linux 2022 setup - if: matrix.container == 'amazonlinux:2022' - run: yum -y install libxcrypt-compat + if: matrix.container == 'amazonlinux:2022' || matrix.container == 'rockylinux:9' + run: yum -y install libxcrypt-compat findutils - name: Yum-based setup - if: startsWith(matrix.container, 'centos') || startsWith(matrix.container, 'amazon') || startsWith(matrix.container, 'oracle') + if: startsWith(matrix.container, 'rocky') || startsWith(matrix.container, 'amazon') || startsWith(matrix.container, 'oracle') run: yum -y install git tar which sudo - name: Ubuntu setup diff --git a/brink.conf b/brink.conf deleted file mode 100644 index 9e0ce89..0000000 --- a/brink.conf +++ /dev/null @@ -1,9 +0,0 @@ -BASE_REQUIREMENTS='pip==20.3.4chevah chevah-brink==0.79.0 paver==1.2.4' -PYTHON_CONFIGURATION='default@2.7.18.52fb2f5' -# For production packages there are 2 options: -BINARY_DIST_URI='https://github.com/chevah/python-package/releases/download' -#BINARY_DIST_URI='https://bin.chevah.com:20443/production' -# For testing packages, make sure this one is the last uncommented instance: -#BINARY_DIST_URI='https://bin.chevah.com:20443/testing' -PIP_INDEX_URL='https://bin.chevah.com:20443/pypi/simple' -CHEVAH_BUILD_DIR='build-compat' diff --git a/brink.sh b/brink.sh deleted file mode 100755 index 2dd8ff2..0000000 --- a/brink.sh +++ /dev/null @@ -1,934 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2010-2020 Adi Roiban. -# See MIT LICENSE for details. -# -# This file has no version. Documentation is found in this comment. -# -# Helper script for bootstrapping a Python based build system on Unix/Msys. -# -# It is similar with a python-virtualenv but it will not used the local -# Python version and can be used on systems without a local Python. -# -# It will delegate the argument to the execute_venv function, -# with the exception of these commands: -# * clean - remove everything, except cache -# * purge - remove (empty) the cache -# * get_python - download Python distribution in cache -# -# It exports the following environment variables: -# * PYTHONPATH - path to the build directory -# * CHEVAH_PYTHON - name of the python versions -# * CHEVAH_OS - name of the current OS -# * CHEVAH_ARCH - CPU type of the current OS -# -# The build directory is used from CHEVAH_BUILD env, -# then read from brink.conf as CHEVAH_BUILD_DIR, -# and will use a default value if not defined there. -# -# The cache directory is read the CHEVAH_CACHE env, -# and then read from brink.conf as CHEVAH_CACHE_DIR, -# and will use a default value if not defined. -# -# You can define your own `execute_venv` function in brink.conf with the -# command used to execute Python inside the newly virtual environment. -# - -# Bash checks -set -o nounset # always check if variables exist -set -o errexit # always exit on error -set -o errtrace # trap errors in functions as well -set -o pipefail # don't ignore exit codes when piping output - -# Initialize default value. -COMMAND=${1-''} -DEBUG=${DEBUG-0} - -# Set default locale. -# We use C (alias for POSIX) for having a basic default value and -# to make sure we explicitly convert all unicode values. -export LANG='C' -export LANGUAGE='C' -export LC_ALL='C' -export LC_CTYPE='C' -export LC_COLLATE='C' -export LC_MESSAGES='C' -export PATH=$PATH:'/sbin:/usr/sbin:/usr/local/bin' - -# -# Global variables. -# -# Used to return non-scalar value from functions. -RESULT='' -WAS_PYTHON_JUST_INSTALLED=0 -DIST_FOLDER='dist' - -# Path global variables. - -# Configuration variable. -CHEVAH_BUILD_DIR="" -# Variale used at runtime. -BUILD_FOLDER="" - -# Configuration variable -CHEVAH_CACHE_DIR= -# Varible used at runtime. -CACHE_FOLDER="" - -PYTHON_BIN="" -PYTHON_LIB="" -LOCAL_PYTHON_BINARY_DIST="" - -# Put default values and create them as global variables. -OS='not-detected-yet' -ARCH='not-detected-yet' - -# Initialize default values from brink.conf -PYTHON_CONFIGURATION='NOT-YET-DEFINED' -PYTHON_VERSION='not.defined.yet' -PYTHON_PLATFORM='unknown-os-and-arch' -PYTHON_NAME='python2.7' -BINARY_DIST_URI='https://github.com/chevah/python-package/releases/download' -PIP_INDEX_URL='https://pypi.org/simple' -BASE_REQUIREMENTS='' - -# -# Check that we have a pavement.py file in the current dir. -# If not, we are out of the source's root dir and brink.sh won't work. -# -check_source_folder() { - if [ ! -e pavement.py ]; then - (>&2 echo 'No "pavement.py" file found in current folder.') - (>&2 echo 'Make sure you are running "brink.sh" from a source folder.') - exit 8 - fi -} - -# Called to trigger the entry point in the virtual environment. -# Can be overwritten in brink.conf -execute_venv() { - ${PYTHON_BIN} $PYTHON3_CHECK -c 'from paver.tasks import main; main()' "$@" -} - - -# Called to update the dependencies inside the newly created virtual -# environment. -update_venv() { - # After updating the python version, the existing pyc files might no - # longer be valid. - _clean_pyc - - set +e - ${PYTHON_BIN} -c 'from paver.tasks import main; main()' deps - exit_code=$? - set -e - if [ $exit_code -ne 0 ]; then - (>&2 echo 'Failed to run the initial "./brink.sh deps" command.') - exit 7 - fi -} - -# Load repo specific configuration. -source brink.conf - - -clean_build() { - # Shortcut for clear since otherwise it will depend on python - echo "Removing ${BUILD_FOLDER}..." - delete_folder ${BUILD_FOLDER} - echo "Removing dist..." - delete_folder ${DIST_FOLDER} - echo "Removing publish..." - delete_folder 'publish' - echo "Removing node_modules..." - delete_folder node_modules - echo "Removing web build" - delete_folder chevah/server/static/build/ - - # In some case pip hangs with a build folder in temp and - # will not continue until it is manually removed. - # On the OSX build server tmp is in $TMPDIR - if [ ! -z "${TMPDIR-}" ]; then - # check if TMPDIR is set before trying to clean it. - rm -rf ${TMPDIR}/pip* - else - rm -rf /tmp/pip* - fi -} - - -_clean_pyc() { - echo "Cleaning pyc files ..." - # AIX's find complains if there are no matching files when using +. - [ $(uname) == AIX ] && touch ./dummy_file_for_AIX.pyc - # Faster than '-exec rm {} \;' and supported in most OS'es, - # details at https://www.in-ulm.de/~mascheck/various/find/#xargs - find ./ -name '*.pyc' -exec rm {} + -} - - -# -# Removes the download/pip cache entries. Must be called before -# building/generating the distribution. -# -purge_cache() { - clean_build - - echo "Cleaning download cache ..." - rm -rf $CACHE_FOLDER/* -} - - -# -# Delete the folder as quickly as possible. -# -delete_folder() { - local target="$1" - # On Windows, we use internal command prompt for maximum speed. - # See: https://stackoverflow.com/a/6208144/539264 - if [ $OS = "win" -a -d $target ]; then - cmd //c "del /f/s/q $target > nul" - cmd //c "rmdir /s/q $target" - else - rm -rf $target - fi -} - - -# -# Wrapper for executing a command and exiting on failure. -# -execute() { - if [ $DEBUG -ne 0 ]; then - echo "Executing:" $@ - fi - - # Make sure $@ is called in quotes as otherwise it will not work. - set +e - "$@" - exit_code=$? - set -e - if [ $exit_code -ne 0 ]; then - (>&2 echo "Failed:" $@) - exit 1 - fi -} - -# -# Update global variables with current paths. -# -update_path_variables() { - resolve_python_version - - if [ "${OS}" = "win" ] ; then - PYTHON_BIN="/lib/python.exe" - PYTHON_LIB="/lib/Lib/" - else - PYTHON_BIN="/bin/python" - PYTHON_LIB="/lib/${PYTHON_NAME}/" - fi - - # Read first from env var. - set +o nounset - BUILD_FOLDER="${CHEVAH_BUILD}" - CACHE_FOLDER="${CHEVAH_CACHE}" - set -o nounset - - if [ "${BUILD_FOLDER}" = "" ] ; then - # Use value from configuration file. - BUILD_FOLDER="${CHEVAH_BUILD_DIR}" - fi - - if [ "${BUILD_FOLDER}" = "" ] ; then - # Use default value if not yet defined. - BUILD_FOLDER="build-${OS}-${ARCH}" - fi - - if [ "${CACHE_FOLDER}" = "" ] ; then - # Use default if not yet defined. - CACHE_FOLDER="${CHEVAH_CACHE_DIR}" - fi - - if [ "${CACHE_FOLDER}" = "" ] ; then - # Use default if not yet defined. - CACHE_FOLDER="cache" - fi - - PYTHON_BIN="${BUILD_FOLDER}${PYTHON_BIN}" - PYTHON_LIB="${BUILD_FOLDER}${PYTHON_LIB}" - - LOCAL_PYTHON_BINARY_DIST="$PYTHON_NAME-$OS-$ARCH" - - export PYTHONPATH=${BUILD_FOLDER} - export CHEVAH_PYTHON=${PYTHON_NAME} - export CHEVAH_OS=${OS} - export CHEVAH_ARCH=${ARCH} - export CHEVAH_CACHE=${CACHE_FOLDER} - export PIP_INDEX_URL=${PIP_INDEX_URL} - -} - -# -# Called to update the Python version env var based on the platform -# advertised by the current environment. -# -resolve_python_version() { - local version_configuration=$PYTHON_CONFIGURATION - local version_configuration_array - local candidate - local candidate_platform - local candidate_version - - PYTHON_PLATFORM="$OS-$ARCH" - - # Using ':' as a delimiter, populate a dedicated array. - IFS=: read -a version_configuration_array <<< "$version_configuration" - # Iterate through all the elements of the array to find the best candidate. - for (( i=0 ; i < ${#version_configuration_array[@]}; i++ )); do - candidate="${version_configuration_array[$i]}" - candidate_platform=$(echo "$candidate" | cut -d "@" -f 1) - candidate_version=$(echo "$candidate" | cut -d "@" -f 2) - if [ "$candidate_platform" = "default" ]; then - # On first pass, we set the default version. - PYTHON_VERSION=$candidate_version - elif [ "${PYTHON_PLATFORM%$candidate_platform*}" = "" ]; then - # If matching a specific platform, we overwrite the default version. - PYTHON_VERSION=$candidate_version - fi - done -} - - -# -# Install base package. -# -install_base_deps() { - echo "Installing base requirements: $BASE_REQUIREMENTS." - pip_install "$BASE_REQUIREMENTS" -} - - -# -# Wrapper for python `pip install` command. -# * $1 - package_name and optional version. -# -pip_install() { - echo "::group::pip install $1" - - set +e - # There is a bug in pip/setuptools when using custom build folders. - # See https://github.com/pypa/pip/issues/3564 - rm -rf ${BUILD_FOLDER}/pip-build - ${PYTHON_BIN} -m \ - pip install \ - --index-url=$PIP_INDEX_URL \ - --build=${BUILD_FOLDER}/pip-build \ - $1 - - exit_code=$? - - echo "::endgroup::" - - set -e - if [ $exit_code -ne 0 ]; then - (>&2 echo "Failed to install $1.") - exit 2 - fi -} - -# -# Check for curl and set needed download commands accordingly. -# -set_download_commands() { - set +o errexit - command -v curl > /dev/null - if [ $? -eq 0 ]; then - # Options not used because of no support in CentOS 5.11's curl: - # --retry-connrefused (since curl 7.52.0) - # --retry-all-errors (since curl 7.71.0) - # Retry 2 times, allocating 10s for the connection phase, - # at most 300s for an attempt, sleeping for 5s between retries. - CURL_RETRY_OPTS="\ - --retry 2 \ - --connect-timeout 10 \ - --max-time 300 \ - --retry-delay 5 \ - " - DOWNLOAD_CMD="curl --remote-name --location $CURL_RETRY_OPTS" - ONLINETEST_CMD="curl --fail --silent --head $CURL_RETRY_OPTS \ - --output /dev/null" - set -o errexit - return - fi - (>&2 echo "Missing curl! It is needed for downloading the Python package.") - exit 3 -} - -# -# Download and extract a binary distribution. -# -get_binary_dist() { - local dist_name=$1 - local remote_base_url=$2 - - echo "Getting $dist_name from $remote_base_url..." - - tar_gz_file=${dist_name}.tar.gz - tar_file=${dist_name}.tar - - mkdir -p ${CACHE_FOLDER} - pushd ${CACHE_FOLDER} - - # Get and extract archive. - rm -rf $dist_name - rm -f $tar_gz_file - rm -f $tar_file - execute $DOWNLOAD_CMD $remote_base_url/${tar_gz_file} - execute gunzip -f $tar_gz_file - execute tar -xf $tar_file - rm -f $tar_gz_file - rm -f $tar_file - - popd -} - -# -# Check if we have a versioned Python distribution. -# -test_version_exists() { - local remote_base_url=$1 - local target_file=python-${PYTHON_VERSION}-${OS}-${ARCH}.tar.gz - - echo "Checking $remote_base_url/${PYTHON_VERSION}/$target_file" - $ONLINETEST_CMD $remote_base_url/${PYTHON_VERSION}/$target_file - return $? -} - -# -# Download and extract in cache the python distributable. -# -get_python_dist() { - local remote_base_url=$1 - local download_mode=$2 - local python_distributable=python-${PYTHON_VERSION}-${OS}-${ARCH} - local onlinetest_errorcode - - set +o errexit - test_version_exists $remote_base_url - onlinetest_errorcode=$? - set -o errexit - - if [ $onlinetest_errorcode -eq 0 ]; then - # We have the requested python version. - get_binary_dist $python_distributable $remote_base_url/${PYTHON_VERSION} - else - (>&2 echo "Couldn't find package on remote server. Full link:") - echo "$remote_base_url/$PYTHON_VERSION/$python_distributable.tar.gz" - exit 4 - fi -} - - -# copy_python can be called in a recursive way, and this is here to prevent -# accidental infinite loops. -COPY_PYTHON_RECURSIONS=0 -# -# Copy python to build folder from binary distribution. -# -copy_python() { - local python_distributable="${CACHE_FOLDER}/${LOCAL_PYTHON_BINARY_DIST}" - local python_installed_version - - COPY_PYTHON_RECURSIONS=`expr $COPY_PYTHON_RECURSIONS + 1` - - if [ $COPY_PYTHON_RECURSIONS -gt 2 ]; then - (>&2 echo "Too many calls to copy_python: $COPY_PYTHON_RECURSIONS") - exit 5 - fi - - # Check that python dist was installed - if [ ! -s ${PYTHON_BIN} ]; then - # We don't have a Python binary, so we install it since everything - # else depends on it. - echo "::group::Get Python" - echo "Bootstrapping ${LOCAL_PYTHON_BINARY_DIST} environment" \ - "to ${BUILD_FOLDER}..." - mkdir -p ${BUILD_FOLDER} - - if [ -d ${python_distributable} ]; then - # We have a cached distributable. - # Check if is at the right version. - local cache_ver_file - cache_ver_file=${python_distributable}/lib/PYTHON_PACKAGE_VERSION - cache_version='UNVERSIONED' - if [ -f $cache_ver_file ]; then - cache_version=`cat $cache_ver_file | cut -d - -f 1` - fi - if [ "$PYTHON_VERSION" != "$cache_version" ]; then - # We have a different version in the cache. - # Just remove it and hope that the next step will download - # the right one. - rm -rf ${python_distributable} - fi - fi - - if [ ! -d ${python_distributable} ]; then - # We don't have a cached python distributable. - echo "No ${LOCAL_PYTHON_BINARY_DIST} environment." \ - "Start downloading it..." - get_python_dist "$BINARY_DIST_URI" "strict" - fi - - echo "Copying Python distribution files... " - cp -R ${python_distributable}/* ${BUILD_FOLDER} - - echo "::endgroup::" - - install_base_deps - WAS_PYTHON_JUST_INSTALLED=1 - else - # We have a Python, but we are not sure if is the right version. - local version_file=${BUILD_FOLDER}/lib/PYTHON_PACKAGE_VERSION - - # If we are upgrading the cache from an unversioned Python, - # cat fails if this file is missing, so we create it blank. - touch $version_file - python_installed_version=`cat $version_file | cut -d - -f 1` - if [ "$PYTHON_VERSION" != "$python_installed_version" ]; then - # We have a different python installed. - # Check if we have the to-be-updated version and fail if - # it does not exists. - set +o errexit - test_version_exists "$BINARY_DIST_URI" - local test_version=$? - set -o errexit - if [ $test_version -ne 0 ]; then - (>&2 echo "The build is now at $python_installed_version.") - (>&2 echo "Failed to find the required $PYTHON_VERSION.") - (>&2 echo "Check your configuration or the remote server.") - exit 6 - fi - - # Remove it and try to install it again. - echo "Updating Python from" \ - $python_installed_version to $PYTHON_VERSION - rm -rf ${BUILD_FOLDER}/* - rm -rf ${python_distributable} - copy_python - fi - fi -} - - -# -# Install dependencies after python was just installed. -# -install_dependencies(){ - if [ $WAS_PYTHON_JUST_INSTALLED -ne 1 ]; then - return - fi - - if [ "$COMMAND" == "deps" ] ; then - # Will be installed soon. - return - fi - - update_venv -} - - -# -# Check version of current OS to see if it is supported. -# If it's too old, exit with a nice informative message. -# If it's supported, return through eval the version numbers to be used for -# naming the package, for example: '71' for AIX 7.1, '114' for Solaris 11.4. -# -check_os_version() { - # First parameter should be the human-readable name for the current OS. - # For example: "Red Hat Enterprise Linux" for RHEL, "macOS" for Darwin etc. - # Second and third parameters must be strings composed of integers - # delimited with dots, representing, in order, the oldest version - # supported for the current OS and the current detected version. - # The fourth parameter is used to return through eval the relevant numbers - # for naming the Python package for the current OS, as detailed above. - local name_fancy="$1" - local version_good="$2" - local version_raw="$3" - local version_chevah="$4" - local version_constructed='' - local flag_supported='good_enough' - local version_raw_array - local version_good_array - - if [[ $version_raw =~ [^[:digit:]\.] ]]; then - (>&2 echo "OS version should only have numbers and periods, but:") - (>&2 echo " \$version_raw=$version_raw") - exit 12 - fi - - # Using '.' as a delimiter, populate the version_* arrays. - IFS=. read -a version_raw_array <<< "$version_raw" - IFS=. read -a version_good_array <<< "$version_good" - - # Iterate through all the integers from the good version to compare them - # one by one with the corresponding integers from the supported version. - for (( i=0 ; i < ${#version_good_array[@]}; i++ )); do - version_constructed="${version_constructed}${version_raw_array[$i]}" - if [ ${version_raw_array[$i]} -gt ${version_good_array[$i]} -a \ - "$flag_supported" = 'good_enough' ]; then - flag_supported='true' - elif [ ${version_raw_array[$i]} -lt ${version_good_array[$i]} -a \ - "$flag_supported" = 'good_enough' ]; then - flag_supported='false' - fi - done - - if [ "$flag_supported" = 'false' ]; then - (>&2 echo "Detected version of ${name_fancy} is: ${version_raw}.") - (>&2 echo "For versions older than ${name_fancy} ${version_good},") - if [ "$OS" = "Linux" ]; then - # For old and/or unsupported Linux distros there's a second chance! - (>&2 echo "the generic Linux runtime is used, if possible.") - check_linux_libc - else - (>&2 echo "there is currently no support.") - exit 13 - fi - fi - - # The sane way to return fancy values with a bash function is to use eval. - eval $version_chevah="'$version_constructed'" -} - -# -# For old unsupported Linux distros (some with no /etc/os-release) and for other -# unsupported Linux distros, we check if the system is based on glibc or musl. -# If so, we use a generic code path that builds everything statically, -# including OpenSSL, thus only requiring glibc or musl. -# -check_linux_libc() { - local ldd_output_file=".chevah_libc_version" - set +o errexit - - command -v ldd > /dev/null - if [ $? -ne 0 ]; then - (>&2 echo "No ldd binary found, can't check for glibc!") - exit 18 - fi - - ldd --version > $ldd_output_file 2>&1 - egrep "GNU libc|GLIBC" $ldd_output_file > /dev/null - if [ $? -eq 0 ]; then - check_glibc_version - else - egrep ^"musl libc" $ldd_output_file > /dev/null - if [ $? -eq 0 ]; then - check_musl_version - else - (>&2 echo "Unknown libc reported by ldd... Unsupported Linux.") - rm $ldd_output_file - exit 19 - fi - fi - - set -o errexit -} - -check_glibc_version(){ - local glibc_version - local glibc_version_array - local supported_glibc2_version - - # Supported minimum minor glibc 2.X versions for various arches. - # For x64, we build on CentOS 5.11 (Final) with glibc 2.5. - # For arm64, we build on Ubuntu 16.04 with glibc 2.23. - # Beware we haven't normalized arch names yet. - case "$ARCH" in - "amd64"|"x86_64"|"x64") - supported_glibc2_version=5 - ;; - "aarch64"|"arm64") - supported_glibc2_version=23 - ;; - *) - (>&2 echo "$ARCH is an unsupported arch for generic Linux!") - exit 17 - ;; - esac - - echo "No specific runtime for the current distribution / version / arch." - echo "Minimum glibc version for this arch: 2.${supported_glibc2_version}." - - # Tested with glibc 2.5/2.11.3/2.12/2.23/2.28-31 and eglibc 2.13/2.19. - glibc_version=$(head -n 1 $ldd_output_file | rev | cut -d\ -f1 | rev) - rm $ldd_output_file - - if [[ $glibc_version =~ [^[:digit:]\.] ]]; then - (>&2 echo "Glibc version should only have numbers and periods, but:") - (>&2 echo " \$glibc_version=$glibc_version") - exit 20 - fi - - IFS=. read -a glibc_version_array <<< "$glibc_version" - - if [ ${glibc_version_array[0]} -ne 2 ]; then - (>&2 echo "Only glibc 2 is supported! Detected version: $glibc_version") - exit 21 - fi - - # Decrement supported_glibc2_version if building against an older glibc. - if [ ${glibc_version_array[1]} -lt ${supported_glibc2_version} ]; then - (>&2 echo "NOT good. Detected version is older: ${glibc_version}!") - exit 22 - else - echo "All is good. Detected glibc version: ${glibc_version}." - fi - - # Supported glibc version detected, set $OS for a generic glibc Linux build. - OS="lnx" -} - -check_musl_version(){ - local musl_version - local musl_version_array - local supported_musl11_version=24 - - echo "No specific runtime for the current distribution / version / arch." - echo "Minimum musl version for this arch: 1.1.${supported_musl11_version}." - - # Tested with musl 1.1.24/1.2.2. - musl_version=$(egrep ^Version $ldd_output_file | cut -d\ -f2) - rm $ldd_output_file - - if [[ $musl_version =~ [^[:digit:]\.] ]]; then - (>&2 echo "Musl version should only have numbers and periods, but:") - (>&2 echo " \$musl_version=$musl_version") - exit 25 - fi - - IFS=. read -a musl_version_array <<< "$musl_version" - - if [ ${musl_version_array[0]} -lt 1 -o ${musl_version_array[1]} -lt 1 ];then - (>&2 echo "Only musl 1.1 or greater supported! Detected: $musl_version") - exit 26 - fi - - # Decrement supported_musl11_version if building against an older musl. - if [ ${musl_version_array[0]} -eq 1 -a ${musl_version_array[1]} -eq 1 \ - -a ${musl_version_array[2]} -lt ${supported_musl11_version} ]; then - (>&2 echo "NOT good. Detected version is older: ${musl_version}!") - exit 27 - else - echo "All is good. Detected musl version: ${musl_version}." - fi - - # Supported musl version detected, set $OS for a generic musl Linux build. - OS="lnx_musl" -} - -# -# For Linux distros with a supported libc, after checking if current version is -# supported with check_os_version(), $OS might be set to something like "lnx" -# if current version is too old, through check_linux_libc() and its subroutines. -# -set_os_if_not_generic() { - local distro_name="$1" - local distro_version="$2" - - # Check if OS starts with "lnx", to match "lnx_musl" too, just in case. - if [ "${OS#lnx}" = "$OS" ]; then - OS="${distro_name}${distro_version}" - fi -} - -# -# Detect OS and ARCH for the current system. -# In some cases we normalize or even override ARCH at the end of this function. -# -detect_os() { - OS=$(uname -s) - - case "$OS" in - MINGW*|MSYS*) - ARCH=$(uname -m) - OS="win" - ;; - Linux) - ARCH=$(uname -m) - if [ ! -f /etc/os-release ]; then - # No /etc/os-release file present, so we don't support this - # distro, but check for glibc, the generic build should work. - check_linux_libc - else - source /etc/os-release - linux_distro="$ID" - distro_fancy_name="$NAME" - # Some rolling-release distros (eg. Arch Linux) have - # no VERSION_ID here, so don't count on it unconditionally. - case "$linux_distro" in - rhel|centos|almalinux|rocky|ol) - os_version_raw="$VERSION_ID" - check_os_version "Red Hat Enterprise Linux" 8 \ - "$os_version_raw" os_version_chevah - if [ ${os_version_chevah} == "8" ]; then - set_os_if_not_generic "rhel" $os_version_chevah - else - # OpenSSL 3.0.x not supported by cryptography 3.3.x. - check_linux_libc - fi - ;; - ubuntu|ubuntu-core) - os_version_raw="$VERSION_ID" - # For versions with older OpenSSL, use generic build. - check_os_version "$distro_fancy_name" 18.04 \ - "$os_version_raw" os_version_chevah - # Only LTS versions are supported. If it doesn't end in - # 04 or first two digits are uneven, use generic build. - if [ ${os_version_chevah%%04} == ${os_version_chevah} \ - -o $(( ${os_version_chevah:0:2} % 2 )) -ne 0 ]; then - check_linux_libc - elif [ ${os_version_chevah} == "2204" ]; then - # OpenSSL 3.0.x not supported by cryptography 3.3.x. - check_linux_libc - fi - set_os_if_not_generic "ubuntu" $os_version_chevah - ;; - *) - # Supported distros with unsupported OpenSSL versions or - # distros not specifically supported: SLES, Debian, etc. - check_linux_libc - ;; - esac - fi - ;; - Darwin) - ARCH=$(uname -m) - os_version_raw=$(sw_vers -productVersion) - # Tested on 10.13, but this works on 10.12 too. Older versions need - # "-Wl,-no_weak_imports" in LDFLAGS to avoid runtime issues. More - # details at https://github.com/Homebrew/homebrew-core/issues/3727. - check_os_version "macOS" 10.12 "$os_version_raw" os_version_chevah - # Build a generic package to cover all supported versions. - OS="macos" - ;; - FreeBSD) - ARCH=$(uname -m) - os_version_raw=$(uname -r | cut -d'.' -f1) - check_os_version "FreeBSD" 12 "$os_version_raw" os_version_chevah - OS="fbsd${os_version_chevah}" - ;; - OpenBSD) - ARCH=$(uname -m) - os_version_raw=$(uname -r) - check_os_version "OpenBSD" 6.7 "$os_version_raw" os_version_chevah - OS="obsd${os_version_chevah}" - ;; - SunOS) - ARCH=$(isainfo -n) - ver_major=$(uname -r | cut -d'.' -f2) - case $ver_major in - 10) - ver_minor=$(\ - head -1 /etc/release | cut -d_ -f2 | sed s/[^0-9]*//g) - ;; - 11) - ver_minor=$(uname -v | cut -d'.' -f2) - ;; - *) - # Not sure if $ver_minor detection works on other versions. - (>&2 echo "Unsupported Solaris version: ${ver_major}.") - exit 15 - ;; - esac - os_version_raw="${ver_major}.${ver_minor}" - check_os_version "Solaris" 11.4 "$os_version_raw" os_version_chevah - OS="sol${os_version_chevah}" - ;; - AIX) - ARCH="ppc$(getconf HARDWARE_BITMODE)" - os_version_raw=$(oslevel) - check_os_version AIX 7.1 "$os_version_raw" os_version_chevah - OS="aix${os_version_chevah}" - ;; - *) - (>&2 echo "Unsupported operating system: ${OS}.") - exit 14 - ;; - esac - - # Normalize arch names. Force 32bit builds on some OS'es. - case "$ARCH" in - "i386"|"i686") - ARCH="x86" - ;; - "amd64"|"x86_64") - ARCH="x64" - ;; - "aarch64") - ARCH="arm64" - ;; - "ppc64") - # Python has not been fully tested on AIX when compiled as a 64bit - # binary, and has math rounding error problems (at least with XL C). - ARCH="ppc" - ;; - "sparcv9") - # We build 32bit binaries on SPARC too. Use "sparc64" for 64bit. - ARCH="sparc" - ;; - esac -} - -detect_os -update_path_variables -set_download_commands - -if [ "$COMMAND" = "clean" ] ; then - clean_build - exit 0 -fi - -if [ "$COMMAND" = "purge" ] ; then - purge_cache - exit 0 -fi - -# Initialize BUILD_ENV_VARS file when building Python from scratch. -if [ "$COMMAND" == "detect_os" ]; then - echo "PYTHON_VERSION=$PYTHON_NAME" > BUILD_ENV_VARS - echo "OS=$OS" >> BUILD_ENV_VARS - echo "ARCH=$ARCH" >> BUILD_ENV_VARS - exit 0 -fi - -if [ "$COMMAND" = "get_python" ] ; then - OS=$2 - ARCH=$3 - resolve_python_version - get_python_dist "$BINARY_DIST_URI" "fallback" - exit 0 -fi - -check_source_folder -copy_python -install_dependencies - -# Update brink.conf dependencies when running deps. -if [ "$COMMAND" == "deps" ] ; then - install_base_deps -fi - -case $COMMAND in - test_ci|test_py3) - PYTHON3_CHECK='-3' - ;; - *) - PYTHON3_CHECK='' - ;; -esac - -set +e -execute_venv "$@" -exit_code=$? -set -e - -exit $exit_code \ No newline at end of file diff --git a/pavement.py b/pavement.py index d5c3d8e..3ded3b8 100644 --- a/pavement.py +++ b/pavement.py @@ -259,21 +259,6 @@ def build(): """ Copy new source code to build folder. """ - if os.name == 'nt': - content = """ -python38.zip -. - -# Uncomment to run site.main() automatically -import site -lib\site-packages -""" - pave.fs.writeContentToFile( - destination=[pave.path.build, 'lib', 'python38._pth'], - content=content, - ) - - @task @needs('build', 'test_python') diff --git a/pythia.conf b/pythia.conf index 60b501b..4bfc061 100644 --- a/pythia.conf +++ b/pythia.conf @@ -1,5 +1,7 @@ -BASE_REQUIREMENTS='chevah-brink==1.0.6 paver==1.2.4' -PYTHON_CONFIGURATION='default@3.8.6.3b1a8ba' +BASE_REQUIREMENTS=('chevah-brink==1.0.10' 'paver==1.3.4' 'wheel') +PYTHON_NAME='python3.11' +PYTHON_VERSION='python3.11' +PYTHON_CONFIGURATION='default@3.11.3.f9d9434' # For production packages there are 2 options: BINARY_DIST_URI='https://github.com/chevah/pythia/releases/download' #BINARY_DIST_URI='https://bin.chevah.com:20443/production' diff --git a/pythia.sh b/pythia.sh index 25812a2..19c89ad 100755 --- a/pythia.sh +++ b/pythia.sh @@ -20,6 +20,8 @@ # * CHEVAH_PYTHON - name of the python versions # * CHEVAH_OS - name of the current OS # * CHEVAH_ARCH - CPU type of the current OS +# * CHEVAH_CACHE - path to the cache directory +# * PIP_INDEX_URL - URL for the used PyPI server. # # The build directory is used from CHEVAH_BUILD env, # then read from pythia.conf as CHEVAH_BUILD_DIR, @@ -39,34 +41,32 @@ set -o errexit # always exit on error set -o errtrace # trap errors in functions as well set -o pipefail # don't ignore exit codes when piping output -# Initialize default value. -COMMAND=${1-''} -DEBUG=${DEBUG-0} +# Initialize default values. +COMMAND="${1-''}" +DEBUG="${DEBUG-0}" # Set default locale. # We use C (alias for POSIX) for having a basic default value and # to make sure we explicitly convert all unicode values. -export LANG='C' -export LANGUAGE='C' -export LC_ALL='C' -export LC_CTYPE='C' -export LC_COLLATE='C' -export LC_MESSAGES='C' -export PATH=$PATH:'/sbin:/usr/sbin:/usr/local/bin' +export LANG="C" +export LANGUAGE="C" +export LC_ALL="C" +export LC_CTYPE="C" +export LC_COLLATE="C" +export LC_MESSAGES="C" +export PATH="$PATH:/sbin:/usr/sbin:/usr/local/bin" # # Global variables. # -# Used to return non-scalar value from functions. -RESULT='' WAS_PYTHON_JUST_INSTALLED=0 -DIST_FOLDER='dist' +DIST_FOLDER="dist" # Path global variables. # Configuration variable. CHEVAH_BUILD_DIR="" -# Variale used at runtime. +# Variable used at runtime. BUILD_FOLDER="" # Configuration variable @@ -79,17 +79,18 @@ PYTHON_LIB="" LOCAL_PYTHON_BINARY_DIST="" # Put default values and create them as global variables. -OS='not-detected-yet' -ARCH='not-detected-yet' +OS="not-detected-yet" +ARCH="not-detected-yet" -# Initialize default values from pythia.conf -PYTHON_CONFIGURATION='NOT-YET-DEFINED' -PYTHON_VERSION='not.defined.yet' -PYTHON_PLATFORM='unknown-os-and-arch' -PYTHON_NAME='python3.8' -BINARY_DIST_URI='https://github.com/chevah/pythia/releases/download' -PIP_INDEX_URL='https://pypi.org/simple' -BASE_REQUIREMENTS='' +# Initialize default values, some are overwritten from pythia.conf. +PYTHON_NAME="not.yet.defined" +PYTHON_CONFIGURATION="NOT-YET-DEFINED" +PYTHON_VERSION="not.defined.yet" +PYTHON_PLATFORM="unknown-os-and-arch" +BINARY_DIST_URI="https://github.com/chevah/pythia/releases/download" +PIP_INDEX_URL="https://pypi.org/simple" +# This is defined as an array to be passed as a chain of options. +BASE_REQUIREMENTS=() # # Check that we have a pavement.py file in the current dir. @@ -97,8 +98,8 @@ BASE_REQUIREMENTS='' # check_source_folder() { if [ ! -e pavement.py ]; then - (>&2 echo 'No "pavement.py" file found in current folder.') - (>&2 echo 'Make sure you are running "pythia.sh" from a source folder.') + (>&2 echo "No 'pavement.py' file found in current folder.") + (>&2 echo "Make sure you are running 'pythia.sh' from a source folder.") exit 8 fi } @@ -106,7 +107,7 @@ check_source_folder() { # Called to trigger the entry point in the virtual environment. # Can be overwritten in pythia.conf execute_venv() { - ${PYTHON_BIN} $PYTHON3_CHECK -c 'from paver.tasks import main; main()' "$@" + "$PYTHON_BIN" -c "from paver.tasks import main; main()" "$@" } @@ -118,13 +119,22 @@ update_venv() { _clean_pyc set +e - ${PYTHON_BIN} -c 'from paver.tasks import main; main()' deps - exit_code=$? + "$PYTHON_BIN" -c "from paver.tasks import main; main()" deps + exit_code="$?" set -e if [ $exit_code -ne 0 ]; then - (>&2 echo 'Failed to run the initial "./pythia.sh deps" command.') + (>&2 echo "Failed to run the initial './pythia.sh deps' command.") exit 7 fi + + set +e + "$PYTHON_BIN" -c "from paver.tasks import main; main()" build + exit_code="$?" + set -e + if [ $exit_code -ne 0 ]; then + (>&2 echo "Failed to run the initial './pythia.sh build' command.") + exit 8 + fi } # Load repo specific configuration. @@ -133,19 +143,19 @@ source pythia.conf clean_build() { # Shortcut for clear since otherwise it will depend on python - echo "Removing ${BUILD_FOLDER}..." - delete_folder ${BUILD_FOLDER} - echo "Removing dist..." - delete_folder ${DIST_FOLDER} - echo "Removing publish..." - delete_folder 'publish' + echo "Removing $BUILD_FOLDER..." + delete_folder "$BUILD_FOLDER" + echo "Removing $DIST_FOLDER..." + delete_folder "$DIST_FOLDER" + echo "Removing publish/..." + delete_folder publish/ # In some case pip hangs with a build folder in temp and # will not continue until it is manually removed. # On the OSX build server tmp is in $TMPDIR - if [ ! -z "${TMPDIR-}" ]; then + if [ -n "${TMPDIR-}" ]; then # check if TMPDIR is set before trying to clean it. - rm -rf ${TMPDIR}/pip* + rm -rf "$TMPDIR"/pip* else rm -rf /tmp/pip* fi @@ -168,7 +178,7 @@ purge_cache() { clean_build echo "Cleaning download cache ..." - rm -rf $CACHE_FOLDER/* + rm -rf "${CACHE_FOLDER:?}"/* } @@ -179,11 +189,13 @@ delete_folder() { local target="$1" # On Windows, we use internal command prompt for maximum speed. # See: https://stackoverflow.com/a/6208144/539264 - if [ $OS = "win" -a -d $target ]; then - cmd //c "del /f/s/q $target > nul" - cmd //c "rmdir /s/q $target" + if [ "$OS" = "win" ]; then + if [ -d "$target" ]; then + cmd //c "del /f/s/q $target > nul" + cmd //c "rmdir /s/q $target" + fi else - rm -rf $target + rm -rf "$target" fi } @@ -192,17 +204,17 @@ delete_folder() { # Wrapper for executing a command and exiting on failure. # execute() { - if [ $DEBUG -ne 0 ]; then - echo "Executing:" $@ + if [ "$DEBUG" -ne 0 ]; then + echo "Executing:" "$@" fi # Make sure $@ is called in quotes as otherwise it will not work. set +e "$@" - exit_code=$? + exit_code="$?" set -e if [ $exit_code -ne 0 ]; then - (>&2 echo "Failed:" $@) + (>&2 echo "Failed:" "$@") exit 1 fi } @@ -213,51 +225,51 @@ execute() { update_path_variables() { resolve_python_version - if [ "${OS}" = "win" ] ; then + if [ "$OS" = "win" ] ; then PYTHON_BIN="/lib/python.exe" PYTHON_LIB="/lib/Lib/" else PYTHON_BIN="/bin/python" - PYTHON_LIB="/lib/${PYTHON_NAME}/" + PYTHON_LIB="/lib/$PYTHON_NAME/" fi # Read first from env var. set +o nounset - BUILD_FOLDER="${CHEVAH_BUILD}" - CACHE_FOLDER="${CHEVAH_CACHE}" + BUILD_FOLDER="$CHEVAH_BUILD" + CACHE_FOLDER="$CHEVAH_CACHE" set -o nounset - if [ "${BUILD_FOLDER}" = "" ] ; then + if [ -z "$BUILD_FOLDER" ] ; then # Use value from configuration file. - BUILD_FOLDER="${CHEVAH_BUILD_DIR}" + BUILD_FOLDER="$CHEVAH_BUILD_DIR" fi - if [ "${BUILD_FOLDER}" = "" ] ; then + if [ -z "$BUILD_FOLDER" ] ; then # Use default value if not yet defined. - BUILD_FOLDER="build-${OS}-${ARCH}" + BUILD_FOLDER="build-$OS-$ARCH" fi - if [ "${CACHE_FOLDER}" = "" ] ; then + if [ -z "$CACHE_FOLDER" ] ; then # Use default if not yet defined. - CACHE_FOLDER="${CHEVAH_CACHE_DIR}" + CACHE_FOLDER="$CHEVAH_CACHE_DIR" fi - if [ "${CACHE_FOLDER}" = "" ] ; then + if [ -z "$CACHE_FOLDER" ] ; then # Use default if not yet defined. CACHE_FOLDER="cache" fi - PYTHON_BIN="${BUILD_FOLDER}${PYTHON_BIN}" - PYTHON_LIB="${BUILD_FOLDER}${PYTHON_LIB}" + PYTHON_BIN="$BUILD_FOLDER/$PYTHON_BIN" + PYTHON_LIB="$BUILD_FOLDER/$PYTHON_LIB" LOCAL_PYTHON_BINARY_DIST="$PYTHON_NAME-$OS-$ARCH" - export PYTHONPATH=${BUILD_FOLDER} - export CHEVAH_PYTHON=${PYTHON_NAME} - export CHEVAH_OS=${OS} - export CHEVAH_ARCH=${ARCH} - export CHEVAH_CACHE=${CACHE_FOLDER} - export PIP_INDEX_URL=${PIP_INDEX_URL} + export PYTHONPATH="$BUILD_FOLDER" + export CHEVAH_PYTHON="$PYTHON_NAME" + export CHEVAH_OS="$OS" + export CHEVAH_ARCH="$ARCH" + export CHEVAH_CACHE="$CACHE_FOLDER" + export PIP_INDEX_URL="$PIP_INDEX_URL" } @@ -266,7 +278,7 @@ update_path_variables() { # advertised by the current environment. # resolve_python_version() { - local version_configuration=$PYTHON_CONFIGURATION + local version_configuration="$PYTHON_CONFIGURATION" local version_configuration_array local candidate local candidate_platform @@ -275,18 +287,18 @@ resolve_python_version() { PYTHON_PLATFORM="$OS-$ARCH" # Using ':' as a delimiter, populate a dedicated array. - IFS=: read -a version_configuration_array <<< "$version_configuration" + IFS=: read -r -a version_configuration_array <<< "$version_configuration" # Iterate through all the elements of the array to find the best candidate. for (( i=0 ; i < ${#version_configuration_array[@]}; i++ )); do candidate="${version_configuration_array[$i]}" - candidate_platform=$(echo "$candidate" | cut -d "@" -f 1) - candidate_version=$(echo "$candidate" | cut -d "@" -f 2) + candidate_platform="$(echo "$candidate" | cut -d"@" -f1)" + candidate_version="$(echo "$candidate" | cut -d"@" -f2)" if [ "$candidate_platform" = "default" ]; then # On first pass, we set the default version. - PYTHON_VERSION=$candidate_version - elif [ "${PYTHON_PLATFORM%$candidate_platform*}" = "" ]; then + PYTHON_VERSION="$candidate_version" + elif [ -z "${PYTHON_PLATFORM%"$candidate_platform"*}" ]; then # If matching a specific platform, we overwrite the default version. - PYTHON_VERSION=$candidate_version + PYTHON_VERSION="$candidate_version" fi done } @@ -296,35 +308,24 @@ resolve_python_version() { # Install base package. # install_base_deps() { - echo "Installing base requirements: $BASE_REQUIREMENTS." - pip_install "$BASE_REQUIREMENTS" -} - - -# -# Wrapper for python `pip install` command. -# * $1 - package_name and optional version. -# -pip_install() { - echo "::group::pip install $1" + echo "::groups::Installing base requirements:" "${BASE_REQUIREMENTS[@]}" set +e # There is a bug in pip/setuptools when using custom build folders. # See https://github.com/pypa/pip/issues/3564 - rm -rf ${BUILD_FOLDER}/pip-build - ${PYTHON_BIN} -m \ + rm -rf "${BUILD_FOLDER:?}"/pip-build + "$PYTHON_BIN" -m \ pip install \ - --index-url=$PIP_INDEX_URL \ - --build=${BUILD_FOLDER}/pip-build \ - $1 + --index-url="$PIP_INDEX_URL" \ + "${BASE_REQUIREMENTS[@]}" - exit_code=$? + exit_code="$?" echo "::endgroup::" set -e if [ $exit_code -ne 0 ]; then - (>&2 echo "Failed to install $1.") + (>&2 echo "Failed to install" "${BASE_REQUIREMENTS[@]}") exit 2 fi } @@ -334,22 +335,22 @@ pip_install() { # set_download_commands() { set +o errexit - command -v curl > /dev/null - if [ $? -eq 0 ]; then - # Options not used because of no support in CentOS 5.11's curl: + if command -v curl > /dev/null; then + # Options not used because of no support in older curl versions: # --retry-connrefused (since curl 7.52.0) # --retry-all-errors (since curl 7.71.0) # Retry 2 times, allocating 10s for the connection phase, # at most 300s for an attempt, sleeping for 5s between retries. - CURL_RETRY_OPTS="\ + # Strings wouldn't work when quoted, using Bash arrays instead. + CURL_RETRY_OPTS=(\ --retry 2 \ --connect-timeout 10 \ --max-time 300 \ --retry-delay 5 \ - " - DOWNLOAD_CMD="curl --remote-name --location $CURL_RETRY_OPTS" - ONLINETEST_CMD="curl --fail --silent --head $CURL_RETRY_OPTS \ - --output /dev/null" + ) + DOWNLOAD_CMD=(curl --remote-name --location "${CURL_RETRY_OPTS[@]}") + ONLINETEST_CMD=(curl --fail --silent --head "${CURL_RETRY_OPTS[@]}" \ + --output /dev/null) set -o errexit return fi @@ -361,26 +362,26 @@ set_download_commands() { # Download and extract a binary distribution. # get_binary_dist() { - local dist_name=$1 - local remote_base_url=$2 + local dist_name="$1" + local remote_base_url="$2" echo "Getting $dist_name from $remote_base_url..." - tar_gz_file=${dist_name}.tar.gz - tar_file=${dist_name}.tar + tar_gz_file="$dist_name".tar.gz + tar_file="$dist_name".tar - mkdir -p ${CACHE_FOLDER} - pushd ${CACHE_FOLDER} + mkdir -p "$CACHE_FOLDER" + pushd "$CACHE_FOLDER" # Get and extract archive. - rm -rf $dist_name - rm -f $tar_gz_file - rm -f $tar_file - execute $DOWNLOAD_CMD $remote_base_url/${tar_gz_file} - execute gunzip -f $tar_gz_file - execute tar -xf $tar_file - rm -f $tar_gz_file - rm -f $tar_file + rm -rf "$dist_name" + rm -f "$tar_gz_file" + rm -f "$tar_file" + execute "${DOWNLOAD_CMD[@]}" "$remote_base_url"/"$tar_gz_file" + execute gunzip -f "$tar_gz_file" + execute tar -xf "$tar_file" + rm -f "$tar_gz_file" + rm -f "$tar_file" popd } @@ -389,11 +390,11 @@ get_binary_dist() { # Check if we have a versioned Python distribution. # test_version_exists() { - local remote_base_url=$1 - local target_file=python-${PYTHON_VERSION}-${OS}-${ARCH}.tar.gz + local remote_base_url="$1" + local target_file="python-$PYTHON_VERSION-$OS-$ARCH.tar.gz" - echo "Checking $remote_base_url/${PYTHON_VERSION}/$target_file" - $ONLINETEST_CMD $remote_base_url/${PYTHON_VERSION}/$target_file + echo "Checking $remote_base_url/$PYTHON_VERSION/$target_file..." + "${ONLINETEST_CMD[@]}" "$remote_base_url"/"$PYTHON_VERSION"/"$target_file" return $? } @@ -401,19 +402,19 @@ test_version_exists() { # Download and extract in cache the python distributable. # get_python_dist() { - local remote_base_url=$1 - local download_mode=$2 - local python_distributable=python-${PYTHON_VERSION}-${OS}-${ARCH} + local remote_base_url="$1" + local python_distributable="python-$PYTHON_VERSION-$OS-$ARCH" local onlinetest_errorcode set +o errexit - test_version_exists $remote_base_url - onlinetest_errorcode=$? + test_version_exists "$remote_base_url" + onlinetest_errorcode="$?" set -o errexit if [ $onlinetest_errorcode -eq 0 ]; then # We have the requested python version. - get_binary_dist $python_distributable $remote_base_url/${PYTHON_VERSION} + get_binary_dist "$python_distributable" \ + "$remote_base_url"/"$PYTHON_VERSION" else (>&2 echo "Couldn't find package on remote server. Full link:") echo "$remote_base_url/$PYTHON_VERSION/$python_distributable.tar.gz" @@ -429,51 +430,51 @@ COPY_PYTHON_RECURSIONS=0 # Copy python to build folder from binary distribution. # copy_python() { - local python_distributable="${CACHE_FOLDER}/${LOCAL_PYTHON_BINARY_DIST}" + local python_distributable="$CACHE_FOLDER/$LOCAL_PYTHON_BINARY_DIST" local python_installed_version - COPY_PYTHON_RECURSIONS=`expr $COPY_PYTHON_RECURSIONS + 1` + COPY_PYTHON_RECURSIONS="$((COPY_PYTHON_RECURSIONS + 1))" - if [ $COPY_PYTHON_RECURSIONS -gt 2 ]; then + if [ "$COPY_PYTHON_RECURSIONS" -gt 2 ]; then (>&2 echo "Too many calls to copy_python: $COPY_PYTHON_RECURSIONS") exit 5 fi # Check that python dist was installed - if [ ! -s ${PYTHON_BIN} ]; then + if [ ! -s "$PYTHON_BIN" ]; then # We don't have a Python binary, so we install it since everything # else depends on it. echo "::group::Get Python" - echo "Bootstrapping ${LOCAL_PYTHON_BINARY_DIST} environment" \ - "to ${BUILD_FOLDER}..." - mkdir -p ${BUILD_FOLDER} + echo "Bootstrapping $LOCAL_PYTHON_BINARY_DIST environment" \ + "to $BUILD_FOLDER..." + mkdir -p "$BUILD_FOLDER" - if [ -d ${python_distributable} ]; then + if [ -d "$python_distributable" ]; then # We have a cached distributable. # Check if is at the right version. local cache_ver_file - cache_ver_file=${python_distributable}/lib/PYTHIA_VERSION - cache_version='UNVERSIONED' - if [ -f $cache_ver_file ]; then - cache_version=`cat $cache_ver_file | cut -d - -f 1` + cache_ver_file="$python_distributable"/lib/PYTHIA_VERSION + cache_version="UNVERSIONED" + if [ -f "$cache_ver_file" ]; then + cache_version="$(cut -d"-" -f1 < "$cache_ver_file")" fi if [ "$PYTHON_VERSION" != "$cache_version" ]; then # We have a different version in the cache. # Just remove it and hope that the next step will download # the right one. - rm -rf ${python_distributable} + rm -rf "$python_distributable" fi fi - if [ ! -d ${python_distributable} ]; then + if [ ! -d "$python_distributable" ]; then # We don't have a cached python distributable. - echo "No ${LOCAL_PYTHON_BINARY_DIST} environment." \ + echo "No $LOCAL_PYTHON_BINARY_DIST environment." \ "Start downloading it..." - get_python_dist "$BINARY_DIST_URI" "strict" + get_python_dist "$BINARY_DIST_URI" fi echo "Copying Python distribution files... " - cp -R ${python_distributable}/* ${BUILD_FOLDER} + cp -R "$python_distributable"/* "$BUILD_FOLDER" echo "::endgroup::" @@ -481,19 +482,19 @@ copy_python() { WAS_PYTHON_JUST_INSTALLED=1 else # We have a Python, but we are not sure if is the right version. - local version_file=${BUILD_FOLDER}/lib/PYTHIA_VERSION + local version_file="$BUILD_FOLDER"/lib/PYTHIA_VERSION # If we are upgrading the cache from Python 2, - # cat fails if this file is missing, so we create it blank. - touch $version_file - python_installed_version=`cat $version_file | cut -d - -f 1` + # This file is required, so we create it if non-existing. + touch "$version_file" + python_installed_version="$(cut -d"-" -f1 < "$version_file")" if [ "$PYTHON_VERSION" != "$python_installed_version" ]; then # We have a different python installed. # Check if we have the to-be-updated version and fail if # it does not exists. set +o errexit test_version_exists "$BINARY_DIST_URI" - local test_version=$? + local test_version="$?" set -o errexit if [ $test_version -ne 0 ]; then (>&2 echo "The build is now at $python_installed_version.") @@ -504,9 +505,9 @@ copy_python() { # Remove it and try to install it again. echo "Updating Python from" \ - $python_installed_version to $PYTHON_VERSION - rm -rf ${BUILD_FOLDER}/* - rm -rf ${python_distributable} + "$python_installed_version to $PYTHON_VERSION" + rm -rf "${BUILD_FOLDER:?}"/* + rm -rf "$python_distributable" copy_python fi fi @@ -517,85 +518,93 @@ copy_python() { # Install dependencies after python was just installed. # install_dependencies(){ - if [ $WAS_PYTHON_JUST_INSTALLED -ne 1 ]; then + if [ "$WAS_PYTHON_JUST_INSTALLED" -ne 1 ]; then return fi - if [ "$COMMAND" == "deps" ] ; then - # Will be installed soon. - return + update_venv + + # Deps command was just requested. + # End the process here so that we will not re-run it as part of the + # general command handling. + if [ "$COMMAND" = "deps" ] ; then + exit 0 fi - update_venv } # # Check version of current OS to see if it is supported. # If it's too old, exit with a nice informative message. -# If it's supported, return through eval the version numbers to be used for -# naming the package, for example: '8' for RHEL 8.2, '2004' for Ubuntu 20.04. +# If it's supported, return through eval the version digits to be used for +# naming the package, e.g.: "12" for FreeBSD 12.x or "114" for Solaris 11.4. # check_os_version() { # First parameter should be the human-readable name for the current OS. - # For example: "Red Hat Enterprise Linux" for RHEL, "macOS" for Darwin etc. - # Second and third parameters must be strings composed of integers + # For example: "Solaris" for SunOS ,"macOS" for Darwin, etc. + # Second and third parameters must be strings composed of digits # delimited with dots, representing, in order, the oldest version # supported for the current OS and the current detected version. - # The fourth parameter is used to return through eval the relevant numbers - # for naming the Python package for the current OS, as detailed above. + # The fourth parameter is used to return through eval the relevant digits + # for naming the Pythia package for the current OS, as detailed above. local name_fancy="$1" local version_good="$2" local version_raw="$3" local version_chevah="$4" - local version_constructed='' - local flag_supported='good_enough' + # Version string built in this function, passed back for naming the package. + # Uses the same number of version digits as the "$version_chevah" variable, + # e.g. for FreeBSD it would be "12", even if OS version is actually "12.1". + local version_built="" + # If major/minor/patch/etc. version digits are the same, it's good enough. + local flag_supported="good_enough" local version_raw_array local version_good_array - if [[ $version_raw =~ [^[:digit:]\.] ]]; then - (>&2 echo "OS version should only have numbers and periods, but:") + if [[ "$version_raw" =~ [^[:digit:]\.] ]]; then + (>&2 echo "OS version should only have digits and dots, but:") (>&2 echo " \$version_raw=$version_raw") exit 12 fi - # Using '.' as a delimiter, populate the version_* arrays. - IFS=. read -a version_raw_array <<< "$version_raw" - IFS=. read -a version_good_array <<< "$version_good" + # Using '.' as a delimiter, populate corresponding version_* arrays. + IFS=. read -r -a version_raw_array <<< "$version_raw" + IFS=. read -r -a version_good_array <<< "$version_good" - # Iterate through all the integers from the good version to compare them - # one by one with the corresponding integers from the supported version. + # Iterate through all the digits from the good version to compare them + # one by one with the corresponding digits from the detected version. for (( i=0 ; i < ${#version_good_array[@]}; i++ )); do - version_constructed="${version_constructed}${version_raw_array[$i]}" - if [ ${version_raw_array[$i]} -gt ${version_good_array[$i]} -a \ - "$flag_supported" = 'good_enough' ]; then - flag_supported='true' - elif [ ${version_raw_array[$i]} -lt ${version_good_array[$i]} -a \ - "$flag_supported" = 'good_enough' ]; then - flag_supported='false' + version_built="${version_built}${version_raw_array[$i]}" + # There is nothing to do if versions are the same, that's good enough. + if [ "${version_raw_array[$i]}" -gt "${version_good_array[$i]}" ]; then + # First newer version! Comparing more minor versions is irrelevant. + # Up to now, compared versions were the same, if there were others. + if [ "$flag_supported" = "good_enough" ]; then + flag_supported="newer_version" + fi + elif [ "${version_raw_array[$i]}" -lt "${version_good_array[$i]}" ];then + # First older version! Comparing more minor versions is irrelevant. + # Up to now, compared versions were the same, if there were others. + if [ "$flag_supported" = "good_enough" ]; then + flag_supported="false" + fi fi done - if [ "$flag_supported" = 'false' ]; then - (>&2 echo "Detected version of ${name_fancy} is: ${version_raw}.") - (>&2 echo "For versions older than ${name_fancy} ${version_good},") - if [ "$OS" = "Linux" ]; then - # For old and/or unsupported Linux distros there's a second chance! - (>&2 echo "the generic Linux runtime is used, if possible.") - check_linux_libc - else - (>&2 echo "there is currently no support.") - exit 13 - fi + # If "$flag_supported" is "newer_version" / "good_enough" is now irrelevant. + if [ "$flag_supported" = "false" ]; then + (>&2 echo "Detected version of $name_fancy is: $version_raw.") + (>&2 echo "For versions older than $name_fancy $version_good,") + (>&2 echo "there is currently no support.") + exit 13 fi - # The sane way to return fancy values with a bash function is to use eval. - eval $version_chevah="'$version_constructed'" + # The sane way to return fancy values with a Bash function is to use eval. + eval "$version_chevah"="'$version_built'" } # -# For old unsupported Linux distros (some with no /etc/os-release) and for other -# unsupported Linux distros, we check if the system is based on glibc or musl. +# On Linux, we check if the system is based on glibc or musl. # If so, we use a generic code path that builds everything statically, # including OpenSSL, thus only requiring glibc or musl. # @@ -603,23 +612,20 @@ check_linux_libc() { local ldd_output_file=".chevah_libc_version" set +o errexit - command -v ldd > /dev/null - if [ $? -ne 0 ]; then - (>&2 echo "No ldd binary found, can't check for glibc!") + if ! command -v ldd > /dev/null; then + (>&2 echo "No ldd binary found, can't check the libc version!") exit 18 fi - ldd --version > $ldd_output_file 2>&1 - egrep "GNU libc|GLIBC" $ldd_output_file > /dev/null - if [ $? -eq 0 ]; then + ldd --version > "$ldd_output_file" 2>&1 + if grep -E -q "GNU libc|GLIBC" "$ldd_output_file"; then check_glibc_version else - egrep ^"musl libc" $ldd_output_file > /dev/null - if [ $? -eq 0 ]; then + if grep -E -q ^"musl libc" $ldd_output_file; then check_musl_version else - (>&2 echo "Unknown libc reported by ldd... Unsupported Linux.") - rm $ldd_output_file + (>&2 echo "Unknown libc reported by ldd... Unsupported Linux!") + rm "$ldd_output_file" exit 19 fi fi @@ -633,105 +639,89 @@ check_glibc_version(){ local supported_glibc2_version # Supported minimum minor glibc 2.X versions for various arches. - # For x64, we build on CentOS 5.11 (Final) with glibc 2.5. - # For arm64, we build on Ubuntu 16.04 with glibc 2.23. - # Beware we haven't normalized arch names yet. - case "$ARCH" in - "amd64"|"x86_64"|"x64") - supported_glibc2_version=5 - ;; - "aarch64"|"arm64") - supported_glibc2_version=23 - ;; - *) - (>&2 echo "$ARCH is an unsupported arch for generic Linux!") - exit 17 - ;; - esac + # For x64, we build on Amazon 2 with glibc 2.26. + # For arm64, we also build on Amazon 2 with glibc 2.26 lately. + # If we get back to building against different libc versions per arch, + # beware we haven't normalized arch names yet. + supported_glibc2_version=26 echo "No specific runtime for the current distribution / version / arch." - echo "Minimum glibc version for this arch: 2.${supported_glibc2_version}." + echo "Minimum glibc version for this arch: 2.$supported_glibc2_version." - # Tested with glibc 2.5/2.11.3/2.12/2.23/2.28-31 and eglibc 2.13/2.19. - glibc_version=$(head -n 1 $ldd_output_file | rev | cut -d\ -f1 | rev) - rm $ldd_output_file + # Tested with glibc 2.5/2.11.3/2.12/2.23/2.28-35 and eglibc 2.13/2.19. + glibc_version="$(head -n 1 "$ldd_output_file" | rev | cut -d" " -f1 | rev)" + rm "$ldd_output_file" - if [[ $glibc_version =~ [^[:digit:]\.] ]]; then - (>&2 echo "Glibc version should only have numbers and periods, but:") + if [[ "$glibc_version" =~ [^[:digit:]\.] ]]; then + (>&2 echo "Glibc version should only have digits and dots, but:") (>&2 echo " \$glibc_version=$glibc_version") exit 20 fi - IFS=. read -a glibc_version_array <<< "$glibc_version" + IFS=. read -r -a glibc_version_array <<< "$glibc_version" - if [ ${glibc_version_array[0]} -ne 2 ]; then + if [ "${glibc_version_array[0]}" -ne 2 ]; then (>&2 echo "Only glibc 2 is supported! Detected version: $glibc_version") exit 21 fi - # Decrement supported_glibc2_version if building against an older glibc. - if [ ${glibc_version_array[1]} -lt ${supported_glibc2_version} ]; then - (>&2 echo "NOT good. Detected version is older: ${glibc_version}!") + # Decrement supported_glibc2_version above if building against older glibc. + if [ "${glibc_version_array[1]}" -lt "$supported_glibc2_version" ]; then + (>&2 echo "NOT good. Detected version is older: $glibc_version!") exit 22 else - echo "All is good. Detected glibc version: ${glibc_version}." + echo "All is good. Detected glibc version: $glibc_version." fi # Supported glibc version detected, set $OS for a generic glibc Linux build. - OS="lnx" + OS="linux" } check_musl_version(){ local musl_version local musl_version_array + local musl_version_unsupported="false" local supported_musl11_version=24 echo "No specific runtime for the current distribution / version / arch." - echo "Minimum musl version for this arch: 1.1.${supported_musl11_version}." + echo "Minimum musl version for this arch: 1.1.$supported_musl11_version." # Tested with musl 1.1.24/1.2.2. - musl_version=$(egrep ^Version $ldd_output_file | cut -d\ -f2) - rm $ldd_output_file + musl_version="$(grep -E ^"Version" "$ldd_output_file" | cut -d" " -f2)" + rm "$ldd_output_file" - if [[ $musl_version =~ [^[:digit:]\.] ]]; then - (>&2 echo "Musl version should only have numbers and periods, but:") + if [[ "$musl_version" =~ [^[:digit:]\.] ]]; then + (>&2 echo "Musl version should only have digits and dots, but:") (>&2 echo " \$musl_version=$musl_version") exit 25 fi - IFS=. read -a musl_version_array <<< "$musl_version" + IFS=. read -r -a musl_version_array <<< "$musl_version" + + # Decrement supported_musl11_version above if building against older musl. + if [ "${musl_version_array[0]}" -lt 1 ]; then + musl_version_unsupported="true" + elif [ "${musl_version_array[0]}" -eq 1 ]; then + if [ "${musl_version_array[1]}" -lt 1 ];then + musl_version_unsupported="true" + elif [ "${musl_version_array[1]}" -eq 1 ];then + if [ "${musl_version_array[2]}" -lt "$supported_musl11_version" ] + then + (>&2 echo "NOT good. Detected version is older: $musl_version!") + exit 27 + fi + fi + fi - if [ ${musl_version_array[0]} -lt 1 -o ${musl_version_array[1]} -lt 1 ];then + if [ "$musl_version_unsupported" = "true" ]; then (>&2 echo "Only musl 1.1 or greater supported! Detected: $musl_version") exit 26 fi - # Decrement supported_musl11_version if building against an older musl. - if [ ${musl_version_array[0]} -eq 1 -a ${musl_version_array[1]} -eq 1 \ - -a ${musl_version_array[2]} -lt ${supported_musl11_version} ]; then - (>&2 echo "NOT good. Detected version is older: ${musl_version}!") - exit 27 - else - echo "All is good. Detected musl version: ${musl_version}." - fi + echo "All is good. Detected musl version: $musl_version." # Supported musl version detected, set $OS for a generic musl Linux build. - OS="lnx_musl" -} - -# -# For Linux distros with a supported libc, after checking if current version is -# supported with check_os_version(), $OS might be set to something like "lnx" -# if current version is too old, through check_linux_libc() and its subroutines. -# -set_os_if_not_generic() { - local distro_name="$1" - local distro_version="$2" - - if [ "${OS#lnx}" = "$OS" ]; then - # $OS doesn't start with lnx, not a generic Linux build. - OS="${distro_name}${distro_version}" - fi + OS="linux_musl" } @@ -740,103 +730,56 @@ set_os_if_not_generic() { # In some cases we normalize or even override ARCH at the end of this function. # detect_os() { - OS=$(uname -s) + local os_version_chevah="" + OS="$(uname -s)" case "$OS" in MINGW*|MSYS*) - ARCH=$(uname -m) + ARCH="$(uname -m)" OS="win" ;; Linux) - ARCH=$(uname -m) - if [ ! -f /etc/os-release ]; then - # No /etc/os-release file present, so we don't support this - # distro, but check for glibc, the generic build should work. - check_linux_libc - else - source /etc/os-release - linux_distro="$ID" - distro_fancy_name="$NAME" - # Some rolling-release distros (eg. Arch Linux) have - # no VERSION_ID here, so don't count on it unconditionally. - case "$linux_distro" in - rhel|centos|almalinux|rocky|ol) - os_version_raw="$VERSION_ID" - check_os_version "Red Hat Enterprise Linux" 8 \ - "$os_version_raw" os_version_chevah - if [ ${os_version_chevah} == "8" ]; then - set_os_if_not_generic "rhel" $os_version_chevah - else - # OpenSSL 3.0.x not supported by cryptography 3.3.x. - check_linux_libc - fi - ;; - ubuntu|ubuntu-core) - os_version_raw="$VERSION_ID" - # For versions with older OpenSSL, use generic build. - check_os_version "$distro_fancy_name" 18.04 \ - "$os_version_raw" os_version_chevah - # Only LTS versions are supported. If it doesn't end in - # 04 or first two digits are uneven, use generic build. - if [ ${os_version_chevah%%04} == ${os_version_chevah} \ - -o $(( ${os_version_chevah:0:2} % 2 )) -ne 0 ]; then - check_linux_libc - elif [ ${os_version_chevah} == "2204" ]; then - # OpenSSL 3.0.x not supported by cryptography 3.3.x. - check_linux_libc - fi - set_os_if_not_generic "ubuntu" $os_version_chevah - ;; - *) - # Supported distros with unsupported OpenSSL versions or - # distros not specifically supported: SLES, Debian, etc. - check_linux_libc - ;; - esac - fi + ARCH="$(uname -m)" + check_linux_libc ;; Darwin) - ARCH=$(uname -m) - os_version_raw=$(sw_vers -productVersion) + ARCH="$(uname -m)" + os_version_raw="$(sw_vers -productVersion)" check_os_version "macOS" 10.13 "$os_version_raw" os_version_chevah # Build a generic package to cover all supported versions. OS="macos" ;; FreeBSD) - ARCH=$(uname -m) - os_version_raw=$(uname -r | cut -d'.' -f1) + ARCH="$(uname -m)" + os_version_raw="$(uname -r | cut -d'.' -f1)" check_os_version "FreeBSD" 12 "$os_version_raw" os_version_chevah - OS="fbsd${os_version_chevah}" + OS="fbsd$os_version_chevah" ;; OpenBSD) - ARCH=$(uname -m) - os_version_raw=$(uname -r) + ARCH="$(uname -m)" + os_version_raw="$(uname -r)" check_os_version "OpenBSD" 6.7 "$os_version_raw" os_version_chevah - OS="obsd${os_version_chevah}" + OS="obsd$os_version_chevah" ;; SunOS) - ARCH=$(isainfo -n) - ver_major=$(uname -r | cut -d'.' -f2) + ARCH="$(isainfo -n)" + ver_major="$(uname -r | cut -d"." -f2)" case $ver_major in - 10) - ver_minor=$(\ - head -1 /etc/release | cut -d_ -f2 | sed s/[^0-9]*//g) - ;; 11) - ver_minor=$(uname -v | cut -d'.' -f2) + ver_minor="$(uname -v | cut -d"." -f2)" ;; *) - # Not sure if $ver_minor detection works on other versions. - (>&2 echo "Unsupported Solaris version: ${ver_major}.") + # Note $ver_minor detection doesn't work on older versions. + (>&2 echo "Unsupported Solaris version: $ver_major.") exit 15 ;; esac - os_version_raw="${ver_major}.${ver_minor}" + os_version_raw="$ver_major.$ver_minor" check_os_version "Solaris" 11.4 "$os_version_raw" os_version_chevah - OS="sol${os_version_chevah}" + OS="sol$os_version_chevah" ;; *) - (>&2 echo "Unsupported operating system: ${OS}.") + (>&2 echo "Unsupported operating system: $OS.") exit 14 ;; esac @@ -869,8 +812,8 @@ if [ "$COMMAND" = "purge" ] ; then exit 0 fi -# Initialize BUILD_ENV_VARS file when building Python from scratch. -if [ "$COMMAND" == "detect_os" ]; then +# Pass OS-specific values through a file when building Python from scratch. +if [ "$COMMAND" = "detect_os" ]; then echo "PYTHON_VERSION=$PYTHON_NAME" > BUILD_ENV_VARS echo "OS=$OS" >> BUILD_ENV_VARS echo "ARCH=$ARCH" >> BUILD_ENV_VARS @@ -878,10 +821,10 @@ if [ "$COMMAND" == "detect_os" ]; then fi if [ "$COMMAND" = "get_python" ] ; then - OS=$2 - ARCH=$3 + OS="$2" + ARCH="$3" resolve_python_version - get_python_dist "$BINARY_DIST_URI" "fallback" + get_python_dist "$BINARY_DIST_URI" exit 0 fi @@ -890,22 +833,13 @@ copy_python install_dependencies # Update pythia.conf dependencies when running deps. -if [ "$COMMAND" == "deps" ] ; then +if [ "$COMMAND" = "deps" ] ; then install_base_deps fi -case $COMMAND in - test_ci|test_py3) - PYTHON3_CHECK='-3' - ;; - *) - PYTHON3_CHECK='' - ;; -esac - set +e execute_venv "$@" -exit_code=$? +exit_code="$?" set -e exit $exit_code diff --git a/release-notes.rst b/release-notes.rst index fdb81a2..67c6452 100644 --- a/release-notes.rst +++ b/release-notes.rst @@ -1,6 +1,13 @@ Release notes for chevah.compat =============================== + +1.0.9 - 2023-07-04 +-------------------- + +* Update for python 3.11. + + 1.0.8 - 2023-05-23 -------------------- diff --git a/setup.cfg b/setup.cfg index 8c0e49b..12ad746 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = chevah-compat -version = 1.0.8 +version = 1.0.9 maintainer = Adi Roiban maintainer_email = adi.roiban@proatria.com license = BSD @@ -15,9 +15,8 @@ python_requires = ~=3.8 install_requires = # The runtime dependencies should be relaxed as otherise it will # generate conflicts with the code using chevah-compat. - zope.interface >= 5.4.0+chevah.2 + zope.interface >= 5.4.0 pywin32 >= 305 ; platform_system == "Windows" - lockfile >= 0.9.1 ; platform_system == "Linux" python-pam >= 2.0.2 ; platform_system == "Linux" ; Used to detect Linux distributions. distro >= 1.6.0 diff --git a/src/chevah_compat/__init__.py b/src/chevah_compat/__init__.py index a1b908a..974326c 100644 --- a/src/chevah_compat/__init__.py +++ b/src/chevah_compat/__init__.py @@ -8,6 +8,7 @@ from __future__ import print_function from __future__ import division from __future__ import absolute_import + import os if os.name == 'posix': diff --git a/src/chevah_compat/testing/testcase.py b/src/chevah_compat/testing/testcase.py index 18f01e0..ab4bb26 100644 --- a/src/chevah_compat/testing/testcase.py +++ b/src/chevah_compat/testing/testcase.py @@ -104,7 +104,7 @@ def _caller_success_member(self): """ Return true if last test run was successful. """ - if self._outcome.errors: + if self._outcome.result.errors: return False return True