commit:     c17e9074f2853e54fc7fb08049453d54a1b6cb8b
Author:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
AuthorDate: Sat May 30 16:16:07 2015 +0000
Commit:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
CommitDate: Thu Jun  4 02:50:39 2015 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=c17e9074

runtests: rewrite in python

The bash was getting ugly, and this allows us to add more smarts sanely
to the main script.

 DEVELOPING  |   2 +-
 runtests    | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 runtests.sh | 109 ------------------------------------------
 3 files changed, 157 insertions(+), 110 deletions(-)

diff --git a/DEVELOPING b/DEVELOPING
index 0b0bb60..31b5594 100644
--- a/DEVELOPING
+++ b/DEVELOPING
@@ -225,7 +225,7 @@ Second create a git tag for this release:
 Then create the tarball and run the tests:
        ./mkrelease.sh --changelog-rev v2.2.7 --tag --runtests 2.2.8
 Make sure you have all supported python versions installed first
-(see PYTHON_SUPPORTED_VERSIONS in runtests.sh).
+(see PYTHON_SUPPORTED_VERSIONS in runtests).
 
 Version bump the ebuild and verify it can re-install itself:
        emerge portage

diff --git a/runtests b/runtests
new file mode 100755
index 0000000..d1f7b6f
--- /dev/null
+++ b/runtests
@@ -0,0 +1,156 @@
+#!/usr/bin/python
+# Copyright 2010-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+#
+# Note: We don't want to import portage modules directly because we do things
+# like run the testsuite through multiple versions of python.
+
+"""Helper script to run portage unittests against different python versions.
+
+Note: Any additional arguments will be passed down directly to the underlying
+unittest runner.  This lets you select specific tests to execute.
+"""
+
+from __future__ import print_function
+
+import argparse
+import os
+import sys
+import subprocess
+
+
+# These are the versions we fully support and require to pass tests.
+PYTHON_SUPPORTED_VERSIONS = [
+       '2.7',
+       '3.3',
+       '3.4',
+]
+# The rest are just "nice to have".
+PYTHON_NICE_VERSIONS = [
+       'pypy',
+       '3.5',
+]
+
+EPREFIX = os.environ.get('PORTAGE_OVERRIDE_EPREFIX', '/')
+
+
+class Colors(object):
+       """Simple object holding color constants."""
+
+       _COLORS_YES = ('y', 'yes', 'true')
+       _COLORS_NO = ('n', 'no', 'false')
+
+       GOOD = BAD = NORMAL = ''
+
+       def __init__(self, colorize=None):
+               if colorize is None:
+                       nocolors = os.environ.get('NOCOLOR', 'false')
+                       # Ugh, look away, for here we invert the world!
+                       if nocolors in self._COLORS_YES:
+                               colorize = False
+                       elif nocolors in self._COLORS_NO:
+                               colorize = True
+                       else:
+                               raise ValueError('$NOCOLORS is invalid: %s' % 
nocolors)
+               else:
+                       if colorize in self._COLORS_YES:
+                               colorize = True
+                       elif colorize in self._COLORS_NO:
+                               colorize = False
+                       else:
+                               raise ValueError('--colors is invalid: %s' % 
colorize)
+
+               if colorize:
+                       self.GOOD = '\033[1;32m'
+                       self.BAD = '\033[1;31m'
+                       self.NORMAL = '\033[0m'
+
+
+def get_python_executable(ver):
+       """Find the right python executable for |ver|"""
+       if ver == 'pypy':
+               prog = 'pypy'
+       else:
+               prog = 'python' + ver
+       return os.path.join(EPREFIX, 'usr', 'bin', prog)
+
+
+def get_parser():
+       """Return a argument parser for this module"""
+       epilog = """Examples:
+List all the available unittests.
+$ %(prog)s --list
+
+Run against specific versions of python.
+$ %(prog)s --python-version '2.7 3.3'
+
+Run just one unittest.
+$ %(prog)s pym/portage/tests/xpak/test_decodeint.py
+"""
+       parser = argparse.ArgumentParser(
+               description=__doc__,
+               formatter_class=argparse.RawDescriptionHelpFormatter,
+               epilog=epilog)
+       parser.add_argument('--color', type=str, default=None,
+               help='Whether to use colorized output (default is auto)')
+       parser.add_argument('--python-versions', action='append',
+               help='Versions of python to test (default is test available)')
+       return parser
+
+
+def main(argv):
+       parser = get_parser()
+       opts, args = parser.parse_known_args(argv)
+       colors = Colors(colorize=opts.color)
+
+       # Figure out all the versions we want to test.
+       if opts.python_versions is None:
+               ignore_missing = True
+               pyversions = PYTHON_SUPPORTED_VERSIONS + PYTHON_NICE_VERSIONS
+       else:
+               ignore_missing = False
+               pyversions = []
+               for ver in opts.python_versions:
+                       if ver == 'supported':
+                               pyversions.extend(PYTHON_SUPPORTED_VERSIONS)
+                       else:
+                               pyversions.extend(ver.split())
+
+       # Actually test those versions now.
+       statuses = []
+       for ver in pyversions:
+               prog = get_python_executable(ver)
+               cmd = [prog, '-b', '-Wd', 'pym/portage/tests/runTests.py'] + 
args
+               if os.access(prog, os.X_OK):
+                       print('%sTesting with Python %s...%s' %
+                               (colors.GOOD, ver, colors.NORMAL))
+                       statuses.append(subprocess.call(cmd))
+               elif not ignore_missing:
+                       print('%sCould not find requested Python %s%s' %
+                               (colors.BAD, ver, colors.NORMAL))
+                       statuses.append(1)
+               print()
+
+       # Then summarize it all.
+       print('\nSummary:\n')
+       width = 10
+       header = '| %-*s | %s' % (width, 'Version', 'Status')
+       print('%s\n|%s' % (header, '-' * (len(header) - 1)))
+       for ver, status in zip(pyversions, statuses):
+               if status:
+                       color = colors.BAD
+                       msg = 'FAIL'
+               else:
+                       color = colors.GOOD
+                       msg = 'PASS'
+               print('| %s%-*s%s | %s%s%s' %
+                       (color, width, ver, colors.NORMAL, color, msg, 
colors.NORMAL))
+       exit(sum(statuses))
+
+
+if __name__ == '__main__':
+       try:
+               main(sys.argv[1:])
+       except KeyboardInterrupt:
+               print('interrupted ...', file=sys.stderr)
+               exit(1)

