1be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarclass LitConfig:
2be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    """LitConfig - Configuration data for a 'lit' test runner instance, shared
3be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    across all tests.
4be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
5be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    The LitConfig object is also used to communicate with client configuration
6be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    files, it is always passed in as the global variable 'lit' so that
7be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    configuration files can access common functionality and internal components
8be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    easily.
9be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    """
10be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
11c2be84fd490d2e0a8de1731adf9c996ba15bba5cDaniel Dunbar    # Provide access to Test module.
12c2be84fd490d2e0a8de1731adf9c996ba15bba5cDaniel Dunbar    import Test
13c2be84fd490d2e0a8de1731adf9c996ba15bba5cDaniel Dunbar
14be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Provide access to built-in formats.
15be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    import LitFormats as formats
16be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
17be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Provide access to built-in utility functions.
18be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    import Util as util
19be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
20be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    def __init__(self, progname, path, quiet,
2132989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin                 useValgrind, valgrindLeakCheck, valgrindArgs,
22be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                 useTclAsSh,
237c12837916e647a9225fe2433f826588f2f28726Andrew Trick                 noExecute, ignoreStdErr, debug, isWindows,
24f626167e69d08f500805d209ff80720240adde3fDaniel Dunbar                 params):
25be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # The name of the test runner.
26be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.progname = progname
27be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # The items to add to the PATH environment variable.
28be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.path = list(map(str, path))
29be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.quiet = bool(quiet)
30be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.useValgrind = bool(useValgrind)
3132989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin        self.valgrindLeakCheck = bool(valgrindLeakCheck)
3232989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin        self.valgrindUserArgs = list(valgrindArgs)
33be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.useTclAsSh = bool(useTclAsSh)
34be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.noExecute = noExecute
357c12837916e647a9225fe2433f826588f2f28726Andrew Trick        self.ignoreStdErr = ignoreStdErr
36be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.debug = debug
37be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.isWindows = bool(isWindows)
38f626167e69d08f500805d209ff80720240adde3fDaniel Dunbar        self.params = dict(params)
397723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar        self.bashPath = None
40be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
41be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.numErrors = 0
42be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.numWarnings = 0
43be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
4432989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin        self.valgrindArgs = []
4532989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin        self.valgrindTriple = ""
4632989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin        if self.useValgrind:
4732989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin            self.valgrindTriple = "-vg"
4832989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin            self.valgrindArgs = ['valgrind', '-q', '--run-libc-freeres=no',
4932989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin                                 '--tool=memcheck', '--trace-children=yes',
5032989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin                                 '--error-exitcode=123']
5132989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin            if self.valgrindLeakCheck:
5232989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin                self.valgrindTriple += "_leak"
5332989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin                self.valgrindArgs.append('--leak-check=full')
54982873cdfb3faa9fc06a5b9ce6296bfddc0b05c3Jeffrey Yasskin            else:
55982873cdfb3faa9fc06a5b9ce6296bfddc0b05c3Jeffrey Yasskin                # The default is 'summary'.
56982873cdfb3faa9fc06a5b9ce6296bfddc0b05c3Jeffrey Yasskin                self.valgrindArgs.append('--leak-check=no')
5732989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin            self.valgrindArgs.extend(self.valgrindUserArgs)
5832989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin
5932989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin
60be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    def load_config(self, config, path):
61be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        """load_config(config, path) - Load a config object from an alternate
62be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        path."""
63be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        from TestingConfig import TestingConfig
64d0b3da1ea266774f97c63b5ec163de964c5711bfAndrew Trick        if self.debug:
65d0b3da1ea266774f97c63b5ec163de964c5711bfAndrew Trick            self.note('load_config from %r' % path)
66be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return TestingConfig.frompath(path, config.parent, self,
67be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      mustExist = True,
68be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      config = config)
69be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
707723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar    def getBashPath(self):
717723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar        """getBashPath - Get the path to 'bash'"""
727723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar        import os, Util
737723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar
747723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar        if self.bashPath is not None:
757723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar            return self.bashPath
767723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar
777723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar        self.bashPath = Util.which('bash', os.pathsep.join(self.path))
787723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar        if self.bashPath is None:
797723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar            # Check some known paths.
80b0ac8677fdcfacea2ff62251ea6515fe6665e37eDaniel Dunbar            for path in ('/bin/bash', '/usr/bin/bash', '/usr/local/bin/bash'):
817723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar                if os.path.exists(path):
827723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar                    self.bashPath = path
837723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar                    break
847723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar
857723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar        if self.bashPath is None:
867723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar            self.warning("Unable to find 'bash', running Tcl tests internally.")
877723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar            self.bashPath = ''
887723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar
897723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar        return self.bashPath
907723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar
91302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi    def getToolsPath(self, dir, paths, tools):
92302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi        import os, Util
93302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi        if dir is not None and os.path.isabs(dir) and os.path.isdir(dir):
94302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi            if not Util.checkToolsPath(dir, tools):
95302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi                return None
96302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi        else:
97302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi            dir = Util.whichTools(tools, paths)
98302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi
99302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi        # bash
100302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi        self.bashPath = Util.which('bash', dir)
101302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi        if self.bashPath is None:
1026bb5fe3a0d7cf92cd5e77382f1c737a919ab7669NAKAMURA Takumi            self.note("Unable to find 'bash.exe'.")
103302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi            self.bashPath = ''
104302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi
105302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi        return dir
106302b16932332fc3eb46a3a65f33597ab1519988aNAKAMURA Takumi
107be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    def _write_message(self, kind, message):
108be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        import inspect, os, sys
109be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
110be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Get the file/line where this message was generated.
111be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        f = inspect.currentframe()
112be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Step out of _write_message, and then out of wrapper.
113be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        f = f.f_back.f_back
114be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        file,line,_,_,_ = inspect.getframeinfo(f)
115be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        location = '%s:%d' % (os.path.basename(file), line)
116be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
117be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        print >>sys.stderr, '%s: %s: %s: %s' % (self.progname, location,
118be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                                kind, message)
119be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
120be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    def note(self, message):
121be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self._write_message('note', message)
122be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
123be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    def warning(self, message):
124be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self._write_message('warning', message)
125be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.numWarnings += 1
126be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
127be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    def error(self, message):
128be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self._write_message('error', message)
129be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self.numErrors += 1
130be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
131be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    def fatal(self, message):
132be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        import sys
133be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        self._write_message('fatal', message)
134be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        sys.exit(2)
135