summaryrefslogtreecommitdiffstats
path: root/azure/aria/aria-extension-cloudify/src/aria/aria/parser/consumption/presentation.py
diff options
context:
space:
mode:
Diffstat (limited to 'azure/aria/aria-extension-cloudify/src/aria/aria/parser/consumption/presentation.py')
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/parser/consumption/presentation.py137
1 files changed, 137 insertions, 0 deletions
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/parser/consumption/presentation.py b/azure/aria/aria-extension-cloudify/src/aria/aria/parser/consumption/presentation.py
new file mode 100644
index 0000000..542b3f0
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/parser/consumption/presentation.py
@@ -0,0 +1,137 @@
+# 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 ...utils.threading import FixedThreadPoolExecutor
+from ...utils.formatting import json_dumps, yaml_dumps
+from ..loading import UriLocation
+from ..reading import AlreadyReadException
+from ..presentation import PresenterNotFoundError
+from .consumer import Consumer
+
+
+class Read(Consumer):
+ """
+ Reads the presentation, handling imports recursively.
+
+ It works by consuming a data source via appropriate :class:`~aria.parser.loading.Loader`,
+ :class:`~aria.parser.reading.Reader`, and :class:`~aria.parser.presentation.Presenter`
+ instances.
+
+ It supports agnostic raw data composition for presenters that have
+ ``_get_import_locations`` and ``_merge_import``.
+
+ To improve performance, loaders are called asynchronously on separate threads.
+
+ Note that parsing may internally trigger more than one loading/reading/presentation
+ cycle, for example if the agnostic raw data has dependencies that must also be parsed.
+ """
+
+ def consume(self):
+ if self.context.presentation.location is None:
+ self.context.validation.report('Presentation consumer: missing location')
+ return
+
+ presenter = None
+ imported_presentations = None
+
+ executor = FixedThreadPoolExecutor(size=self.context.presentation.threads,
+ timeout=self.context.presentation.timeout)
+ executor.print_exceptions = self.context.presentation.print_exceptions
+ try:
+ presenter = self._present(self.context.presentation.location, None, None, executor)
+ executor.drain()
+
+ # Handle exceptions
+ for e in executor.exceptions:
+ self._handle_exception(e)
+
+ imported_presentations = executor.returns
+ finally:
+ executor.close()
+
+ # Merge imports
+ if (imported_presentations is not None) and hasattr(presenter, '_merge_import'):
+ for imported_presentation in imported_presentations:
+ okay = True
+ if hasattr(presenter, '_validate_import'):
+ okay = presenter._validate_import(self.context, imported_presentation)
+ if okay:
+ presenter._merge_import(imported_presentation)
+
+ self.context.presentation.presenter = presenter
+
+ def dump(self):
+ if self.context.has_arg_switch('yaml'):
+ indent = self.context.get_arg_value_int('indent', 2)
+ raw = self.context.presentation.presenter._raw
+ self.context.write(yaml_dumps(raw, indent=indent))
+ elif self.context.has_arg_switch('json'):
+ indent = self.context.get_arg_value_int('indent', 2)
+ raw = self.context.presentation.presenter._raw
+ self.context.write(json_dumps(raw, indent=indent))
+ else:
+ self.context.presentation.presenter._dump(self.context)
+
+ def _handle_exception(self, e):
+ if isinstance(e, AlreadyReadException):
+ return
+ super(Read, self)._handle_exception(e)
+
+ def _present(self, location, origin_location, presenter_class, executor):
+ # Link the context to this thread
+ self.context.set_thread_local()
+
+ raw = self._read(location, origin_location)
+
+ if self.context.presentation.presenter_class is not None:
+ # The presenter class we specified in the context overrides everything
+ presenter_class = self.context.presentation.presenter_class
+ else:
+ try:
+ presenter_class = self.context.presentation.presenter_source.get_presenter(raw)
+ except PresenterNotFoundError:
+ if presenter_class is None:
+ raise
+ # We'll use the presenter class we were given (from the presenter that imported us)
+ if presenter_class is None:
+ raise PresenterNotFoundError('presenter not found')
+
+ presentation = presenter_class(raw=raw)
+
+ if presentation is not None and hasattr(presentation, '_link_locators'):
+ presentation._link_locators()
+
+ # Submit imports to executor
+ if hasattr(presentation, '_get_import_locations'):
+ import_locations = presentation._get_import_locations(self.context)
+ if import_locations:
+ for import_location in import_locations:
+ # The imports inherit the parent presenter class and use the current location as
+ # their origin location
+ import_location = UriLocation(import_location)
+ executor.submit(self._present, import_location, location, presenter_class,
+ executor)
+
+ return presentation
+
+ def _read(self, location, origin_location):
+ if self.context.reading.reader is not None:
+ return self.context.reading.reader.read()
+ loader = self.context.loading.loader_source.get_loader(self.context.loading, location,
+ origin_location)
+ reader = self.context.reading.reader_source.get_reader(self.context.reading, location,
+ loader)
+ return reader.read()