summaryrefslogtreecommitdiffstats
path: root/src/rocksdb/build_tools/precommit_checker.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/rocksdb/build_tools/precommit_checker.py')
-rwxr-xr-xsrc/rocksdb/build_tools/precommit_checker.py208
1 files changed, 208 insertions, 0 deletions
diff --git a/src/rocksdb/build_tools/precommit_checker.py b/src/rocksdb/build_tools/precommit_checker.py
new file mode 100755
index 00000000..0f8884df
--- /dev/null
+++ b/src/rocksdb/build_tools/precommit_checker.py
@@ -0,0 +1,208 @@
+#!/usr/local/fbcode/gcc-4.9-glibc-2.20-fb/bin/python2.7
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+import argparse
+import commands
+import subprocess
+import sys
+import re
+import os
+import time
+
+
+#
+# Simple logger
+#
+
+class Log:
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.f = open(self.filename, 'w+', 0)
+
+ def caption(self, str):
+ line = "\n##### %s #####\n" % str
+ if self.f:
+ self.f.write("%s \n" % line)
+ else:
+ print(line)
+
+ def error(self, str):
+ data = "\n\n##### ERROR ##### %s" % str
+ if self.f:
+ self.f.write("%s \n" % data)
+ else:
+ print(data)
+
+ def log(self, str):
+ if self.f:
+ self.f.write("%s \n" % str)
+ else:
+ print(str)
+
+#
+# Shell Environment
+#
+
+
+class Env(object):
+
+ def __init__(self, logfile, tests):
+ self.tests = tests
+ self.log = Log(logfile)
+
+ def shell(self, cmd, path=os.getcwd()):
+ if path:
+ os.chdir(path)
+
+ self.log.log("==== shell session ===========================")
+ self.log.log("%s> %s" % (path, cmd))
+ status = subprocess.call("cd %s; %s" % (path, cmd), shell=True,
+ stdout=self.log.f, stderr=self.log.f)
+ self.log.log("status = %s" % status)
+ self.log.log("============================================== \n\n")
+ return status
+
+ def GetOutput(self, cmd, path=os.getcwd()):
+ if path:
+ os.chdir(path)
+
+ self.log.log("==== shell session ===========================")
+ self.log.log("%s> %s" % (path, cmd))
+ status, out = commands.getstatusoutput(cmd)
+ self.log.log("status = %s" % status)
+ self.log.log("out = %s" % out)
+ self.log.log("============================================== \n\n")
+ return status, out
+
+#
+# Pre-commit checker
+#
+
+
+class PreCommitChecker(Env):
+
+ def __init__(self, args):
+ Env.__init__(self, args.logfile, args.tests)
+ self.ignore_failure = args.ignore_failure
+
+ #
+ # Get commands for a given job from the determinator file
+ #
+ def get_commands(self, test):
+ status, out = self.GetOutput(
+ "RATIO=1 build_tools/rocksdb-lego-determinator %s" % test, ".")
+ return status, out
+
+ #
+ # Run a specific CI job
+ #
+ def run_test(self, test):
+ self.log.caption("Running test %s locally" % test)
+
+ # get commands for the CI job determinator
+ status, cmds = self.get_commands(test)
+ if status != 0:
+ self.log.error("Error getting commands for test %s" % test)
+ return False
+
+ # Parse the JSON to extract the commands to run
+ cmds = re.findall("'shell':'([^\']*)'", cmds)
+
+ if len(cmds) == 0:
+ self.log.log("No commands found")
+ return False
+
+ # Run commands
+ for cmd in cmds:
+ # Replace J=<..> with the local environment variable
+ if "J" in os.environ:
+ cmd = cmd.replace("J=1", "J=%s" % os.environ["J"])
+ cmd = cmd.replace("make ", "make -j%s " % os.environ["J"])
+ # Run the command
+ status = self.shell(cmd, ".")
+ if status != 0:
+ self.log.error("Error running command %s for test %s"
+ % (cmd, test))
+ return False
+
+ return True
+
+ #
+ # Run specified CI jobs
+ #
+ def run_tests(self):
+ if not self.tests:
+ self.log.error("Invalid args. Please provide tests")
+ return False
+
+ self.print_separator()
+ self.print_row("TEST", "RESULT")
+ self.print_separator()
+
+ result = True
+ for test in self.tests:
+ start_time = time.time()
+ self.print_test(test)
+ result = self.run_test(test)
+ elapsed_min = (time.time() - start_time) / 60
+ if not result:
+ self.log.error("Error running test %s" % test)
+ self.print_result("FAIL (%dm)" % elapsed_min)
+ if not self.ignore_failure:
+ return False
+ result = False
+ else:
+ self.print_result("PASS (%dm)" % elapsed_min)
+
+ self.print_separator()
+ return result
+
+ #
+ # Print a line
+ #
+ def print_separator(self):
+ print("".ljust(60, "-"))
+
+ #
+ # Print two colums
+ #
+ def print_row(self, c0, c1):
+ print("%s%s" % (c0.ljust(40), c1.ljust(20)))
+
+ def print_test(self, test):
+ print(test.ljust(40), end="")
+ sys.stdout.flush()
+
+ def print_result(self, result):
+ print(result.ljust(20))
+
+#
+# Main
+#
+parser = argparse.ArgumentParser(description='RocksDB pre-commit checker.')
+
+# --log <logfile>
+parser.add_argument('--logfile', default='/tmp/precommit-check.log',
+ help='Log file. Default is /tmp/precommit-check.log')
+# --ignore_failure
+parser.add_argument('--ignore_failure', action='store_true', default=False,
+ help='Stop when an error occurs')
+# <test ....>
+parser.add_argument('tests', nargs='+',
+ help='CI test(s) to run. e.g: unit punit asan tsan ubsan')
+
+args = parser.parse_args()
+checker = PreCommitChecker(args)
+
+print("Please follow log %s" % checker.log.filename)
+
+if not checker.run_tests():
+ print("Error running tests. Please check log file %s"
+ % checker.log.filename)
+ sys.exit(1)
+
+sys.exit(0)