1894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanclass LitConfig:
2894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    """LitConfig - Configuration data for a 'lit' test runner instance, shared
3894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    across all tests.
4894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
5894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    The LitConfig object is also used to communicate with client configuration
6894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    files, it is always passed in as the global variable 'lit' so that
7894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    configuration files can access common functionality and internal components
8894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    easily.
9894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    """
10894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    # Provide access to Test module.
1219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    import Test
1319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
14894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    # Provide access to built-in formats.
15894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    import LitFormats as formats
16894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
17894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    # Provide access to built-in utility functions.
18894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    import Util as util
19894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
20894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def __init__(self, progname, path, quiet,
21894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                 useValgrind, valgrindLeakCheck, valgrindArgs,
22894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                 useTclAsSh,
2319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                 noExecute, ignoreStdErr, debug, isWindows,
24894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                 params):
25894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        # The name of the test runner.
26894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.progname = progname
27894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        # The items to add to the PATH environment variable.
28894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.path = list(map(str, path))
29894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.quiet = bool(quiet)
30894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.useValgrind = bool(useValgrind)
31894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.valgrindLeakCheck = bool(valgrindLeakCheck)
32894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.valgrindUserArgs = list(valgrindArgs)
33894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.useTclAsSh = bool(useTclAsSh)
34894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.noExecute = noExecute
3519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        self.ignoreStdErr = ignoreStdErr
36894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.debug = debug
37894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.isWindows = bool(isWindows)
38894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.params = dict(params)
39894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.bashPath = None
40894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
41894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.numErrors = 0
42894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.numWarnings = 0
43894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
44894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.valgrindArgs = []
45894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.valgrindTriple = ""
46894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if self.useValgrind:
47894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            self.valgrindTriple = "-vg"
48894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            self.valgrindArgs = ['valgrind', '-q', '--run-libc-freeres=no',
49894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                                 '--tool=memcheck', '--trace-children=yes',
50894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                                 '--error-exitcode=123']
51894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            if self.valgrindLeakCheck:
52894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                self.valgrindTriple += "_leak"
53894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                self.valgrindArgs.append('--leak-check=full')
54894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            else:
55894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                # The default is 'summary'.
56894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                self.valgrindArgs.append('--leak-check=no')
57894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            self.valgrindArgs.extend(self.valgrindUserArgs)
58894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
59894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
60894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def load_config(self, config, path):
61894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        """load_config(config, path) - Load a config object from an alternate
62894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        path."""
63894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        from TestingConfig import TestingConfig
64894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return TestingConfig.frompath(path, config.parent, self,
65894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                                      mustExist = True,
66894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                                      config = config)
67894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
68894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def getBashPath(self):
69894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        """getBashPath - Get the path to 'bash'"""
70894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        import os, Util
71894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
72894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if self.bashPath is not None:
73894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return self.bashPath
74894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
75894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.bashPath = Util.which('bash', os.pathsep.join(self.path))
76894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if self.bashPath is None:
77894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            # Check some known paths.
78894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            for path in ('/bin/bash', '/usr/bin/bash', '/usr/local/bin/bash'):
79894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                if os.path.exists(path):
80894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    self.bashPath = path
81894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    break
82894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
83894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if self.bashPath is None:
84894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            self.warning("Unable to find 'bash', running Tcl tests internally.")
85894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            self.bashPath = ''
86894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
87894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return self.bashPath
88894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
8919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    def getToolsPath(self, dir, paths, tools):
9019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        import os, Util
9119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        if dir is not None and os.path.isabs(dir) and os.path.isdir(dir):
9219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            if not Util.checkToolsPath(dir, tools):
9319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                return None
9419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        else:
9519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            dir = Util.whichTools(tools, paths)
9619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
9719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        # bash
9819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        self.bashPath = Util.which('bash', dir)
9919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        if self.bashPath is None:
10019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            self.note("Unable to find 'bash.exe'.")
10119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            self.bashPath = ''
10219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
10319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        return dir
10419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
105894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def _write_message(self, kind, message):
106894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        import inspect, os, sys
107894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
108894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        # Get the file/line where this message was generated.
109894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        f = inspect.currentframe()
110894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        # Step out of _write_message, and then out of wrapper.
111894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        f = f.f_back.f_back
112894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        file,line,_,_,_ = inspect.getframeinfo(f)
113894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        location = '%s:%d' % (os.path.basename(file), line)
114894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
115894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        print >>sys.stderr, '%s: %s: %s: %s' % (self.progname, location,
116894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                                                kind, message)
117894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
118894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def note(self, message):
119894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self._write_message('note', message)
120894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
121894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def warning(self, message):
122894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self._write_message('warning', message)
123894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.numWarnings += 1
124894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
125894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def error(self, message):
126894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self._write_message('error', message)
127894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.numErrors += 1
128894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
129894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def fatal(self, message):
130894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        import sys
131894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self._write_message('fatal', message)
132894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        sys.exit(2)
133