vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / parser / validation / issue.py
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/parser/validation/issue.py b/azure/aria/aria-extension-cloudify/src/aria/aria/parser/validation/issue.py
new file mode 100644 (file)
index 0000000..42fc580
--- /dev/null
@@ -0,0 +1,190 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import  # so we can import standard 'collections'
+
+from ...utils import (
+    collections,
+    type,
+    threading,
+    exceptions,
+    console,
+    formatting
+)
+
+
+class Issue(object):
+    PLATFORM = 0
+    """
+    Platform error (e.g. I/O, hardware, a bug in ARIA)
+    """
+
+    SYNTAX = 1
+    """
+    Syntax and format (e.g. YAML, XML, JSON)
+    """
+
+    FIELD = 2
+    """
+    Single field
+    """
+
+    BETWEEN_FIELDS = 3
+    """
+    Relationships between fields within the type (internal grammar)
+    """
+
+    BETWEEN_TYPES = 4
+    """
+    Relationships between types (e.g. inheritance, external grammar)
+    """
+
+    BETWEEN_INSTANCES = 5
+    """
+    Topology (e.g. static requirements and capabilities)
+    """
+
+    EXTERNAL = 6
+    """
+    External (e.g. live requirements and capabilities)
+    """
+
+    ALL = 100
+
+    def __init__(self, message=None, exception=None, location=None, line=None,
+                 column=None, locator=None, snippet=None, level=0):
+        if message is not None:
+            self.message = str(message)
+        elif exception is not None:
+            self.message = str(exception)
+        else:
+            self.message = 'unknown issue'
+
+        self.exception = exception
+
+        if locator is not None:
+            self.location = locator.location
+            self.line = locator.line
+            self.column = locator.column
+        else:
+            self.location = location
+            self.line = line
+            self.column = column
+
+        self.snippet = snippet
+        self.level = level
+
+    @property
+    def as_raw(self):
+        return collections.OrderedDict((
+            ('level', self.level),
+            ('message', self.message),
+            ('location', self.location),
+            ('line', self.line),
+            ('column', self.column),
+            ('snippet', self.snippet),
+            ('exception', type.full_type_name(self.exception) if self.exception else None)))
+
+    @property
+    def locator_as_str(self):
+        if self.location is not None:
+            if self.line is not None:
+                if self.column is not None:
+                    return '"%s":%d:%d' % (self.location, self.line, self.column)
+                else:
+                    return '"%s":%d' % (self.location, self.line)
+            else:
+                return '"%s"' % self.location
+        else:
+            return None
+
+    @property
+    def heading_as_str(self):
+        return '%d: %s' % (self.level, self.message)
+
+    @property
+    def details_as_str(self):
+        details_str = ''
+        locator = self.locator_as_str
+        if locator is not None:
+            details_str += '@%s' % locator
+        if self.snippet is not None:
+            details_str += '\n%s' % self.snippet
+        return details_str
+
+    def __str__(self):
+        heading_str = self.heading_as_str
+        details = self.details_as_str
+        if details:
+            heading_str += ', ' + details
+        return heading_str
+
+
+class ReporterMixin(object):
+
+    Issue = Issue
+
+    def __init__(self, *args, **kwargs):
+        super(ReporterMixin, self).__init__(*args, **kwargs)
+        self._issues = threading.LockedList()
+        self.max_level = self.Issue.ALL
+
+    def report(self, message=None, exception=None, location=None, line=None,
+               column=None, locator=None, snippet=None, level=Issue.PLATFORM, issue=None):
+        if issue is None:
+            issue = self.Issue(message, exception, location, line, column, locator, snippet, level)
+
+        # Avoid duplicate issues
+        with self._issues:
+            for i in self._issues:
+                if str(i) == str(issue):
+                    return
+
+            self._issues.append(issue)
+
+    @property
+    def has_issues(self):
+        return len(self._issues) > 0
+
+    @property
+    def issues(self):
+        issues = [i for i in self._issues if i.level <= self.max_level]
+        issues.sort(key=lambda i: (i.level, i.location, i.line, i.column, i.message))
+        return collections.FrozenList(issues)
+
+    @property
+    def issues_as_raw(self):
+        return [formatting.as_raw(i) for i in self.issues]
+
+    def extend_issues(self, *issues):
+        with self._issues:
+            self._issues.extend(*issues)
+
+    def dump_issues(self):
+        issues = self.issues
+        if issues:
+            console.puts(console.Colored.blue('Validation issues:', bold=True))
+            with console.indent(2):
+                for issue in issues:
+                    console.puts(console.Colored.blue(issue.heading_as_str))
+                    details = issue.details_as_str
+                    if details:
+                        with console.indent(3):
+                            console.puts(details)
+                    if issue.exception is not None:
+                        with console.indent(3):
+                            exceptions.print_exception(issue.exception)
+            return True
+        return False