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):
34 """Represents a position in the source file which we
37 def __init__(self, filename=None, line=None, column=None):
38 self.filename = filename
42 def __cmp__(self, other):
43 return cmp((self.filename, self.line, self.column),
44 (other.filename, other.line, other.column))
47 return '<Position %s:%d:%d>' % (
48 os.path.basename(self.filename),
52 def format(self, cwd):
53 filename = self.filename
54 if filename.startswith(cwd):
55 filename = filename[len(cwd):]
56 if self.column is not None:
57 return '%s:%d:%d' % (filename, self.line, self.column)
58 elif self.line is not None:
59 return '%s:%d' % (filename, self.line, )
61 return '%s:' % (filename, )
63 def offset(self, offset):
64 return Position(self.filename, self.line+offset, self.column)
67 class MessageLogger(object):
70 def __init__(self, namespace, output=None):
73 self._cwd = os.getcwd() + os.sep
75 self._namespace = namespace
76 self._enable_warnings = False
77 self._warning_count = 0
80 def get(cls, *args, **kwargs):
81 if cls._instance is None:
82 cls._instance = cls(*args, **kwargs)
85 def enable_warnings(self, enable):
86 self._enable_warnings = enable
88 def get_warning_count(self):
89 return self._warning_count
91 def log(self, log_type, text, positions=None, prefix=None):
92 """Log a warning, using optional file positioning information.
93 If the warning is related to a ast.Node type, see log_node()."""
94 utils.break_on_debug_flag('warning')
96 self._warning_count += 1
98 if not self._enable_warnings and log_type != FATAL:
101 # Always drop through on fatal
103 if type(positions) == set:
104 positions = list(positions)
105 if isinstance(positions, Position):
106 positions = [positions]
109 positions = [Position('<unknown>')]
111 for position in positions[:-1]:
112 self._output.write("%s:\n" % (position.format(cwd=self._cwd), ))
113 last_position = positions[-1].format(cwd=self._cwd)
115 if log_type == WARNING:
116 error_type = "Warning"
117 elif log_type == ERROR:
119 elif log_type == FATAL:
123 '''%s: %s: %s: %s: %s\n''' % (last_position, error_type, self._namespace.name,
128 '''%s: %s: %s: %s\n''' % (last_position, error_type, self._namespace.name, text))
131 '''%s: %s: %s\n''' % (last_position, error_type, text))
133 self._output.write(text)
134 if log_type == FATAL:
135 utils.break_on_debug_flag('fatal')
136 raise SystemExit(text)
138 def log_node(self, log_type, node, text, context=None, positions=None):
139 """Log a warning, using information about file positions from
140 the given node. The optional context argument, if given, should be
141 another ast.Node type which will also be displayed. If no file position
142 information is available from the node, the position data from the
143 context will be used."""
146 elif getattr(node, 'file_positions', None):
147 positions = node.file_positions
148 elif context and context.file_positions:
149 positions = context.file_positions
153 text = "context=%r %s" % (node, text)
156 text = "%s: %s" % (getattr(context, 'symbol', context.name), text)
157 elif not positions and hasattr(node, 'name'):
158 text = "(%s)%s: %s" % (node.__class__.__name__, node.name, text)
160 self.log(log_type, text, positions)
162 def log_symbol(self, log_type, symbol, text):
163 """Log a warning in the context of the given symbol."""
164 self.log(log_type, text, symbol.position,
165 prefix="symbol=%r" % (symbol.ident, ))
168 def log_node(log_type, node, text, context=None, positions=None):
169 ml = MessageLogger.get()
170 ml.log_node(log_type, node, text, context=context, positions=positions)
172 def warn(text, positions=None, prefix=None):
173 ml = MessageLogger.get()
174 ml.log(WARNING, text, positions, prefix)
176 def warn_node(node, text, context=None, positions=None):
177 log_node(WARNING, node, text, context=context, positions=positions)
179 def warn_symbol(symbol, text):
180 ml = MessageLogger.get()
181 ml.log_symbol(WARNING, symbol, text)
183 def fatal(text, positions=None, prefix=None):
184 ml = MessageLogger.get()
185 ml.log(FATAL, text, positions, prefix)