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.bashPath = ''
80
81        return self.bashPath
82
83    def getToolsPath(self, dir, paths, tools):
84        if dir is not None and os.path.isabs(dir) and os.path.isdir(dir):
85            if not lit.util.checkToolsPath(dir, tools):
86                return None
87        else:
88            dir = lit.util.whichTools(tools, paths)
89
90        # bash
91        self.bashPath = lit.util.which('bash', dir)
92        if self.bashPath is None:
93            self.bashPath = ''
94
95        return dir
96
97    def _write_message(self, kind, message):
98        # Get the file/line where this message was generated.
99        f = inspect.currentframe()
100        # Step out of _write_message, and then out of wrapper.
101        f = f.f_back.f_back
102        file,line,_,_,_ = inspect.getframeinfo(f)
103        location = '%s:%d' % (os.path.basename(file), line)
104
105        sys.stderr.write('%s: %s: %s: %s\n' % (self.progname, location,
106                                               kind, message))
107
108    def note(self, message):
109        self._write_message('note', message)
110
111    def warning(self, message):
112        self._write_message('warning', message)
113        self.numWarnings += 1
114
115    def error(self, message):
116        self._write_message('error', message)
117        self.numErrors += 1
118
119    def fatal(self, message):
120        self._write_message('fatal', message)
121        sys.exit(2)
122