| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 | #!/usr/bin/env python2.7# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.from __future__ import absolute_importfrom __future__ import divisionfrom __future__ import print_functionfrom __future__ import unicode_literalsimport argparseimport commandsimport subprocessimport sysimport reimport osimport 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_failureparser.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)
 |