vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / parser / validation / issue.py
1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements.  See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License.  You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 from __future__ import absolute_import  # so we can import standard 'collections'
17
18 from ...utils import (
19     collections,
20     type,
21     threading,
22     exceptions,
23     console,
24     formatting
25 )
26
27
28 class Issue(object):
29     PLATFORM = 0
30     """
31     Platform error (e.g. I/O, hardware, a bug in ARIA)
32     """
33
34     SYNTAX = 1
35     """
36     Syntax and format (e.g. YAML, XML, JSON)
37     """
38
39     FIELD = 2
40     """
41     Single field
42     """
43
44     BETWEEN_FIELDS = 3
45     """
46     Relationships between fields within the type (internal grammar)
47     """
48
49     BETWEEN_TYPES = 4
50     """
51     Relationships between types (e.g. inheritance, external grammar)
52     """
53
54     BETWEEN_INSTANCES = 5
55     """
56     Topology (e.g. static requirements and capabilities)
57     """
58
59     EXTERNAL = 6
60     """
61     External (e.g. live requirements and capabilities)
62     """
63
64     ALL = 100
65
66     def __init__(self, message=None, exception=None, location=None, line=None,
67                  column=None, locator=None, snippet=None, level=0):
68         if message is not None:
69             self.message = str(message)
70         elif exception is not None:
71             self.message = str(exception)
72         else:
73             self.message = 'unknown issue'
74
75         self.exception = exception
76
77         if locator is not None:
78             self.location = locator.location
79             self.line = locator.line
80             self.column = locator.column
81         else:
82             self.location = location
83             self.line = line
84             self.column = column
85
86         self.snippet = snippet
87         self.level = level
88
89     @property
90     def as_raw(self):
91         return collections.OrderedDict((
92             ('level', self.level),
93             ('message', self.message),
94             ('location', self.location),
95             ('line', self.line),
96             ('column', self.column),
97             ('snippet', self.snippet),
98             ('exception', type.full_type_name(self.exception) if self.exception else None)))
99
100     @property
101     def locator_as_str(self):
102         if self.location is not None:
103             if self.line is not None:
104                 if self.column is not None:
105                     return '"%s":%d:%d' % (self.location, self.line, self.column)
106                 else:
107                     return '"%s":%d' % (self.location, self.line)
108             else:
109                 return '"%s"' % self.location
110         else:
111             return None
112
113     @property
114     def heading_as_str(self):
115         return '%d: %s' % (self.level, self.message)
116
117     @property
118     def details_as_str(self):
119         details_str = ''
120         locator = self.locator_as_str
121         if locator is not None:
122             details_str += '@%s' % locator
123         if self.snippet is not None:
124             details_str += '\n%s' % self.snippet
125         return details_str
126
127     def __str__(self):
128         heading_str = self.heading_as_str
129         details = self.details_as_str
130         if details:
131             heading_str += ', ' + details
132         return heading_str
133
134
135 class ReporterMixin(object):
136
137     Issue = Issue
138
139     def __init__(self, *args, **kwargs):
140         super(ReporterMixin, self).__init__(*args, **kwargs)
141         self._issues = threading.LockedList()
142         self.max_level = self.Issue.ALL
143
144     def report(self, message=None, exception=None, location=None, line=None,
145                column=None, locator=None, snippet=None, level=Issue.PLATFORM, issue=None):
146         if issue is None:
147             issue = self.Issue(message, exception, location, line, column, locator, snippet, level)
148
149         # Avoid duplicate issues
150         with self._issues:
151             for i in self._issues:
152                 if str(i) == str(issue):
153                     return
154
155             self._issues.append(issue)
156
157     @property
158     def has_issues(self):
159         return len(self._issues) > 0
160
161     @property
162     def issues(self):
163         issues = [i for i in self._issues if i.level <= self.max_level]
164         issues.sort(key=lambda i: (i.level, i.location, i.line, i.column, i.message))
165         return collections.FrozenList(issues)
166
167     @property
168     def issues_as_raw(self):
169         return [formatting.as_raw(i) for i in self.issues]
170
171     def extend_issues(self, *issues):
172         with self._issues:
173             self._issues.extend(*issues)
174
175     def dump_issues(self):
176         issues = self.issues
177         if issues:
178             console.puts(console.Colored.blue('Validation issues:', bold=True))
179             with console.indent(2):
180                 for issue in issues:
181                     console.puts(console.Colored.blue(issue.heading_as_str))
182                     details = issue.details_as_str
183                     if details:
184                         with console.indent(3):
185                             console.puts(details)
186                     if issue.exception is not None:
187                         with console.indent(3):
188                             exceptions.print_exception(issue.exception)
189             return True
190         return False