diff options
author | Jarret Shook <jashoo@microsoft.com> | 2019-01-11 12:55:44 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-11 12:55:44 -0800 |
commit | 18781c5ae27e543744adc811fef074b96e07fd1a (patch) | |
tree | e7d7b37077c9de9d455f721b14a17ebe3f078d35 | |
parent | c5ab4466175ec58069adabb51995c571234512cd (diff) | |
download | coreclr-18781c5ae27e543744adc811fef074b96e07fd1a.tar.gz coreclr-18781c5ae27e543744adc811fef074b96e07fd1a.tar.bz2 coreclr-18781c5ae27e543744adc811fef074b96e07fd1a.zip |
Share arg validation runtest and run-pmi-diff (#20812)
* Share arg validation runtest and run-pmi-diff
Use the same arg validation in runtests.py and run-pmi-diffs.py
* Add valid arches to ci_arch
-rw-r--r-- | scripts/coreclr_arguments.py | 272 | ||||
-rwxr-xr-x | tests/runtest.py | 219 | ||||
-rwxr-xr-x[-rw-r--r--] | tests/scripts/run-pmi-diffs.py | 151 |
3 files changed, 424 insertions, 218 deletions
diff --git a/scripts/coreclr_arguments.py b/scripts/coreclr_arguments.py new file mode 100644 index 0000000000..d207061110 --- /dev/null +++ b/scripts/coreclr_arguments.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python +# +## Licensed to the .NET Foundation under one or more agreements. +## The .NET Foundation licenses this file to you under the MIT license. +## See the LICENSE file in the project root for more information. +# +## +# Title : coreclr_arguments.py +# +# Notes: +# +# Setup script, to avoid re-writing argument validation between different +# coreclr scripts. +# +################################################################################ +################################################################################ + +import argparse +import datetime +import json +import os +import platform +import shutil +import subprocess +import sys +import tempfile +import time +import re +import string + +import xml.etree.ElementTree + +from collections import defaultdict +from sys import platform as _platform + +################################################################################ +################################################################################ + +class CoreclrArguments: + + ############################################################################ + # ctor + ############################################################################ + + def __init__(self, + args, + require_built_test_dir=False, + require_built_core_root=False, + require_built_product_dir=False, + default_build_type="Debug"): + """ Setup the args based on the argparser obj + + Args: + args(ArgParser): Parsed arguments + + Notes: + If there is no core_root, or test location passed, create a default + location using the build type and the arch. + """ + + # Default values. Note that these are extensible. + self.host_os = None + self.arch = None + self.build_type = None + self.core_root = None + self.coreclr_repo_location = None + + self.default_build_type = default_build_type + + self.require_built_product_dir = require_built_product_dir + self.require_built_core_root = require_built_core_root + self.require_built_test_dir = require_built_test_dir + + self.valid_arches = ["x64", "x86", "arm", "arm64"] + self.valid_build_types = ["Debug", "Checked", "Release"] + self.valid_host_os = ["Windows", "Windows_NT", "OSX", "Linux"] + + self.__initialize__(args) + + ############################################################################ + # Instance Methods + ############################################################################ + + def check_build_type(self, build_type): + if build_type != None and len(build_type) > 0: + # Force the build type to be capitalized + build_type = build_type.capitalize() + return build_type + + elif build_type == None: + return self.default_build_type + + if not build_type in self.valid_build_types: + return False + + return True + + def verify(self, + args, + arg_name, + verify, + failure_str, + arg_value=None, + modify_arg=None, + modify_after_validation=False): + """ Verify an arg + + Args: + args (argParser) : arg parser args + arg_name (String) : argument to verify + verify (lambda: arg -> bool) : verify method + failure_str (String) : failure output if not verified + modify_arg (lambda: arg -> arg) : modify the argument before assigning + + Returns: + verified (bool) + """ + verified = False + arg_value = None + + if isinstance(args, argparse.Namespace): + try: + arg_value = getattr(args, arg_name) + except: + pass + + else: + arg_value = args + + if modify_arg != None and not modify_after_validation: + arg_value = modify_arg(arg_value) + + try: + verified = verify(arg_value) + except: + pass + + if verified == False and isinstance(failure_str, str): + print(failure_str) + sys.exit(1) + elif verified == False: + print(failure_str(arg_value)) + sys.exit(1) + + if modify_arg != None and modify_after_validation: + arg_value = modify_arg(arg_value) + + if verified != True and arg_value is None: + arg_value = verified + + # Add a new member variable based on the verified arg + setattr(self, arg_name, arg_value) + + ############################################################################ + # Helper Methods + ############################################################################ + + def __initialize__(self, args): + def check_host_os(host_os): + if host_os is None: + host_os = provide_default_host_os() + assert(host_os != None) + + return host_os + + else: + return host_os in self.valid_host_os + + def check_arch(arch): + if arch is None: + arch = provide_default_arch() + assert(arch in self.valid_arches) + + return arch + + else: + return arch in self.valid_arches + + def provide_default_arch(): + platform_machine = platform.machine() + if platform_machine == "x86_64": + return "x64" + elif platform_machine == "i386": + return "x86" + elif platform_machine == "armhf": + return "arm" + elif platform_machine == "armel": + return "armel" + elif platform_machine == "aarch64" or platform_machine == "arm64": + return "arm64" + else: + raise RuntimeError("Unsupported platform") + + def provide_default_host_os(): + if _platform == "linux" or _platform == "linux2": + return "Linux" + elif _platform == "darwin": + return "OSX" + elif _platform == "win32": + return "Windows_NT" + else: + print("Unknown OS: %s" % self.host_os) + sys.exit(1) + + return None + + def check_and_return_test_location(test_location): + default_test_location = os.path.join(self.coreclr_repo_location, "bin", "tests", "%s.%s.%s" % (self.host_os, self.arch, self.build_type)) + + if os.path.isdir(default_test_location) or not self.require_built_test_dir: + return default_test_location + + elif not os.path.isdir(test_location) and self.require_built_test_dir: + return False + + return test_location + + def check_and_return_default_core_root(core_root): + default_core_root = os.path.join(self.test_location, "Tests", "Core_Root") + + if os.path.isdir(default_core_root) or not self.require_built_core_root: + return default_core_root + + elif not os.path.isdir(core_root) and self.require_built_core_root: + return False + + return core_root + + def check_and_return_default_product_location(product_location): + default_product_location = os.path.join(self.bin_location, "Product", "%s.%s.%s" % (self.host_os, self.arch, self.build_type)) + + if os.path.isdir(default_product_location) or not self.require_built_product_dir: + return default_product_location + elif os.path.isdir(product_location) and self.require_build_product_dir: + return False + + return product_location + + self.coreclr_repo_location = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + self.bin_location = os.path.join(self.coreclr_repo_location, "bin") + + self.verify(args, + "host_os", + check_host_os, + "Unsupported host_os", + modify_arg=lambda host_os: provide_default_host_os() if host_os is None else host_os) + + self.verify(args, + "arch", + check_arch, + "Unsupported architecture: %s.\nSupported architectures: %s" % (args.arch, ", ".join(self.valid_arches))) + + self.verify(args, + "build_type", + self.check_build_type, + "Unsupported configuration: %s.\nSupported configurations: %s" % (args.build_type, ", ".join(self.valid_build_types)), + modify_arg=lambda arg: arg.capitalize()) + + self.verify(args, + "test_location", + check_and_return_test_location, + "Error, incorrect test location.") + + self.verify(args, + "core_root", + check_and_return_default_core_root, + "Error, incorrect core_root location.") + + self.verify(args, + "product_location", + check_and_return_default_product_location, + "Error, incorrect product_location.")
\ No newline at end of file diff --git a/tests/runtest.py b/tests/runtest.py index 48340e7e81..5f38b8ddbc 100755 --- a/tests/runtest.py +++ b/tests/runtest.py @@ -61,12 +61,15 @@ from collections import defaultdict from sys import platform as _platform # Version specific imports - if sys.version_info.major < 3: import urllib else: import urllib.request +sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "scripts")) + +from coreclr_arguments import * + ################################################################################ # Argument Parser ################################################################################ @@ -1110,113 +1113,47 @@ def setup_args(args): location using the build type and the arch. """ - if args.generate_layout_only: - args.generate_layout = True - - host_os = None - arch = args.arch.lower() - build_type = args.build_type - - test_location = args.test_location - core_root = args.core_root - test_native_bin_location = args.test_native_bin_location - - coreclr_repo_location = args.coreclr_repo_location - if os.path.basename(coreclr_repo_location) == "tests": - coreclr_repo_location = os.path.dirname(coreclr_repo_location) - - if _platform == "linux" or _platform == "linux2": - host_os = "Linux" - elif _platform == "darwin": - host_os = "OSX" - elif _platform == "win32": - host_os = "Windows_NT" - else: - print("Unknown OS: %s" % host_os) - sys.exit(1) - - assert os.path.isdir(coreclr_repo_location) - - valid_arches = ["x64", "x86", "arm", "arm64"] - if not arch in valid_arches: - print("Unsupported architecture: %s." % arch) - print("Supported architectures: %s" % "[%s]" % ", ".join(valid_arches)) - sys.exit(1) - - def check_build_type(build_type): - valid_build_types = ["Debug", "Checked", "Release"] - - if build_type != None and len(build_type) > 0: - # Force the build type to be capitalized - build_type = build_type.capitalize() + coreclr_setup_args = CoreclrArguments(args, + require_built_test_dir=True, + require_built_core_root=True, + require_built_product_dir=args.generate_layout_only) - if not build_type in valid_build_types: - print("Unsupported configuration: %s." % build_type) - print("Supported configurations: %s" % "[%s]" % ", ".join(valid_build_types)) - sys.exit(1) - - return build_type - - build_type = check_build_type(build_type) - - if test_location is None: - default_test_location = os.path.join(coreclr_repo_location, "bin", "tests", "%s.%s.%s" % (host_os, arch, build_type)) - - if os.path.isdir(default_test_location): - test_location = default_test_location - - print("Using default test location.") - print("TestLocation: %s" % default_test_location) - print("") - - else: - # The tests for the default location have not been built. - print("Error, unable to find the tests at %s" % default_test_location) - - suggested_location = None - possible_test_locations = [item for item in os.listdir(os.path.join(coreclr_repo_location, "bin", "tests")) if host_os in item and arch in item] - if len(possible_test_locations) > 0: - print("Tests are built for the following:") - for item in possible_test_locations: - print(item.replace(".", " ")) - - print("Please run runtest.py again with the correct build-type by passing -build_type") - else: - print("No tests have been built for this host and arch. Please run build-test.%s" % ("cmd" if host_os == "Windows_NT" else "sh")) - - sys.exit(1) - else: - # If we have supplied our own test location then we need to create a test location - # that the scripting will expect. As it is now, there is a dependency on the - # test location being under test/<os>.<build_type>.<arch> + normal_location = os.path.join(coreclr_setup_args.bin_location, "tests", "%s.%s.%s" % (coreclr_setup_args.host_os, coreclr_setup_args.arch, coreclr_setup_args.build_type)) - # Make sure that we are using the correct build_type. This is a test drop, it is possible - # that we are inferring the build type to be Debug incorrectly. + # If we have supplied our own test location then we need to create a test location + # that the scripting will expect. As it is now, there is a dependency on the + # test location being under test/<os>.<build_type>.<arch> - if build_type not in test_location: + # Make sure that we are using the correct build_type. This is a test drop, it is possible + # that we are inferring the build type to be Debug incorrectly. + if coreclr_setup_args.build_type not in coreclr_setup_args.test_location: # Remove punctuation - corrected_build_type = re.sub("[%s]" % string.punctuation, "", test_location.split(".")[-1]) - build_type = check_build_type(corrected_build_type) + corrected_build_type = re.sub("[%s]" % string.punctuation, "", coreclr_setup_args.test_location.split(".")[-1]) + coreclr_setup_args.verify(corrected_build_type, + "build_type", + coreclr_setup_args.check_build_type, + "Unsupported configuration: %s.\nSupported configurations: %s" % (corrected_build_type, ", ".join(coreclr_setup_args.valid_build_types))) - default_test_location = os.path.join(coreclr_repo_location, "bin", "tests", "%s.%s.%s" % (host_os, arch, build_type)) + if args.test_location is not None and coreclr_setup_args.test_location != normal_location: + test_location = args.test_location # Remove optional end os.path.sep if test_location[-1] == os.path.sep: test_location = test_location[:-1] - if test_location.lower() != default_test_location.lower() and os.path.isdir(default_test_location): + if normal_location.lower() != test_location.lower() and os.path.isdir(normal_location): # Remove the existing directory if there is one. - shutil.rmtree(default_test_location) + shutil.rmtree(normal_location) print("Non-standard test location being used.") print("Overwrite the standard location with these tests.") print("TODO: Change runtest.proj to allow running from non-standard test location.") print("") - print("cp -r %s %s" % (test_location, default_test_location)) - shutil.copytree(test_location, default_test_location) + print("cp -r %s %s" % (coreclr_setup_args.test_location, normal_location)) + shutil.copytree(coreclr_setup_args.test_location, normal_location) - test_location = default_test_location + test_location = normal_location # unset core_root so it can be put in the default location core_root = None @@ -1224,35 +1161,15 @@ def setup_args(args): # Force the core_root to be setup again. args.generate_layout = True - else: - test_location = default_test_location - - print("Using default test location.") - print("TestLocation: %s" % default_test_location) - print("") - - if core_root is None: - default_core_root = os.path.join(test_location, "Tests", "Core_Root") - - if os.path.isdir(default_core_root): - core_root = default_core_root - - print("Using default location for core_root.") - print("Core_Root: %s" % core_root) - print("") + coreclr_setup_args.verify(test_location, + "test_location", + lambda arg: True, + "Error setting test location.") - elif args.generate_layout is False: - # CORE_ROOT has not been setup correctly. - print("Error, unable to find CORE_ROOT at %s" % default_core_root) - print("Please run runtest.py with --generate_layout specified.") - - sys.exit(1) - - else: - print("--generate_layout passed. Core_Root will be populated at: %s" % default_core_root) - core_root = default_core_root - else: - print("Core_Root: %s" % core_root) + coreclr_setup_args.verify(args, + "generate_layout", + lambda arg: True, + "Error setting generate_layout") is_same_os = False is_same_arch = False @@ -1260,36 +1177,46 @@ def setup_args(args): # We will write out build information into the test directory. This is used # by runtest.py to determine whether we need to rebuild the test wrappers. - if os.path.isfile(os.path.join(test_location, "build_info.json")): - with open(os.path.join(test_location, "build_info.json")) as file_handle: + if os.path.isfile(os.path.join(coreclr_setup_args.test_location, "build_info.json")): + with open(os.path.join(coreclr_setup_args.test_location, "build_info.json")) as file_handle: build_info = json.load(file_handle) - is_same_os = build_info["build_os"] == host_os - is_same_arch = build_info["build_arch"] == arch - is_same_build_type = build_info["build_type"] == build_type - - if host_os != "Windows_NT" and not (is_same_os and is_same_arch and is_same_build_type): - if test_native_bin_location is None: - print("Using default location for test_native_bin_location.") - test_native_bin_location = os.path.join(os.path.join(coreclr_repo_location, "bin", "obj", "%s.%s.%s" % (host_os, arch, build_type), "tests")) - print("Native bin location: %s" % test_native_bin_location) - print("") - - if not os.path.isdir(test_native_bin_location): - print("Error, test_native_bin_location: %s, does not exist." % test_native_bin_location) - sys.exit(1) - - if args.product_location is None and args.generate_layout: - product_location = os.path.join(coreclr_repo_location, "bin", "Product", "%s.%s.%s" % (host_os, arch, build_type)) - if not os.path.isdir(product_location): - print("Error, unable to determine the product location. This is most likely because build_type was") - print("incorrectly passed. Or the product is not built. Please explicitely pass -product_location") - - sys.exit(1) - + is_same_os = build_info["build_os"] == coreclr_setup_args.host_os + is_same_arch = build_info["build_arch"] == coreclr_setup_args.arch + is_same_build_type = build_info["build_type"] == coreclr_setup_args.build_type + + if coreclr_setup_args.host_os != "Windows_NT" and not (is_same_os and is_same_arch and is_same_build_type): + test_native_bin_location = None + if args.test_native_bin_location is None: + test_native_bin_location = os.path.join(os.path.join(coreclr_setup_args.coreclr_repo_location, "bin", "obj", "%s.%s.%s" % (coreclr_setup_args.host_os, coreclr_setup_args.arch, coreclr_setup_args.build_type), "tests")) + else: + test_native_bin_location = args.test_native_bin_location + + coreclr_setup_args.verify(test_native_bin_location, + "test_native_bin_location", + lambda test_native_bin_location: os.path.isdir(test_native_bin_location), + "Error setting test_native_bin_location") else: - product_location = args.product_location - - return host_os, arch, build_type, coreclr_repo_location, product_location, core_root, test_location, test_native_bin_location + setattr(coreclr_setup_args, "test_native_bin_location", None) + + print("host_os :%s" % coreclr_setup_args.host_os) + print("arch :%s" % coreclr_setup_args.arch) + print("build_type :%s" % coreclr_setup_args.build_type) + print("coreclr_repo_location :%s" % coreclr_setup_args.coreclr_repo_location) + print("product_location :%s" % coreclr_setup_args.product_location) + print("core_root :%s" % coreclr_setup_args.core_root) + print("test_location :%s" % coreclr_setup_args.test_location) + print("test_native_bin_location :%s" % coreclr_setup_args.test_native_bin_location) + + return ( + coreclr_setup_args.host_os, + coreclr_setup_args.arch, + coreclr_setup_args.build_type, + coreclr_setup_args.coreclr_repo_location, + coreclr_setup_args.product_location, + coreclr_setup_args.core_root, + coreclr_setup_args.test_location, + coreclr_setup_args.test_native_bin_location + ) def setup_tools(host_os, coreclr_repo_location): """ Setup the tools for the repo diff --git a/tests/scripts/run-pmi-diffs.py b/tests/scripts/run-pmi-diffs.py index 4416ab8bf2..bfaaec5055 100644..100755 --- a/tests/scripts/run-pmi-diffs.py +++ b/tests/scripts/run-pmi-diffs.py @@ -4,10 +4,8 @@ # The .NET Foundation licenses this file to you under the MIT license. # See the LICENSE file in the project root for more information. # -########################################################################## -########################################################################## -# -# Module: run-pmi-diffs.py +## +# Title :run-pmi-diffs.py # # Notes: # @@ -26,17 +24,20 @@ import os import re import shutil import subprocess +import urllib import sys import tarfile import zipfile # Version specific imports - if sys.version_info.major < 3: import urllib else: import urllib.request +sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "scripts")) +from coreclr_arguments import * + ########################################################################## # Globals ########################################################################## @@ -126,79 +127,85 @@ class ChangeDir: def validate_args(args): """ Validate all of the arguments parsed. Args: - args (argparser.ArgumentParser): Args parsed by the argument parser. + args (argparser.ArgumentParser) : Args parsed by the argument parser. Returns: - (arch, ci_arch, build_type, base_root, diff_root, scratch_root, skip_baseline_build, skip_diffs, target_branch, commit_hash) - (str, str, str, str, str, str, bool, bool, str, str) + args (CoreclrArguments) : Args parsed Notes: - If the arguments are valid then return them all in a tuple. If not, raise - an exception stating x argument is incorrect. + If the arguments are valid then return them all in a tuple. If not, + raise an exception stating x argument is incorrect. """ - arch = args.arch - ci_arch = args.ci_arch - build_type = args.build_type - base_root = args.base_root - diff_root = args.diff_root - scratch_root = args.scratch_root - skip_baseline_build = args.skip_baseline_build - skip_diffs = args.skip_diffs - target_branch = args.target_branch - commit_hash = args.commit_hash - - def validate_arg(arg, check): - """ Validate an individual arg - Args: - arg (str|bool): argument to be validated - check (lambda: x-> bool): test that returns either True or False - : based on whether the check passes. - - Returns: - is_valid (bool): Is the argument valid? - """ - - helper = lambda item: item is not None and check(item) - - if not helper(arg): - raise Exception('Argument: %s is not valid.' % (arg)) - - valid_archs = ['x86', 'x64', 'arm', 'arm64'] - valid_ci_archs = valid_archs + ['x86_arm_altjit', 'x64_arm64_altjit'] - valid_build_types = ['Debug', 'Checked', 'Release'] - - arch = next((a for a in valid_archs if a.lower() == arch.lower()), arch) - build_type = next((b for b in valid_build_types if b.lower() == build_type.lower()), build_type) - - validate_arg(arch, lambda item: item in valid_archs) - validate_arg(build_type, lambda item: item in valid_build_types) - - if diff_root is None: - diff_root = nth_dirname(os.path.abspath(sys.argv[0]), 3) - else: - diff_root = os.path.abspath(diff_root) - validate_arg(diff_root, lambda item: os.path.isdir(diff_root)) - - if scratch_root is None: - scratch_root = os.path.join(diff_root, '_', 'pmi') - else: - scratch_root = os.path.abspath(scratch_root) - - if ci_arch is not None: - validate_arg(ci_arch, lambda item: item in valid_ci_archs) - - args = (arch, ci_arch, build_type, base_root, diff_root, scratch_root, skip_baseline_build, skip_diffs, target_branch, commit_hash) + coreclr_setup_args = CoreclrArguments(args, + require_built_test_dir=False, + require_built_core_root=True, + require_built_product_dir=False) + + coreclr_setup_args.verify(args, + "base_root", + lambda directory: os.path.isdir(directory) if directory is not None else True, + "Base root is not a valid directory") + + coreclr_setup_args.verify(args, + "diff_root", + lambda directory: os.path.isdir(directory) if directory is not None else True, + "Base root is not a valid directory", + modify_arg=lambda directory: nth_dirname(os.path.abspath(sys.argv[0]), 3) if directory is None else os.path.abspath(directory)) + + coreclr_setup_args.verify(args, + "scratch_root", + lambda directory: os.path.isdir(directory) if directory is not None else True, + "Base root is not a valid directory", + modify_arg=lambda directory: nth_dirname(os.path.abspath(sys.argv[0]), 3) if directory is None else os.path.abspath(directory)) + + coreclr_setup_args.verify(args, + "skip_baseline_build", + lambda unused: True, + "Error setting baseline build") + + coreclr_setup_args.verify(args, + "skip_diffs", + lambda unused: True, + "Error setting skip_diffs") + + coreclr_setup_args.verify(args, + "target_branch", + lambda unused: True, + "Error setting target_branch") + + coreclr_setup_args.verify(args, + "commit_hash", + lambda unused: True, + "Error setting commit_hash") + + coreclr_setup_args.verify(args, + "ci_arch", + lambda ci_arch: ci_arch in coreclr_setup_args.valid_arches + ['x86_arm_altjit', 'x64_arm64_altjit'], + "Error setting ci_arch") + + args = ( + coreclr_setup_args.arch, + coreclr_setup_args.ci_arch, + coreclr_setup_args.build_type, + coreclr_setup_args.base_root, + coreclr_setup_args.diff_root, + coreclr_setup_args.scratch_root, + coreclr_setup_args.skip_baseline_build, + coreclr_setup_args.skip_diffs, + coreclr_setup_args.target_branch, + coreclr_setup_args.commit_hash + ) log('Configuration:') - log(' arch: %s' % arch) - log(' ci_arch: %s' % ci_arch) - log(' build_type: %s' % build_type) - log(' base_root: %s' % base_root) - log(' diff_root: %s' % diff_root) - log(' scratch_root: %s' % scratch_root) - log(' skip_baseline_build: %s' % skip_baseline_build) - log(' skip_diffs: %s' % skip_diffs) - log(' target_branch: %s' % target_branch) - log(' commit_hash: %s' % commit_hash) + log(' arch: %s' % coreclr_setup_args.arch) + log(' ci_arch: %s' % coreclr_setup_args.ci_arch) + log(' build_type: %s' % coreclr_setup_args.build_type) + log(' base_root: %s' % coreclr_setup_args.base_root) + log(' diff_root: %s' % coreclr_setup_args.diff_root) + log(' scratch_root: %s' % coreclr_setup_args.scratch_root) + log(' skip_baseline_build: %s' % coreclr_setup_args.skip_baseline_build) + log(' skip_diffs: %s' % coreclr_setup_args.skip_diffs) + log(' target_branch: %s' % coreclr_setup_args.target_branch) + log(' commit_hash: %s' % coreclr_setup_args.commit_hash) return args |