diff --git a/runtests.sh b/runtests.sh
deleted file mode 100755
index a7ca101..0000000
--- a/runtests.sh
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/bin/bash
-# Copyright 2010-2014 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-# These are the versions we care about.  The rest are just "nice to have".
-PYTHON_SUPPORTED_VERSIONS="2.7 3.3 3.4"
-PYTHON_VERSIONS="2.7 pypy 3.3 3.4 3.5"
-
-# has to be run from portage root dir
-cd "${0%/*}" || exit 1
-
-case "${NOCOLOR:-false}" in
-       yes|true)
-               GOOD=
-               BAD=
-               NORMAL=
-               ;;
-       no|false)
-               GOOD=$'\e[1;32m'
-               BAD=$'\e[1;31m'
-               NORMAL=$'\e[0m'
-               ;;
-esac
-
-interrupted() {
-       echo "interrupted." >&2
-       exit 1
-}
-
-trap interrupted SIGINT
-
-unused_args=()
-IGNORE_MISSING_VERSIONS=true
-
-while [ $# -gt 0 ] ; do
-       case "$1" in
-               --python-versions=*)
-                       PYTHON_VERSIONS=${1#--python-versions=}
-                       IGNORE_MISSING_VERSIONS=false
-                       ;;
-               --python-versions)
-                       shift
-                       PYTHON_VERSIONS=$1
-                       IGNORE_MISSING_VERSIONS=false
-                       ;;
-               *)
-                       unused_args[${#unused_args[@]}]=$1
-                       ;;
-       esac
-       shift
-done
-if [[ ${PYTHON_VERSIONS} == "supported" ]] ; then
-       PYTHON_VERSIONS=${PYTHON_SUPPORTED_VERSIONS}
-fi
-
-set -- "${unused_args[@]}"
-
-eprefix=${PORTAGE_OVERRIDE_EPREFIX}
-exit_status="0"
-found_versions=()
-status_array=()
-for version in ${PYTHON_VERSIONS}; do
-       if [[ $version = 'pypy' ]] ; then
-               executable=${eprefix}/usr/bin/pypy
-       else
-               executable=${eprefix}/usr/bin/python${version}
-       fi
-       if [[ -x "${executable}" ]]; then
-               echo -e "${GOOD}Testing with Python ${version}...${NORMAL}"
-               "${executable}" -b -Wd pym/portage/tests/runTests.py "$@"
-               status=$?
-               status_array[${#status_array[@]}]=${status}
-               found_versions[${#found_versions[@]}]=${version}
-               if [ ${status} -ne 0 ] ; then
-                       echo -e "${BAD}Testing with Python ${version} 
failed${NORMAL}"
-                       exit_status="1"
-               fi
-               echo
-       elif [[ ${IGNORE_MISSING_VERSIONS} != "true" ]] ; then
-               echo -e "${BAD}Could not find requested Python 
${version}${NORMAL}"
-               exit_status="1"
-       fi
-done
-
-if [ ${#status_array[@]} -gt 0 ] ; then
-       max_len=0
-       for version in ${found_versions[@]} ; do
-               [ ${#version} -gt ${max_len} ] && max_len=${#version}
-       done
-       (( columns = max_len + 2 ))
-       (( columns >= 7 )) || columns=7
-       printf "\nSummary:\n\n"
-       printf "| %-${columns}s | %s\n|" "Version" "Status"
-       (( total_cols = columns + 11 ))
-       eval "printf -- '-%.0s' {1..${total_cols}}"
-       printf "\n"
-       row=0
-       for version in ${found_versions[@]} ; do
-               if [ ${status_array[${row}]} -eq 0 ] ; then
-                       status="success"
-               else
-                       status="fail"
-               fi
-               printf "| %-${columns}s | %s\n" "${version}" "${status}"
-               (( row++ ))
-       done
-fi
-
-exit ${exit_status}

Reply via email to