gimarshallingtests: Add string_ to boxed structure
[platform/upstream/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()."""
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             if self._namespace:
127                 text = (
128 '''%s: %s: %s: %s\n''' % (last_position, error_type, self._namespace.name, text))
129             else:
130                 text = (
131 '''%s: %s: %s\n''' % (last_position, error_type, text))
132
133         self._output.write(text)
134         if log_type == FATAL:
135             utils.break_on_debug_flag('fatal')
136             raise SystemExit(text)
137
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."""
144         if positions:
145             pass
146         elif getattr(node, 'file_positions', None):
147             positions = node.file_positions
148         elif context and context.file_positions:
149             positions = context.file_positions
150         else:
151             positions = []
152             if not context:
153                 text = "context=%r %s" % (node, text)
154
155         if context:
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)
159
160         self.log(log_type, text, positions)
161
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, ))
166
167
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)
171
172 def warn(text, positions=None, prefix=None):
173     ml = MessageLogger.get()
174     ml.log(WARNING, text, positions, prefix)
175
176 def warn_node(node, text, context=None, positions=None):
177     log_node(WARNING, node, text, context=context, positions=positions)
178
179 def warn_symbol(symbol, text):
180     ml = MessageLogger.get()
181     ml.log_symbol(WARNING, symbol, text)
182
183 def fatal(text, positions=None, prefix=None):
184     ml = MessageLogger.get()
185     ml.log(FATAL, text, positions, prefix)