Add gobject-introspection.changes file
[profile/ivi/gobject-introspection.git] / giscanner / message.py
1 #!/usr/bin/env python
2 # -*- Mode: Python -*-
3 # GObject-Introspection - a framework for introspecting GObject libraries
4 # Copyright (C) 2010 Red Hat, Inc.
5 # Copyright (C) 2010 Johan Dahlin
6 #
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.
11 #
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.
16 #
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
20 # 02110-1301, USA.
21 #
22
23 import os
24 import sys
25
26 from . import utils
27
28 (WARNING,
29  ERROR,
30  FATAL) = range(3)
31
32
33 class Position(object):
34     """Represents a position in the source file which we
35     want to inform about.
36     """
37     def __init__(self, filename=None, line=None, column=None):
38         self.filename = filename
39         self.line = line
40         self.column = column
41
42     def __cmp__(self, other):
43         return cmp((self.filename, self.line, self.column),
44                    (other.filename, other.line, other.column))
45
46     def __repr__(self):
47         return '<Position %s:%d:%d>' % (
48             os.path.basename(self.filename),
49             self.line or -1,
50             self.column or -1)
51
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, )
60         else:
61             return '%s:' % (filename, )
62
63     def offset(self, offset):
64         return Position(self.filename, self.line+offset, self.column)
65
66
67 class MessageLogger(object):
68     _instance = None
69
70     def __init__(self, namespace, output=None):
71         if output is None:
72             output = sys.stderr
73         self._cwd = os.getcwd() + os.sep
74         self._output = output
75         self._namespace = namespace
76         self._enable_warnings = False
77         self._warning_count = 0
78
79     @classmethod
80     def get(cls, *args, **kwargs):
81         if cls._instance is None:
82             cls._instance = cls(*args, **kwargs)
83         return cls._instance
84
85     def enable_warnings(self, enable):
86         self._enable_warnings = enable
87
88     def get_warning_count(self):
89         return self._warning_count
90
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_warning()."""
94         utils.break_on_debug_flag('warning')
95
96         self._warning_count += 1
97
98         if not self._enable_warnings and log_type != FATAL:
99             return
100
101         # Always drop through on fatal
102
103         if type(positions) == set:
104             positions = list(positions)
105         if isinstance(positions, Position):
106             positions = [positions]
107
108         if not positions:
109             positions = [Position('<unknown>')]
110
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)
114
115         if log_type == WARNING:
116             error_type = "Warning"
117         elif log_type == ERROR:
118             error_type = "Error"
119         elif log_type == FATAL:
120             error_type = "Fatal"
121         if prefix:
122             text = (
123 '''%s: %s: %s: %s: %s\n''' % (last_position, error_type, self._namespace.name,
124                             prefix, text))
125         else:
126             text = (
127 '''%s: %s: %s: %s\n''' % (last_position, error_type, self._namespace.name, text))
128
129         self._output.write(text)
130         if log_type == FATAL:
131             utils.break_on_debug_flag('fatal')
132             raise SystemExit(text)
133
134     def log_node(self, log_type, node, text, context=None, positions=None):
135         """Log a warning, using information about file positions from
136 the given node.  The optional context argument, if given, should be
137 another ast.Node type which will also be displayed.  If no file position
138 information is available from the node, the position data from the
139 context will be used."""
140         if positions:
141             pass
142         elif getattr(node, 'file_positions', None):
143             positions = node.file_positions
144         elif context and context.file_positions:
145             positions = context.file_positions
146         else:
147             positions = []
148             if not context:
149                 text = "context=%r %s" % (node, text)
150
151         if context:
152             text = "%s: %s" % (getattr(context, 'symbol', context.name), text)
153         elif not positions and hasattr(node, 'name'):
154             text = "(%s)%s: %s" % (node.__class__.__name__, node.name, text)
155
156         self.log(log_type, text, positions)
157
158     def log_symbol(self, log_type, symbol, text):
159         """Log a warning in the context of the given symbol."""
160         self.log(log_type, text, symbol.position,
161                  prefix="symbol=%r" % (symbol.ident, ))
162
163
164 def log_node(log_type, node, text, context=None, positions=None):
165     ml = MessageLogger.get()
166     ml.log_node(log_type, node, text, context=context, positions=positions)
167
168 def warn(text, positions=None, prefix=None):
169     ml = MessageLogger.get()
170     ml.log(WARNING, text, positions, prefix)
171
172 def warn_node(node, text, context=None, positions=None):
173     log_node(WARNING, node, text, context=context, positions=positions)
174
175 def warn_symbol(symbol, text):
176     ml = MessageLogger.get()
177     ml.log_symbol(WARNING, symbol, text)
178
179 def fatal(text, positions=None, prefix=None):
180     ml = MessageLogger.get()
181     ml.log(FATAL, text, positions, prefix)