17db96d56Sopenharmony_ci#!./python 27db96d56Sopenharmony_ci"""Run Python tests against multiple installations of OpenSSL and LibreSSL 37db96d56Sopenharmony_ci 47db96d56Sopenharmony_ciThe script 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_ci (1) downloads OpenSSL / LibreSSL tar bundle 77db96d56Sopenharmony_ci (2) extracts it to ./src 87db96d56Sopenharmony_ci (3) compiles OpenSSL / LibreSSL 97db96d56Sopenharmony_ci (4) installs OpenSSL / LibreSSL into ../multissl/$LIB/$VERSION/ 107db96d56Sopenharmony_ci (5) forces a recompilation of Python modules using the 117db96d56Sopenharmony_ci header and library files from ../multissl/$LIB/$VERSION/ 127db96d56Sopenharmony_ci (6) runs Python's test suite 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_ciThe script must be run with Python's build directory as current working 157db96d56Sopenharmony_cidirectory. 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ciThe script uses LD_RUN_PATH, LD_LIBRARY_PATH, CPPFLAGS and LDFLAGS to bend 187db96d56Sopenharmony_cisearch paths for header files and shared libraries. It's known to work on 197db96d56Sopenharmony_ciLinux with GCC and clang. 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_ciPlease keep this script compatible with Python 2.7, and 3.4 to 3.7. 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_ci(c) 2013-2017 Christian Heimes <christian@python.org> 247db96d56Sopenharmony_ci""" 257db96d56Sopenharmony_cifrom __future__ import print_function 267db96d56Sopenharmony_ci 277db96d56Sopenharmony_ciimport argparse 287db96d56Sopenharmony_cifrom datetime import datetime 297db96d56Sopenharmony_ciimport logging 307db96d56Sopenharmony_ciimport os 317db96d56Sopenharmony_citry: 327db96d56Sopenharmony_ci from urllib.request import urlopen 337db96d56Sopenharmony_ci from urllib.error import HTTPError 347db96d56Sopenharmony_ciexcept ImportError: 357db96d56Sopenharmony_ci from urllib2 import urlopen, HTTPError 367db96d56Sopenharmony_ciimport re 377db96d56Sopenharmony_ciimport shutil 387db96d56Sopenharmony_ciimport string 397db96d56Sopenharmony_ciimport subprocess 407db96d56Sopenharmony_ciimport sys 417db96d56Sopenharmony_ciimport tarfile 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_cilog = logging.getLogger("multissl") 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ciOPENSSL_OLD_VERSIONS = [ 477db96d56Sopenharmony_ci] 487db96d56Sopenharmony_ci 497db96d56Sopenharmony_ciOPENSSL_RECENT_VERSIONS = [ 507db96d56Sopenharmony_ci "1.1.1u", 517db96d56Sopenharmony_ci "3.0.9", 527db96d56Sopenharmony_ci "3.1.1", 537db96d56Sopenharmony_ci] 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ciLIBRESSL_OLD_VERSIONS = [ 567db96d56Sopenharmony_ci] 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ciLIBRESSL_RECENT_VERSIONS = [ 597db96d56Sopenharmony_ci] 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci# store files in ../multissl 627db96d56Sopenharmony_ciHERE = os.path.dirname(os.path.abspath(__file__)) 637db96d56Sopenharmony_ciPYTHONROOT = os.path.abspath(os.path.join(HERE, '..', '..')) 647db96d56Sopenharmony_ciMULTISSL_DIR = os.path.abspath(os.path.join(PYTHONROOT, '..', 'multissl')) 657db96d56Sopenharmony_ci 667db96d56Sopenharmony_ci 677db96d56Sopenharmony_ciparser = argparse.ArgumentParser( 687db96d56Sopenharmony_ci prog='multissl', 697db96d56Sopenharmony_ci description=( 707db96d56Sopenharmony_ci "Run CPython tests with multiple OpenSSL and LibreSSL " 717db96d56Sopenharmony_ci "versions." 727db96d56Sopenharmony_ci ) 737db96d56Sopenharmony_ci) 747db96d56Sopenharmony_ciparser.add_argument( 757db96d56Sopenharmony_ci '--debug', 767db96d56Sopenharmony_ci action='store_true', 777db96d56Sopenharmony_ci help="Enable debug logging", 787db96d56Sopenharmony_ci) 797db96d56Sopenharmony_ciparser.add_argument( 807db96d56Sopenharmony_ci '--disable-ancient', 817db96d56Sopenharmony_ci action='store_true', 827db96d56Sopenharmony_ci help="Don't test OpenSSL and LibreSSL versions without upstream support", 837db96d56Sopenharmony_ci) 847db96d56Sopenharmony_ciparser.add_argument( 857db96d56Sopenharmony_ci '--openssl', 867db96d56Sopenharmony_ci nargs='+', 877db96d56Sopenharmony_ci default=(), 887db96d56Sopenharmony_ci help=( 897db96d56Sopenharmony_ci "OpenSSL versions, defaults to '{}' (ancient: '{}') if no " 907db96d56Sopenharmony_ci "OpenSSL and LibreSSL versions are given." 917db96d56Sopenharmony_ci ).format(OPENSSL_RECENT_VERSIONS, OPENSSL_OLD_VERSIONS) 927db96d56Sopenharmony_ci) 937db96d56Sopenharmony_ciparser.add_argument( 947db96d56Sopenharmony_ci '--libressl', 957db96d56Sopenharmony_ci nargs='+', 967db96d56Sopenharmony_ci default=(), 977db96d56Sopenharmony_ci help=( 987db96d56Sopenharmony_ci "LibreSSL versions, defaults to '{}' (ancient: '{}') if no " 997db96d56Sopenharmony_ci "OpenSSL and LibreSSL versions are given." 1007db96d56Sopenharmony_ci ).format(LIBRESSL_RECENT_VERSIONS, LIBRESSL_OLD_VERSIONS) 1017db96d56Sopenharmony_ci) 1027db96d56Sopenharmony_ciparser.add_argument( 1037db96d56Sopenharmony_ci '--tests', 1047db96d56Sopenharmony_ci nargs='*', 1057db96d56Sopenharmony_ci default=(), 1067db96d56Sopenharmony_ci help="Python tests to run, defaults to all SSL related tests.", 1077db96d56Sopenharmony_ci) 1087db96d56Sopenharmony_ciparser.add_argument( 1097db96d56Sopenharmony_ci '--base-directory', 1107db96d56Sopenharmony_ci default=MULTISSL_DIR, 1117db96d56Sopenharmony_ci help="Base directory for OpenSSL / LibreSSL sources and builds." 1127db96d56Sopenharmony_ci) 1137db96d56Sopenharmony_ciparser.add_argument( 1147db96d56Sopenharmony_ci '--no-network', 1157db96d56Sopenharmony_ci action='store_false', 1167db96d56Sopenharmony_ci dest='network', 1177db96d56Sopenharmony_ci help="Disable network tests." 1187db96d56Sopenharmony_ci) 1197db96d56Sopenharmony_ciparser.add_argument( 1207db96d56Sopenharmony_ci '--steps', 1217db96d56Sopenharmony_ci choices=['library', 'modules', 'tests'], 1227db96d56Sopenharmony_ci default='tests', 1237db96d56Sopenharmony_ci help=( 1247db96d56Sopenharmony_ci "Which steps to perform. 'library' downloads and compiles OpenSSL " 1257db96d56Sopenharmony_ci "or LibreSSL. 'module' also compiles Python modules. 'tests' builds " 1267db96d56Sopenharmony_ci "all and runs the test suite." 1277db96d56Sopenharmony_ci ) 1287db96d56Sopenharmony_ci) 1297db96d56Sopenharmony_ciparser.add_argument( 1307db96d56Sopenharmony_ci '--system', 1317db96d56Sopenharmony_ci default='', 1327db96d56Sopenharmony_ci help="Override the automatic system type detection." 1337db96d56Sopenharmony_ci) 1347db96d56Sopenharmony_ciparser.add_argument( 1357db96d56Sopenharmony_ci '--force', 1367db96d56Sopenharmony_ci action='store_true', 1377db96d56Sopenharmony_ci dest='force', 1387db96d56Sopenharmony_ci help="Force build and installation." 1397db96d56Sopenharmony_ci) 1407db96d56Sopenharmony_ciparser.add_argument( 1417db96d56Sopenharmony_ci '--keep-sources', 1427db96d56Sopenharmony_ci action='store_true', 1437db96d56Sopenharmony_ci dest='keep_sources', 1447db96d56Sopenharmony_ci help="Keep original sources for debugging." 1457db96d56Sopenharmony_ci) 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci 1487db96d56Sopenharmony_ciclass AbstractBuilder(object): 1497db96d56Sopenharmony_ci library = None 1507db96d56Sopenharmony_ci url_templates = None 1517db96d56Sopenharmony_ci src_template = None 1527db96d56Sopenharmony_ci build_template = None 1537db96d56Sopenharmony_ci depend_target = None 1547db96d56Sopenharmony_ci install_target = 'install' 1557db96d56Sopenharmony_ci jobs = os.cpu_count() 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ci module_files = ( 1587db96d56Sopenharmony_ci os.path.join(PYTHONROOT, "Modules/_ssl.c"), 1597db96d56Sopenharmony_ci os.path.join(PYTHONROOT, "Modules/_hashopenssl.c"), 1607db96d56Sopenharmony_ci ) 1617db96d56Sopenharmony_ci module_libs = ("_ssl", "_hashlib") 1627db96d56Sopenharmony_ci 1637db96d56Sopenharmony_ci def __init__(self, version, args): 1647db96d56Sopenharmony_ci self.version = version 1657db96d56Sopenharmony_ci self.args = args 1667db96d56Sopenharmony_ci # installation directory 1677db96d56Sopenharmony_ci self.install_dir = os.path.join( 1687db96d56Sopenharmony_ci os.path.join(args.base_directory, self.library.lower()), version 1697db96d56Sopenharmony_ci ) 1707db96d56Sopenharmony_ci # source file 1717db96d56Sopenharmony_ci self.src_dir = os.path.join(args.base_directory, 'src') 1727db96d56Sopenharmony_ci self.src_file = os.path.join( 1737db96d56Sopenharmony_ci self.src_dir, self.src_template.format(version)) 1747db96d56Sopenharmony_ci # build directory (removed after install) 1757db96d56Sopenharmony_ci self.build_dir = os.path.join( 1767db96d56Sopenharmony_ci self.src_dir, self.build_template.format(version)) 1777db96d56Sopenharmony_ci self.system = args.system 1787db96d56Sopenharmony_ci 1797db96d56Sopenharmony_ci def __str__(self): 1807db96d56Sopenharmony_ci return "<{0.__class__.__name__} for {0.version}>".format(self) 1817db96d56Sopenharmony_ci 1827db96d56Sopenharmony_ci def __eq__(self, other): 1837db96d56Sopenharmony_ci if not isinstance(other, AbstractBuilder): 1847db96d56Sopenharmony_ci return NotImplemented 1857db96d56Sopenharmony_ci return ( 1867db96d56Sopenharmony_ci self.library == other.library 1877db96d56Sopenharmony_ci and self.version == other.version 1887db96d56Sopenharmony_ci ) 1897db96d56Sopenharmony_ci 1907db96d56Sopenharmony_ci def __hash__(self): 1917db96d56Sopenharmony_ci return hash((self.library, self.version)) 1927db96d56Sopenharmony_ci 1937db96d56Sopenharmony_ci @property 1947db96d56Sopenharmony_ci def short_version(self): 1957db96d56Sopenharmony_ci """Short version for OpenSSL download URL""" 1967db96d56Sopenharmony_ci return None 1977db96d56Sopenharmony_ci 1987db96d56Sopenharmony_ci @property 1997db96d56Sopenharmony_ci def openssl_cli(self): 2007db96d56Sopenharmony_ci """openssl CLI binary""" 2017db96d56Sopenharmony_ci return os.path.join(self.install_dir, "bin", "openssl") 2027db96d56Sopenharmony_ci 2037db96d56Sopenharmony_ci @property 2047db96d56Sopenharmony_ci def openssl_version(self): 2057db96d56Sopenharmony_ci """output of 'bin/openssl version'""" 2067db96d56Sopenharmony_ci cmd = [self.openssl_cli, "version"] 2077db96d56Sopenharmony_ci return self._subprocess_output(cmd) 2087db96d56Sopenharmony_ci 2097db96d56Sopenharmony_ci @property 2107db96d56Sopenharmony_ci def pyssl_version(self): 2117db96d56Sopenharmony_ci """Value of ssl.OPENSSL_VERSION""" 2127db96d56Sopenharmony_ci cmd = [ 2137db96d56Sopenharmony_ci sys.executable, 2147db96d56Sopenharmony_ci '-c', 'import ssl; print(ssl.OPENSSL_VERSION)' 2157db96d56Sopenharmony_ci ] 2167db96d56Sopenharmony_ci return self._subprocess_output(cmd) 2177db96d56Sopenharmony_ci 2187db96d56Sopenharmony_ci @property 2197db96d56Sopenharmony_ci def include_dir(self): 2207db96d56Sopenharmony_ci return os.path.join(self.install_dir, "include") 2217db96d56Sopenharmony_ci 2227db96d56Sopenharmony_ci @property 2237db96d56Sopenharmony_ci def lib_dir(self): 2247db96d56Sopenharmony_ci return os.path.join(self.install_dir, "lib") 2257db96d56Sopenharmony_ci 2267db96d56Sopenharmony_ci @property 2277db96d56Sopenharmony_ci def has_openssl(self): 2287db96d56Sopenharmony_ci return os.path.isfile(self.openssl_cli) 2297db96d56Sopenharmony_ci 2307db96d56Sopenharmony_ci @property 2317db96d56Sopenharmony_ci def has_src(self): 2327db96d56Sopenharmony_ci return os.path.isfile(self.src_file) 2337db96d56Sopenharmony_ci 2347db96d56Sopenharmony_ci def _subprocess_call(self, cmd, env=None, **kwargs): 2357db96d56Sopenharmony_ci log.debug("Call '{}'".format(" ".join(cmd))) 2367db96d56Sopenharmony_ci return subprocess.check_call(cmd, env=env, **kwargs) 2377db96d56Sopenharmony_ci 2387db96d56Sopenharmony_ci def _subprocess_output(self, cmd, env=None, **kwargs): 2397db96d56Sopenharmony_ci log.debug("Call '{}'".format(" ".join(cmd))) 2407db96d56Sopenharmony_ci if env is None: 2417db96d56Sopenharmony_ci env = os.environ.copy() 2427db96d56Sopenharmony_ci env["LD_LIBRARY_PATH"] = self.lib_dir 2437db96d56Sopenharmony_ci out = subprocess.check_output(cmd, env=env, **kwargs) 2447db96d56Sopenharmony_ci return out.strip().decode("utf-8") 2457db96d56Sopenharmony_ci 2467db96d56Sopenharmony_ci def _download_src(self): 2477db96d56Sopenharmony_ci """Download sources""" 2487db96d56Sopenharmony_ci src_dir = os.path.dirname(self.src_file) 2497db96d56Sopenharmony_ci if not os.path.isdir(src_dir): 2507db96d56Sopenharmony_ci os.makedirs(src_dir) 2517db96d56Sopenharmony_ci data = None 2527db96d56Sopenharmony_ci for url_template in self.url_templates: 2537db96d56Sopenharmony_ci url = url_template.format(v=self.version, s=self.short_version) 2547db96d56Sopenharmony_ci log.info("Downloading from {}".format(url)) 2557db96d56Sopenharmony_ci try: 2567db96d56Sopenharmony_ci req = urlopen(url) 2577db96d56Sopenharmony_ci # KISS, read all, write all 2587db96d56Sopenharmony_ci data = req.read() 2597db96d56Sopenharmony_ci except HTTPError as e: 2607db96d56Sopenharmony_ci log.error( 2617db96d56Sopenharmony_ci "Download from {} has from failed: {}".format(url, e) 2627db96d56Sopenharmony_ci ) 2637db96d56Sopenharmony_ci else: 2647db96d56Sopenharmony_ci log.info("Successfully downloaded from {}".format(url)) 2657db96d56Sopenharmony_ci break 2667db96d56Sopenharmony_ci if data is None: 2677db96d56Sopenharmony_ci raise ValueError("All download URLs have failed") 2687db96d56Sopenharmony_ci log.info("Storing {}".format(self.src_file)) 2697db96d56Sopenharmony_ci with open(self.src_file, "wb") as f: 2707db96d56Sopenharmony_ci f.write(data) 2717db96d56Sopenharmony_ci 2727db96d56Sopenharmony_ci def _unpack_src(self): 2737db96d56Sopenharmony_ci """Unpack tar.gz bundle""" 2747db96d56Sopenharmony_ci # cleanup 2757db96d56Sopenharmony_ci if os.path.isdir(self.build_dir): 2767db96d56Sopenharmony_ci shutil.rmtree(self.build_dir) 2777db96d56Sopenharmony_ci os.makedirs(self.build_dir) 2787db96d56Sopenharmony_ci 2797db96d56Sopenharmony_ci tf = tarfile.open(self.src_file) 2807db96d56Sopenharmony_ci name = self.build_template.format(self.version) 2817db96d56Sopenharmony_ci base = name + '/' 2827db96d56Sopenharmony_ci # force extraction into build dir 2837db96d56Sopenharmony_ci members = tf.getmembers() 2847db96d56Sopenharmony_ci for member in list(members): 2857db96d56Sopenharmony_ci if member.name == name: 2867db96d56Sopenharmony_ci members.remove(member) 2877db96d56Sopenharmony_ci elif not member.name.startswith(base): 2887db96d56Sopenharmony_ci raise ValueError(member.name, base) 2897db96d56Sopenharmony_ci member.name = member.name[len(base):].lstrip('/') 2907db96d56Sopenharmony_ci log.info("Unpacking files to {}".format(self.build_dir)) 2917db96d56Sopenharmony_ci tf.extractall(self.build_dir, members) 2927db96d56Sopenharmony_ci 2937db96d56Sopenharmony_ci def _build_src(self, config_args=()): 2947db96d56Sopenharmony_ci """Now build openssl""" 2957db96d56Sopenharmony_ci log.info("Running build in {}".format(self.build_dir)) 2967db96d56Sopenharmony_ci cwd = self.build_dir 2977db96d56Sopenharmony_ci cmd = [ 2987db96d56Sopenharmony_ci "./config", *config_args, 2997db96d56Sopenharmony_ci "shared", "--debug", 3007db96d56Sopenharmony_ci "--prefix={}".format(self.install_dir) 3017db96d56Sopenharmony_ci ] 3027db96d56Sopenharmony_ci # cmd.extend(["no-deprecated", "--api=1.1.0"]) 3037db96d56Sopenharmony_ci env = os.environ.copy() 3047db96d56Sopenharmony_ci # set rpath 3057db96d56Sopenharmony_ci env["LD_RUN_PATH"] = self.lib_dir 3067db96d56Sopenharmony_ci if self.system: 3077db96d56Sopenharmony_ci env['SYSTEM'] = self.system 3087db96d56Sopenharmony_ci self._subprocess_call(cmd, cwd=cwd, env=env) 3097db96d56Sopenharmony_ci if self.depend_target: 3107db96d56Sopenharmony_ci self._subprocess_call( 3117db96d56Sopenharmony_ci ["make", "-j1", self.depend_target], cwd=cwd, env=env 3127db96d56Sopenharmony_ci ) 3137db96d56Sopenharmony_ci self._subprocess_call(["make", f"-j{self.jobs}"], cwd=cwd, env=env) 3147db96d56Sopenharmony_ci 3157db96d56Sopenharmony_ci def _make_install(self): 3167db96d56Sopenharmony_ci self._subprocess_call( 3177db96d56Sopenharmony_ci ["make", "-j1", self.install_target], 3187db96d56Sopenharmony_ci cwd=self.build_dir 3197db96d56Sopenharmony_ci ) 3207db96d56Sopenharmony_ci self._post_install() 3217db96d56Sopenharmony_ci if not self.args.keep_sources: 3227db96d56Sopenharmony_ci shutil.rmtree(self.build_dir) 3237db96d56Sopenharmony_ci 3247db96d56Sopenharmony_ci def _post_install(self): 3257db96d56Sopenharmony_ci pass 3267db96d56Sopenharmony_ci 3277db96d56Sopenharmony_ci def install(self): 3287db96d56Sopenharmony_ci log.info(self.openssl_cli) 3297db96d56Sopenharmony_ci if not self.has_openssl or self.args.force: 3307db96d56Sopenharmony_ci if not self.has_src: 3317db96d56Sopenharmony_ci self._download_src() 3327db96d56Sopenharmony_ci else: 3337db96d56Sopenharmony_ci log.debug("Already has src {}".format(self.src_file)) 3347db96d56Sopenharmony_ci self._unpack_src() 3357db96d56Sopenharmony_ci self._build_src() 3367db96d56Sopenharmony_ci self._make_install() 3377db96d56Sopenharmony_ci else: 3387db96d56Sopenharmony_ci log.info("Already has installation {}".format(self.install_dir)) 3397db96d56Sopenharmony_ci # validate installation 3407db96d56Sopenharmony_ci version = self.openssl_version 3417db96d56Sopenharmony_ci if self.version not in version: 3427db96d56Sopenharmony_ci raise ValueError(version) 3437db96d56Sopenharmony_ci 3447db96d56Sopenharmony_ci def recompile_pymods(self): 3457db96d56Sopenharmony_ci log.warning("Using build from {}".format(self.build_dir)) 3467db96d56Sopenharmony_ci # force a rebuild of all modules that use OpenSSL APIs 3477db96d56Sopenharmony_ci for fname in self.module_files: 3487db96d56Sopenharmony_ci os.utime(fname, None) 3497db96d56Sopenharmony_ci # remove all build artefacts 3507db96d56Sopenharmony_ci for root, dirs, files in os.walk('build'): 3517db96d56Sopenharmony_ci for filename in files: 3527db96d56Sopenharmony_ci if filename.startswith(self.module_libs): 3537db96d56Sopenharmony_ci os.unlink(os.path.join(root, filename)) 3547db96d56Sopenharmony_ci 3557db96d56Sopenharmony_ci # overwrite header and library search paths 3567db96d56Sopenharmony_ci env = os.environ.copy() 3577db96d56Sopenharmony_ci env["CPPFLAGS"] = "-I{}".format(self.include_dir) 3587db96d56Sopenharmony_ci env["LDFLAGS"] = "-L{}".format(self.lib_dir) 3597db96d56Sopenharmony_ci # set rpath 3607db96d56Sopenharmony_ci env["LD_RUN_PATH"] = self.lib_dir 3617db96d56Sopenharmony_ci 3627db96d56Sopenharmony_ci log.info("Rebuilding Python modules") 3637db96d56Sopenharmony_ci cmd = [sys.executable, os.path.join(PYTHONROOT, "setup.py"), "build"] 3647db96d56Sopenharmony_ci self._subprocess_call(cmd, env=env) 3657db96d56Sopenharmony_ci self.check_imports() 3667db96d56Sopenharmony_ci 3677db96d56Sopenharmony_ci def check_imports(self): 3687db96d56Sopenharmony_ci cmd = [sys.executable, "-c", "import _ssl; import _hashlib"] 3697db96d56Sopenharmony_ci self._subprocess_call(cmd) 3707db96d56Sopenharmony_ci 3717db96d56Sopenharmony_ci def check_pyssl(self): 3727db96d56Sopenharmony_ci version = self.pyssl_version 3737db96d56Sopenharmony_ci if self.version not in version: 3747db96d56Sopenharmony_ci raise ValueError(version) 3757db96d56Sopenharmony_ci 3767db96d56Sopenharmony_ci def run_python_tests(self, tests, network=True): 3777db96d56Sopenharmony_ci if not tests: 3787db96d56Sopenharmony_ci cmd = [ 3797db96d56Sopenharmony_ci sys.executable, 3807db96d56Sopenharmony_ci os.path.join(PYTHONROOT, 'Lib/test/ssltests.py'), 3817db96d56Sopenharmony_ci '-j0' 3827db96d56Sopenharmony_ci ] 3837db96d56Sopenharmony_ci elif sys.version_info < (3, 3): 3847db96d56Sopenharmony_ci cmd = [sys.executable, '-m', 'test.regrtest'] 3857db96d56Sopenharmony_ci else: 3867db96d56Sopenharmony_ci cmd = [sys.executable, '-m', 'test', '-j0'] 3877db96d56Sopenharmony_ci if network: 3887db96d56Sopenharmony_ci cmd.extend(['-u', 'network', '-u', 'urlfetch']) 3897db96d56Sopenharmony_ci cmd.extend(['-w', '-r']) 3907db96d56Sopenharmony_ci cmd.extend(tests) 3917db96d56Sopenharmony_ci self._subprocess_call(cmd, stdout=None) 3927db96d56Sopenharmony_ci 3937db96d56Sopenharmony_ci 3947db96d56Sopenharmony_ciclass BuildOpenSSL(AbstractBuilder): 3957db96d56Sopenharmony_ci library = "OpenSSL" 3967db96d56Sopenharmony_ci url_templates = ( 3977db96d56Sopenharmony_ci "https://www.openssl.org/source/openssl-{v}.tar.gz", 3987db96d56Sopenharmony_ci "https://www.openssl.org/source/old/{s}/openssl-{v}.tar.gz" 3997db96d56Sopenharmony_ci ) 4007db96d56Sopenharmony_ci src_template = "openssl-{}.tar.gz" 4017db96d56Sopenharmony_ci build_template = "openssl-{}" 4027db96d56Sopenharmony_ci # only install software, skip docs 4037db96d56Sopenharmony_ci install_target = 'install_sw' 4047db96d56Sopenharmony_ci depend_target = 'depend' 4057db96d56Sopenharmony_ci 4067db96d56Sopenharmony_ci def _post_install(self): 4077db96d56Sopenharmony_ci if self.version.startswith("3."): 4087db96d56Sopenharmony_ci self._post_install_3xx() 4097db96d56Sopenharmony_ci 4107db96d56Sopenharmony_ci def _build_src(self, config_args=()): 4117db96d56Sopenharmony_ci if self.version.startswith("3."): 4127db96d56Sopenharmony_ci config_args += ("enable-fips",) 4137db96d56Sopenharmony_ci super()._build_src(config_args) 4147db96d56Sopenharmony_ci 4157db96d56Sopenharmony_ci def _post_install_3xx(self): 4167db96d56Sopenharmony_ci # create ssl/ subdir with example configs 4177db96d56Sopenharmony_ci # Install FIPS module 4187db96d56Sopenharmony_ci self._subprocess_call( 4197db96d56Sopenharmony_ci ["make", "-j1", "install_ssldirs", "install_fips"], 4207db96d56Sopenharmony_ci cwd=self.build_dir 4217db96d56Sopenharmony_ci ) 4227db96d56Sopenharmony_ci if not os.path.isdir(self.lib_dir): 4237db96d56Sopenharmony_ci # 3.0.0-beta2 uses lib64 on 64 bit platforms 4247db96d56Sopenharmony_ci lib64 = self.lib_dir + "64" 4257db96d56Sopenharmony_ci os.symlink(lib64, self.lib_dir) 4267db96d56Sopenharmony_ci 4277db96d56Sopenharmony_ci @property 4287db96d56Sopenharmony_ci def short_version(self): 4297db96d56Sopenharmony_ci """Short version for OpenSSL download URL""" 4307db96d56Sopenharmony_ci mo = re.search(r"^(\d+)\.(\d+)\.(\d+)", self.version) 4317db96d56Sopenharmony_ci parsed = tuple(int(m) for m in mo.groups()) 4327db96d56Sopenharmony_ci if parsed < (1, 0, 0): 4337db96d56Sopenharmony_ci return "0.9.x" 4347db96d56Sopenharmony_ci if parsed >= (3, 0, 0): 4357db96d56Sopenharmony_ci # OpenSSL 3.0.0 -> /old/3.0/ 4367db96d56Sopenharmony_ci parsed = parsed[:2] 4377db96d56Sopenharmony_ci return ".".join(str(i) for i in parsed) 4387db96d56Sopenharmony_ci 4397db96d56Sopenharmony_ciclass BuildLibreSSL(AbstractBuilder): 4407db96d56Sopenharmony_ci library = "LibreSSL" 4417db96d56Sopenharmony_ci url_templates = ( 4427db96d56Sopenharmony_ci "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-{v}.tar.gz", 4437db96d56Sopenharmony_ci ) 4447db96d56Sopenharmony_ci src_template = "libressl-{}.tar.gz" 4457db96d56Sopenharmony_ci build_template = "libressl-{}" 4467db96d56Sopenharmony_ci 4477db96d56Sopenharmony_ci 4487db96d56Sopenharmony_cidef configure_make(): 4497db96d56Sopenharmony_ci if not os.path.isfile('Makefile'): 4507db96d56Sopenharmony_ci log.info('Running ./configure') 4517db96d56Sopenharmony_ci subprocess.check_call([ 4527db96d56Sopenharmony_ci './configure', '--config-cache', '--quiet', 4537db96d56Sopenharmony_ci '--with-pydebug' 4547db96d56Sopenharmony_ci ]) 4557db96d56Sopenharmony_ci 4567db96d56Sopenharmony_ci log.info('Running make') 4577db96d56Sopenharmony_ci subprocess.check_call(['make', '--quiet']) 4587db96d56Sopenharmony_ci 4597db96d56Sopenharmony_ci 4607db96d56Sopenharmony_cidef main(): 4617db96d56Sopenharmony_ci args = parser.parse_args() 4627db96d56Sopenharmony_ci if not args.openssl and not args.libressl: 4637db96d56Sopenharmony_ci args.openssl = list(OPENSSL_RECENT_VERSIONS) 4647db96d56Sopenharmony_ci args.libressl = list(LIBRESSL_RECENT_VERSIONS) 4657db96d56Sopenharmony_ci if not args.disable_ancient: 4667db96d56Sopenharmony_ci args.openssl.extend(OPENSSL_OLD_VERSIONS) 4677db96d56Sopenharmony_ci args.libressl.extend(LIBRESSL_OLD_VERSIONS) 4687db96d56Sopenharmony_ci 4697db96d56Sopenharmony_ci logging.basicConfig( 4707db96d56Sopenharmony_ci level=logging.DEBUG if args.debug else logging.INFO, 4717db96d56Sopenharmony_ci format="*** %(levelname)s %(message)s" 4727db96d56Sopenharmony_ci ) 4737db96d56Sopenharmony_ci 4747db96d56Sopenharmony_ci start = datetime.now() 4757db96d56Sopenharmony_ci 4767db96d56Sopenharmony_ci if args.steps in {'modules', 'tests'}: 4777db96d56Sopenharmony_ci for name in ['setup.py', 'Modules/_ssl.c']: 4787db96d56Sopenharmony_ci if not os.path.isfile(os.path.join(PYTHONROOT, name)): 4797db96d56Sopenharmony_ci parser.error( 4807db96d56Sopenharmony_ci "Must be executed from CPython build dir" 4817db96d56Sopenharmony_ci ) 4827db96d56Sopenharmony_ci if not os.path.samefile('python', sys.executable): 4837db96d56Sopenharmony_ci parser.error( 4847db96d56Sopenharmony_ci "Must be executed with ./python from CPython build dir" 4857db96d56Sopenharmony_ci ) 4867db96d56Sopenharmony_ci # check for configure and run make 4877db96d56Sopenharmony_ci configure_make() 4887db96d56Sopenharmony_ci 4897db96d56Sopenharmony_ci # download and register builder 4907db96d56Sopenharmony_ci builds = [] 4917db96d56Sopenharmony_ci 4927db96d56Sopenharmony_ci for version in args.openssl: 4937db96d56Sopenharmony_ci build = BuildOpenSSL( 4947db96d56Sopenharmony_ci version, 4957db96d56Sopenharmony_ci args 4967db96d56Sopenharmony_ci ) 4977db96d56Sopenharmony_ci build.install() 4987db96d56Sopenharmony_ci builds.append(build) 4997db96d56Sopenharmony_ci 5007db96d56Sopenharmony_ci for version in args.libressl: 5017db96d56Sopenharmony_ci build = BuildLibreSSL( 5027db96d56Sopenharmony_ci version, 5037db96d56Sopenharmony_ci args 5047db96d56Sopenharmony_ci ) 5057db96d56Sopenharmony_ci build.install() 5067db96d56Sopenharmony_ci builds.append(build) 5077db96d56Sopenharmony_ci 5087db96d56Sopenharmony_ci if args.steps in {'modules', 'tests'}: 5097db96d56Sopenharmony_ci for build in builds: 5107db96d56Sopenharmony_ci try: 5117db96d56Sopenharmony_ci build.recompile_pymods() 5127db96d56Sopenharmony_ci build.check_pyssl() 5137db96d56Sopenharmony_ci if args.steps == 'tests': 5147db96d56Sopenharmony_ci build.run_python_tests( 5157db96d56Sopenharmony_ci tests=args.tests, 5167db96d56Sopenharmony_ci network=args.network, 5177db96d56Sopenharmony_ci ) 5187db96d56Sopenharmony_ci except Exception as e: 5197db96d56Sopenharmony_ci log.exception("%s failed", build) 5207db96d56Sopenharmony_ci print("{} failed: {}".format(build, e), file=sys.stderr) 5217db96d56Sopenharmony_ci sys.exit(2) 5227db96d56Sopenharmony_ci 5237db96d56Sopenharmony_ci log.info("\n{} finished in {}".format( 5247db96d56Sopenharmony_ci args.steps.capitalize(), 5257db96d56Sopenharmony_ci datetime.now() - start 5267db96d56Sopenharmony_ci )) 5277db96d56Sopenharmony_ci print('Python: ', sys.version) 5287db96d56Sopenharmony_ci if args.steps == 'tests': 5297db96d56Sopenharmony_ci if args.tests: 5307db96d56Sopenharmony_ci print('Executed Tests:', ' '.join(args.tests)) 5317db96d56Sopenharmony_ci else: 5327db96d56Sopenharmony_ci print('Executed all SSL tests.') 5337db96d56Sopenharmony_ci 5347db96d56Sopenharmony_ci print('OpenSSL / LibreSSL versions:') 5357db96d56Sopenharmony_ci for build in builds: 5367db96d56Sopenharmony_ci print(" * {0.library} {0.version}".format(build)) 5377db96d56Sopenharmony_ci 5387db96d56Sopenharmony_ci 5397db96d56Sopenharmony_ciif __name__ == "__main__": 5407db96d56Sopenharmony_ci main() 541