From 7c6191ec117ad613b1e60ade63e2de6291a60d27 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Sat, 8 Dec 2012 15:43:23 +0400 Subject: [PATCH] Refactored run.py script and temporary file generation logic * use OPENCV_TEMP_PATH environment variable on all platforms * fix cleanup after OpenCV tests on Windows * add --list flag to output names of all tests found * do not override user-passed --perf_min_samples and --perf_force_samples options by --check flag * fix complier checks inside run.py --- modules/core/src/system.cpp | 37 +++++------ modules/ts/misc/run.py | 150 +++++++++++++++++++++++++------------------- 2 files changed, 101 insertions(+), 86 deletions(-) diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index e0932a7..b3a136b 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -359,26 +359,24 @@ string format( const char* fmt, ... ) string tempfile( const char* suffix ) { + const char *temp_dir = getenv("OPENCV_TEMP_PATH"); + string fname; + #if defined WIN32 || defined _WIN32 - char temp_dir[MAX_PATH + 1] = { 0 }; + char temp_dir2[MAX_PATH + 1] = { 0 }; char temp_file[MAX_PATH + 1] = { 0 }; - ::GetTempPathA(sizeof(temp_dir), temp_dir); + if (temp_dir == 0 || temp_dir[0] == 0) + { + ::GetTempPathA(sizeof(temp_dir2), temp_dir2); + temp_dir = temp_dir2; + } if(0 == ::GetTempFileNameA(temp_dir, "ocv", 0, temp_file)) return string(); DeleteFileA(temp_file); - string name = temp_file; - if(suffix) - { - if (suffix[0] != '.') - return name + "." + suffix; - else - return name + suffix; - } - else - return name; + fname = temp_file; # else # ifdef ANDROID //char defaultTemplate[] = "/mnt/sdcard/__opencv_temp.XXXXXX"; @@ -387,9 +385,7 @@ string tempfile( const char* suffix ) char defaultTemplate[] = "/tmp/__opencv_temp.XXXXXX"; # endif - string fname; - const char *temp_dir = getenv("OPENCV_TEMP_PATH"); - if(temp_dir == 0 || temp_dir[0] == 0) + if (temp_dir == 0 || temp_dir[0] == 0) fname = defaultTemplate; else { @@ -401,19 +397,20 @@ string tempfile( const char* suffix ) } const int fd = mkstemp((char*)fname.c_str()); - if(fd == -1) return ""; + if (fd == -1) return string(); + close(fd); remove(fname.c_str()); +# endif - if(suffix) + if (suffix) { if (suffix[0] != '.') - fname = fname + "." + suffix; + return fname + "." + suffix; else - fname += suffix; + return fname + suffix; } return fname; -# endif } static CvErrorCallback customErrorCallback = 0; diff --git a/modules/ts/misc/run.py b/modules/ts/misc/run.py index d70effe..6d4507c 100755 --- a/modules/ts/misc/run.py +++ b/modules/ts/misc/run.py @@ -66,13 +66,13 @@ parse_patterns = ( {'name': "opencv_cxx_flags_debug", 'default': "", 'pattern': re.compile("^OPENCV_EXTRA_C_FLAGS_DEBUG:INTERNAL=(.*)$")}, {'name': "opencv_cxx_flags_release", 'default': "", 'pattern': re.compile("^OPENCV_EXTRA_C_FLAGS_RELEASE:INTERNAL=(.*)$")}, {'name': "cxx_flags_android", 'default': None, 'pattern': re.compile("^ANDROID_CXX_FLAGS:INTERNAL=(.*)$")}, - {'name': "cxx_compiler_path", 'default': None, 'pattern': re.compile("^CMAKE_CXX_COMPILER:FILEPATH=(.*)$")}, {'name': "ndk_path", 'default': None, 'pattern': re.compile("^(?:ANDROID_NDK|ANDROID_STANDALONE_TOOLCHAIN)?:PATH=(.*)$")}, {'name': "android_abi", 'default': None, 'pattern': re.compile("^ANDROID_ABI:STRING=(.*)$")}, {'name': "android_executable", 'default': None, 'pattern': re.compile("^ANDROID_EXECUTABLE:FILEPATH=(.*android.*)$")}, {'name': "is_x64", 'default': "OFF", 'pattern': re.compile("^CUDA_64_BIT_DEVICE_CODE:BOOL=(ON)$")},#ugly( {'name': "cmake_generator", 'default': None, 'pattern': re.compile("^CMAKE_GENERATOR:INTERNAL=(.+)$")}, {'name': "cxx_compiler", 'default': None, 'pattern': re.compile("^CMAKE_CXX_COMPILER:FILEPATH=(.+)$")}, + {'name': "cxx_compiler_arg1", 'default': None, 'pattern': re.compile("^CMAKE_CXX_COMPILER_ARG1:[A-Z]+=(.+)$")}, {'name': "with_cuda", 'default': "OFF", 'pattern': re.compile("^WITH_CUDA:BOOL=(ON)$")}, {'name': "cuda_library", 'default': None, 'pattern': re.compile("^CUDA_CUDA_LIBRARY:FILEPATH=(.+)$")}, {'name': "core_dependencies", 'default': None, 'pattern': re.compile("^opencv_core_LIB_DEPENDS:STATIC=(.+)$")}, @@ -199,40 +199,51 @@ def getRunningProcessExePathByName(name): except: return None -class RunInfo(object): - def setCallback(self, name, callback): - setattr(self, name, callback) - - def __init__(self, path, options): +class TestSuite(object): + def __init__(self, options, path = None): self.options = options self.path = path self.error = None self.setUp = None self.tearDown = None - self.nameprefix = "opencv_" + options.mode + "_" + self.adb = None + self.targetos = None + self.nameprefix = "opencv_" + self.options.mode + "_" for p in parse_patterns: setattr(self, p["name"], p["default"]) - cachefile = open(os.path.join(path, "CMakeCache.txt"), "rt") - try: - for l in cachefile.readlines(): - ll = l.strip() - if not ll or ll.startswith("#"): - continue - for p in parse_patterns: - match = p["pattern"].match(ll) - if match: - value = match.groups()[0] - if value and not value.endswith("-NOTFOUND"): - setattr(self, p["name"], value) - except: - pass - cachefile.close() + if self.path: + cachefile = open(os.path.join(self.path, "CMakeCache.txt"), "rt") + try: + for l in cachefile.readlines(): + ll = l.strip() + if not ll or ll.startswith("#"): + continue + for p in parse_patterns: + match = p["pattern"].match(ll) + if match: + value = match.groups()[0] + if value and not value.endswith("-NOTFOUND"): + setattr(self, p["name"], value) + except: + pass + cachefile.close() + + # detect target platform + if self.android_executable or self.android_abi or self.ndk_path: + self.targetos = "android" + else: + self.targetos = hostos + + self.initialize() + + def initialize(self): # fix empty tests dir if not self.tests_dir: self.tests_dir = self.path self.tests_dir = os.path.normpath(self.tests_dir) - # add path to adb + + # compute path to adb if self.android_executable: self.adb = os.path.join(os.path.dirname(os.path.dirname(self.android_executable)), ("platform-tools/adb","platform-tools/adb.exe")[hostos == 'nt']) if not os.path.isfile(self.adb) or not os.access(self.adb, os.X_OK): @@ -240,20 +251,14 @@ class RunInfo(object): else: self.adb = None - # detect target platform - if self.android_executable or self.android_abi or self.ndk_path: - self.targetos = "android" - else: - self.targetos = hostos - if self.targetos == "android": # fix adb tool location if not self.adb: self.adb = getRunningProcessExePathByName("adb") if not self.adb: self.adb = "adb" - if options.adb_serial: - self.adb = [self.adb, "-s", options.adb_serial] + if self.options.adb_serial: + self.adb = [self.adb, "-s", self.options.adb_serial] else: self.adb = [self.adb] try: @@ -261,7 +266,7 @@ class RunInfo(object): except OSError: self.adb = [] # remember current device serial. Needed if another device is connected while this script runs - if self.adb and not options.adb_serial: + if self.adb and not self.options.adb_serial: adb_res = self.runAdb("devices") if not adb_res: self.error = "Could not run adb command: %s (for %s)" % (self.error, self.path) @@ -276,13 +281,10 @@ class RunInfo(object): self.error = "Too many (%s) devices are connected. Please specify single device using --serial option:\n\n" % (len(connected_devices)) + adb_res self.adb = [] else: - options.adb_serial = connected_devices[0].split("\t")[0] - self.adb = self.adb + ["-s", options.adb_serial] + self.options.adb_serial = connected_devices[0].split("\t")[0] + self.adb = self.adb + ["-s", self.options.adb_serial] if self.adb: - print "adb command:", " ".join(self.adb) - - if self.adb: - #construct name for aapt tool + # construct name for aapt tool self.aapt = [os.path.join(os.path.dirname(self.adb[0]), ("aapt","aapt.exe")[hostos == 'nt'])] # fix has_perf_tests param @@ -295,14 +297,17 @@ class RunInfo(object): # fix test path if "Visual Studio" in self.cmake_generator: - if options.configuration: - self.tests_dir = os.path.join(self.tests_dir, options.configuration) + if self.options.configuration: + self.tests_dir = os.path.join(self.tests_dir, self.options.configuration) else: self.tests_dir = os.path.join(self.tests_dir, self.build_type) elif not self.is_x64 and self.cxx_compiler: #one more attempt to detect x64 compiler try: - output = Popen([self.cxx_compiler, "-v"], stdout=PIPE, stderr=PIPE).communicate() + compiler = [self.cxx_compiler] + if self.cxx_compiler_arg1: + compiler.append(self.cxx_compiler_arg1) + output = Popen(compiler + ["-v"], stdout=PIPE, stderr=PIPE).communicate() if not output[0] and "x86_64" in output[1]: self.is_x64 = True except OSError: @@ -499,9 +504,11 @@ class RunInfo(object): fd = os.fdopen(tmpfile[0], "w+b") fd.write(SIMD_DETECTION_PROGRAM) fd.close(); - options = [self.cxx_compiler_path] + options = [self.cxx_compiler] + if self.cxx_compiler_arg1: + options.append(self.cxx_compiler_arg1) cxx_flags = self.cxx_flags + " " + self.cxx_flags_release + " " + self.opencv_cxx_flags + " " + self.opencv_cxx_flags_release - if self.targetos == "android": + if self.targetos == "android" and self.cxx_flags_android: cxx_flags = self.cxx_flags_android + " " + cxx_flags prev_option = None @@ -634,21 +641,21 @@ class RunInfo(object): logfile = userlog[0][userlog[0].find(":")+1:] if self.targetos == "android" and exe.endswith(".apk"): - print "running java tests:", exe + print "Run java tests:", exe try: # get package info output = Popen(self.aapt + ["dump", "xmltree", exe, "AndroidManifest.xml"], stdout=PIPE, stderr=_stderr).communicate() if not output[0]: - print >> _stderr, "failed to get manifest info from", exe + print >> _stderr, "fail to dump manifest from", exe return tags = re.split(r"[ ]+E: ", output[0]) - #get package name + # get package name manifest_tag = [t for t in tags if t.startswith("manifest ")] if not manifest_tag: - print >> _stderr, "failed to get manifest info from", exe + print >> _stderr, "fail to read package name from", exe return pkg_name = re.search(r"^[ ]+A: package=\"(?P.*?)\" \(Raw: \"(?P=pkg)\"\)\r?$", manifest_tag[0], flags=re.MULTILINE).group("pkg") - #get test instrumentation info + # get test instrumentation info instrumentation_tag = [t for t in tags if t.startswith("instrumentation ")] if not instrumentation_tag: print >> _stderr, "can not find instrumentation detials in", exe @@ -663,7 +670,7 @@ class RunInfo(object): pkg_target += self.options.junit_package else: pkg_target = self.options.junit_package - #uninstall already installed package + # uninstall previously installed package print >> _stderr, "Uninstalling old", pkg_name, "from device..." Popen(self.adb + ["uninstall", pkg_name], stdout=PIPE, stderr=_stderr).communicate() print >> _stderr, "Installing new", exe, "to device...", @@ -675,10 +682,10 @@ class RunInfo(object): print >> _stderr, "Failed to install", exe, "to device" return print >> _stderr, "Running jUnit tests for ", pkg_target - if self.setUp is not None: + if self.setUp: self.setUp() Popen(self.adb + ["shell", "am instrument -w -e package " + pkg_target + " " + pkg_name + "/" + pkg_runner], stdout=_stdout, stderr=_stderr).wait() - if self.tearDown is not None: + if self.tearDown: self.tearDown() except OSError: pass @@ -693,27 +700,27 @@ class RunInfo(object): andoidcwd = tempdir + getpass.getuser().replace(" ","") + "_" + self.options.mode +"/" exename = os.path.basename(exe) androidexe = andoidcwd + exename - #upload + # upload _stderr.write("Uploading... ") output = Popen(self.adb + ["push", exe, androidexe], stdout=_stdout, stderr=_stderr).wait() if output != 0: print >> _stderr, "adb finishes unexpectedly with error code", output return - #chmod + # chmod output = Popen(self.adb + ["shell", "chmod 777 " + androidexe], stdout=_stdout, stderr=_stderr).wait() if output != 0: print >> _stderr, "adb finishes unexpectedly with error code", output return - #run + # run if self.options.help: command = exename + " --help" else: command = exename + " " + " ".join(args) print >> _stderr, "Run command:", command - if self.setUp is not None: + if self.setUp: self.setUp() - Popen(self.adb + ["shell", "export OPENCV_TEST_DATA_PATH=" + self.test_data_path + "&& cd " + andoidcwd + "&& ./" + command], stdout=_stdout, stderr=_stderr).wait() - if self.tearDown is not None: + Popen(self.adb + ["shell", "export OPENCV_TEST_DATA_PATH=" + self.options.test_data_path + "&& cd " + andoidcwd + "&& ./" + command], stdout=_stdout, stderr=_stderr).wait() + if self.tearDown: self.tearDown() # try get log if not self.options.help: @@ -758,6 +765,7 @@ class RunInfo(object): try: shutil.rmtree(temp_path) + pass except: pass @@ -767,8 +775,12 @@ class RunInfo(object): return None def runTests(self, tests, _stdout, _stderr, workingDir, args = []): + if not self.isRunnable(): + print >> _stderr, "Error:", self.error if self.error: return [] + if self.adb and self.targetos == "android": + print "adb command:", " ".join(self.adb) if not tests: tests = self.tests logs = [] @@ -802,7 +814,6 @@ if __name__ == "__main__": parser = OptionParser() parser.add_option("-t", "--tests", dest="tests", help="comma-separated list of modules to test", metavar="SUITS", default="") - parser.add_option("-w", "--cwd", dest="cwd", help="working directory for tests", metavar="PATH", default=".") parser.add_option("-a", "--accuracy", dest="accuracy", help="look for accuracy tests instead of performance tests", action="store_true", default=False) parser.add_option("-l", "--longname", dest="useLongNames", action="store_true", help="generate log files with long names", default=False) @@ -812,6 +823,7 @@ if __name__ == "__main__": parser.add_option("", "--package", dest="junit_package", help="Android: run jUnit tests for specified package", metavar="package", default="") parser.add_option("", "--help-tests", dest="help", help="Show help for test executable", action="store_true", default=False) parser.add_option("", "--check", dest="check", help="Shortcut for '--perf_min_samples=1 --perf_force_samples=1'", action="store_true", default=False) + parser.add_option("", "--list", dest="list", help="List available tests", action="store_true", default=False) (options, args) = parser.parse_args(argv) @@ -823,7 +835,7 @@ if __name__ == "__main__": run_args = getRunArgs(args[1:] or ['.']) if len(run_args) == 0: - print >> sys.stderr, "Usage:\n", os.path.basename(sys.argv[0]), "" + print >> sys.stderr, "Usage:", os.path.basename(sys.argv[0]), "[options] [build_path]" exit(1) tests = [s.strip() for s in options.tests.split(",") if s] @@ -833,17 +845,23 @@ if __name__ == "__main__": test_args = [a for a in test_args if not a.startswith("--gtest_output=")] if options.check: - test_args.extend(["--perf_min_samples=1", "--perf_force_samples=1"]) + if not [a for a in test_args if a.startswith("--perf_min_samples=")] : + test_args.extend(["--perf_min_samples=1"]) + if not [a for a in test_args if a.startswith("--perf_force_samples=")] : + test_args.extend(["--perf_force_samples=1"]) logs = [] + test_list = [] for path in run_args: - info = RunInfo(path, options) - #print vars(info),"\n" - if not info.isRunnable(): - print >> sys.stderr, "Error:", info.error + suite = TestSuite(options, path) + #print vars(suite),"\n" + if options.list: + test_list.extend(suite.tests) else: - info.test_data_path = options.test_data_path - logs.extend(info.runTests(tests, sys.stdout, sys.stderr, options.cwd, test_args)) + logs.extend(suite.runTests(tests, sys.stdout, sys.stderr, options.cwd, test_args)) + + if options.list: + print os.linesep.join(test_list) or "No tests found" if logs: print >> sys.stderr, "Collected: ", " ".join(logs) -- 2.7.4