1from __future__ import absolute_import
2import inspect
3import os
4import sys
5
6import lit.Test
7import lit.formats
8import lit.TestingConfig
9import lit.util
10
11class LitConfig:
12    """LitConfig - Configuration data for a 'lit' test runner instance, shared
13    across all tests.
14
15    The LitConfig object is also used to communicate with client configuration
16    files, it is always passed in as the global variable 'lit' so that
17    configuration files can access common functionality and internal components
18    easily.
19    """
20
21    def __init__(self, progname, path, quiet,
22                 useValgrind, valgrindLeakCheck, valgrindArgs,
23                 noExecute, debug, isWindows,
24                 params, config_prefix = None):
25        # The name of the test runner.
26        self.progname = progname
27        # The items to add to the PATH environment variable.
28        self.path = [str(p) for p in path]
29        self.quiet = bool(quiet)
30        self.useValgrind = bool(useValgrind)
31        self.valgrindLeakCheck = bool(valgrindLeakCheck)
32        self.valgrindUserArgs = list(valgrindArgs)
33        self.noExecute = noExecute
34        self.debug = debug
35        self.isWindows = bool(isWindows)
36        self.params = dict(params)
37        self.bashPath = None
38
39        # Configuration files to look for when discovering test suites.
40        self.config_prefix = config_prefix or 'lit'
41        self.config_name = '%s.cfg' % (self.config_prefix,)
42        self.site_config_name = '%s.site.cfg' % (self.config_prefix,)
43        self.local_config_name = '%s.local.cfg' % (self.config_prefix,)
44
45        self.numErrors = 0
46        self.numWarnings = 0
47
48        self.valgrindArgs = []
49        if self.useValgrind:
50            self.valgrindArgs = ['valgrind', '-q', '--run-libc-freeres=no',
51                                 '--tool=memcheck', '--trace-children=yes',
52                                 '--error-exitcode=123']
53            if self.valgrindLeakCheck:
54                self.valgrindArgs.append('--leak-check=full')
55            else:
56                # The default is 'summary'.
57                self.valgrindArgs.append('--leak-check=no')
58            self.valgrindArgs.extend(self.valgrindUserArgs)
59
60
61    def load_config(self, config, path):
62        """load_config(config, path) - Load a config object from an alternate
63        path."""
64        if self.debug:
65            self.note('load_config from %r' % path)
66        config.load_from_path(path, self)
67        return config
68
69    def getBashPath(self):
70        """getBashPath - Get the path to 'bash'"""
71        if self.bashPath is not None:
72            return self.bashPath
73
74        self.bashPath = lit.util.which('bash', os.pathsep.join(self.path))
75        if self.bashPath is None:
76            self.bashPath = lit.util.which('bash')
77
78        if self.bashPath is None:
79            self.warning("Unable to find 'bash'.")
80            self.bashPath = ''
81
82        return self.bashPath
83
84    def getToolsPath(self, dir, paths, tools):
85        if dir is not None and os.path.isabs(dir) and os.path.isdir(dir):
86            if not lit.util.checkToolsPath(dir, tools):
87                return None
88        else:
89            dir = lit.util.whichTools(tools, paths)
90
91        # bash
92        self.bashPath = lit.util.which('bash', dir)
93        if self.bashPath is None:
94            self.note("Unable to find 'bash.exe'.")
95            self.bashPath = ''
96
97        return dir
98
99    def _write_message(self, kind, message):
100        # Get the file/line where this message was generated.
101        f = inspect.currentframe()
102        # Step out of _write_message, and then out of wrapper.
103        f = f.f_back.f_back
104        file,line,_,_,_ = inspect.getframeinfo(f)
105        location = '%s:%d' % (os.path.basename(file), line)
106
107        sys.stderr.write('%s: %s: %s: %s\n' % (self.progname, location,
108                                               kind, message))
109
110    def note(self, message):
111        self._write_message('note', message)
112
113    def warning(self, message):
114        self._write_message('warning', message)
115        self.numWarnings += 1
116
117    def error(self, message):
118        self._write_message('error', message)
119        self.numErrors += 1
120
121    def fatal(self, message):
122        self._write_message('fatal', message)
123        sys.exit(2)
124