3 # GObject-Introspection - a framework for introspecting GObject libraries
4 # Copyright (C) 2010 Red Hat, Inc.
5 # Copyright (C) 2010 Johan Dahlin
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License
9 # as published by the Free Software Foundation; either version 2
10 # of the License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
33 class Position(object):
35 Represents a position in the source file which we
39 __slots__ = ('filename', 'line', 'column')
41 def __init__(self, filename=None, line=None, column=None):
42 self.filename = filename
46 def __cmp__(self, other):
47 return cmp((self.filename, self.line, self.column),
48 (other.filename, other.line, other.column))
51 return '<Position %s:%d:%d>' % (os.path.basename(self.filename), self.line or -1,
54 def format(self, cwd):
55 filename = os.path.realpath(self.filename)
56 cwd = os.path.realpath(cwd)
57 common_prefix = os.path.commonprefix((filename, cwd))
59 filename = os.path.relpath(filename, common_prefix)
61 if self.column is not None:
62 return '%s:%d:%d' % (filename, self.line, self.column)
63 elif self.line is not None:
64 return '%s:%d' % (filename, self.line, )
66 return '%s:' % (filename, )
69 class MessageLogger(object):
72 def __init__(self, namespace, output=None):
75 self._cwd = os.getcwd()
77 self._namespace = namespace
78 self._enable_warnings = []
79 self._warning_count = 0
83 def get(cls, *args, **kwargs):
84 if cls._instance is None:
85 cls._instance = cls(*args, **kwargs)
88 def enable_warnings(self, log_types):
89 self._enable_warnings = log_types
91 def get_warning_count(self):
92 return self._warning_count
94 def get_error_count(self):
95 return self._error_count
97 def log(self, log_type, text, positions=None, prefix=None):
99 Log a warning, using optional file positioning information.
100 If the warning is related to a ast.Node type, see log_node().
102 utils.break_on_debug_flag('warning')
104 self._warning_count += 1
106 if not log_type in self._enable_warnings:
109 if type(positions) == set:
110 positions = list(positions)
111 if isinstance(positions, Position):
112 positions = [positions]
115 positions = [Position('<unknown>')]
117 for position in positions[:-1]:
118 self._output.write("%s:\n" % (position.format(cwd=self._cwd), ))
119 last_position = positions[-1].format(cwd=self._cwd)
121 if log_type == WARNING:
122 error_type = "Warning"
123 elif log_type == ERROR:
125 self._error_count += 1
126 elif log_type == FATAL:
130 text = ('%s: %s: %s: %s: %s\n' % (last_position, error_type,
131 self._namespace.name, prefix, text))
134 text = ('%s: %s: %s: %s\n' % (last_position, error_type,
135 self._namespace.name, text))
137 text = ('%s: %s: %s\n' % (last_position, error_type, text))
139 self._output.write(text)
141 if log_type == FATAL:
142 utils.break_on_debug_flag('fatal')
143 raise SystemExit(text)
145 def log_node(self, log_type, node, text, context=None, positions=None):
147 Log a warning, using information about file positions from
148 the given node. The optional context argument, if given, should be
149 another ast.Node type which will also be displayed. If no file position
150 information is available from the node, the position data from the
151 context will be used.
155 elif getattr(node, 'file_positions', None):
156 positions = node.file_positions
157 elif context and context.file_positions:
158 positions = context.file_positions
162 text = "context=%r %s" % (node, text)
165 text = "%s: %s" % (getattr(context, 'symbol', context.name), text)
166 elif not positions and hasattr(node, 'name'):
167 text = "(%s)%s: %s" % (node.__class__.__name__, node.name, text)
169 self.log(log_type, text, positions)
171 def log_symbol(self, log_type, symbol, text):
172 """Log a warning in the context of the given symbol."""
173 self.log(log_type, text, symbol.position,
174 prefix="symbol=%r" % (symbol.ident, ))
177 def log_node(log_type, node, text, context=None, positions=None):
178 ml = MessageLogger.get()
179 ml.log_node(log_type, node, text, context=context, positions=positions)
182 def warn(text, positions=None, prefix=None):
183 ml = MessageLogger.get()
184 ml.log(WARNING, text, positions, prefix)
187 def warn_node(node, text, context=None, positions=None):
188 log_node(WARNING, node, text, context=context, positions=positions)
191 def warn_symbol(symbol, text):
192 ml = MessageLogger.get()
193 ml.log_symbol(WARNING, symbol, text)
196 def error(text, positions=None, prefix=None):
197 ml = MessageLogger.get()
198 ml.log(ERROR, text, positions, prefix)
201 def fatal(text, positions=None, prefix=None):
202 ml = MessageLogger.get()
203 ml.log(FATAL, text, positions, prefix)