# Copyright Contributors to the Testing Farm project.
# SPDX-License-Identifier: Apache-2.0

import gluetool

import gluetool_modules_framework.libs

from gluetool.log import ContextAdapter

from typing import Optional, Any, Dict  # noqa


class ColdStore(gluetool.Module):
    """
    Provides - and logs - "cold store" URL - an URL somewhere in the wild that, when opened,
    contains artifacts produced by this particular pipeline invocation.
    """

    name = 'coldstore'
    description = 'Provides "cold store" URL'
    supported_dryrun_level = gluetool.glue.DryRunLevels.DRY

    options = {
        'artifacts-location-template': {
            'help': """
                    When set, it will be rendered to provide the **final** location of **pipeline** artifacts.
                    It has access to common eval context, with ``ARTIFACTS_LOCATION`` representing **current**
                    - local, on the machine running the pipeline - location of an artifact.
                    (default: %(default)s).
                    """,
            'default': None
        },
        'coldstore-url-template': {
            'help': 'Template used for creating a cold store URL.'
        }
    }

    required_options = ('coldstore-url-template',)

    shared_functions = ['artifacts_location']

    @property
    def coldstore_url(self):
        # type: () -> str
        return gluetool.utils.render_template(self.option('coldstore-url-template'), **self.shared('eval_context'))

    @property
    def eval_context(self):
        # type: () -> Dict[str, str]
        # To render cold store URL, we need eval context. When asked to provide eval context, we want to
        # include cold store URL. Voila, infinite recursion: eval_context => dasboard_url => eval_context => ...

        if gluetool_modules_framework.libs.is_recursion(__file__, 'eval_context'):
            return {}

        __content__ = {  # noqa
            'COLDSTORE_URL': """
                             URL of the "cold store" page containing artifacts of this particula pipeline.
                             """
        }

        return {
            'COLDSTORE_URL': self.coldstore_url
        }

    def artifacts_location(self, local_path, logger=None, context=None):
        # type: (str, Optional[ContextAdapter], Optional[Dict[str, Any]]) -> str
        """
        Convert **local** location of a pipeline artifact - e.g. a test log generated by a module - into
        a **final** location. The final location may live in a coldstore or some place else, or even be
        equal to the local one.

        The goal is to provide a method for transparently rendering final locations based on coldstore
        and pipeline runner properties (availability, URLs, etc.). Imagine that pipeline is running in
        the environment with coldstore available, next time it has access only to a Jenkins instance,
        third time it's running on user's laptop. Each time, modules need a single point to convert the
        local path to something point to the same file, but when the pipeline finishes, i.e. coldstore
        location, Jenkins ``/artifact/...`` URL or ``file://...`` URL.

        :param str local_path: current, local, location of the artifact. Passed to the template as
            a ``ARTIFACTS_LOCATION`` variable.
        :param logger: logger to use for logging. If not set, this module's logger is used.
        :param dict context: context to use. If not set, global eval context is acquired. It is enhanced
            with ``ARTIFACTS_LOCATION`` variable before use.
        :returns: final location of the artifact.
        """

        logger = logger or self.logger
        context = context or self.shared('eval_context')

        if not self.option('artifacts-location-template'):
            return local_path

        final_path = gluetool.utils.render_template(
            self.option('artifacts-location-template'),
            logger=logger,
            ARTIFACTS_LOCATION=local_path,
            **context
        )

        logger.debug("mapping artifacts location '{}' => {}".format(local_path, final_path))

        # The rendered location may be URL, but also it may be something completely different.
        # Try to treat it like the URL, but ignore failures - ``treat_url`` would fail when
        # the string didn't start with schema, for example.
        try:
            return gluetool.utils.treat_url(final_path, logger=self.logger)

        except:  # noqa: E722  # do not use bare 'except'
            return final_path

    def execute(self):
        # type: () -> None
        if not self.coldstore_url:
            self.warn('Cold store URL seems to be empty')
            return

        self.info('For the pipeline artifacts, see {}'.format(self.coldstore_url))

# Copyright Contributors to the Testing Farm project.
# SPDX-License-Identifier: Apache-2.0

import gluetool

import gluetool_modules_framework.libs

from gluetool.log import ContextAdapter

from typing import Optional, Any, Dict  # noqa


class ColdStore(gluetool.Module):
    """
    Provides - and logs - "cold store" URL - an URL somewhere in the wild that, when opened,
    contains artifacts produced by this particular pipeline invocation.
    """

    name = 'coldstore'
    description = 'Provides "cold store" URL'
    supported_dryrun_level = gluetool.glue.DryRunLevels.DRY

    options = {
        'artifacts-location-template': {
            'help': """
                    When set, it will be rendered to provide the **final** location of **pipeline** artifacts.
                    It has access to common eval context, with ``ARTIFACTS_LOCATION`` representing **current**
                    - local, on the machine running the pipeline - location of an artifact.
                    (default: %(default)s).
                    """,
            'default': None
        },
        'coldstore-url-template': {
            'help': 'Template used for creating a cold store URL.'
        }
    }

    required_options = ('coldstore-url-template',)

    shared_functions = ['artifacts_location']

    @property
    def coldstore_url(self):
        # type: () -> str
        return gluetool.utils.render_template(self.option('coldstore-url-template'), **self.shared('eval_context'))

    @property
    def eval_context(self):
        # type: () -> Dict[str, str]
        # To render cold store URL, we need eval context. When asked to provide eval context, we want to
        # include cold store URL. Voila, infinite recursion: eval_context => dasboard_url => eval_context => ...

        if gluetool_modules_framework.libs.is_recursion(__file__, 'eval_context'):
            return {}

        __content__ = {  # noqa
            'COLDSTORE_URL': """
                             URL of the "cold store" page containing artifacts of this particula pipeline.
                             """
        }

        return {
            'COLDSTORE_URL': self.coldstore_url
        }

    def artifacts_location(self, local_path, logger=None, context=None):
        # type: (str, Optional[ContextAdapter], Optional[Dict[str, Any]]) -> str
        """
        Convert **local** location of a pipeline artifact - e.g. a test log generated by a module - into
        a **final** location. The final location may live in a coldstore or some place else, or even be
        equal to the local one.

        The goal is to provide a method for transparently rendering final locations based on coldstore
        and pipeline runner properties (availability, URLs, etc.). Imagine that pipeline is running in
        the environment with coldstore available, next time it has access only to a Jenkins instance,
        third time it's running on user's laptop. Each time, modules need a single point to convert the
        local path to something point to the same file, but when the pipeline finishes, i.e. coldstore
        location, Jenkins ``/artifact/...`` URL or ``file://...`` URL.

        :param str local_path: current, local, location of the artifact. Passed to the template as
            a ``ARTIFACTS_LOCATION`` variable.
        :param logger: logger to use for logging. If not set, this module's logger is used.
        :param dict context: context to use. If not set, global eval context is acquired. It is enhanced
            with ``ARTIFACTS_LOCATION`` variable before use.
        :returns: final location of the artifact.
        """

        logger = logger or self.logger
        context = context or self.shared('eval_context')

        if not self.option('artifacts-location-template'):
            return local_path

        final_path = gluetool.utils.render_template(
            self.option('artifacts-location-template'),
            logger=logger,
            ARTIFACTS_LOCATION=local_path,
            **context
        )

        logger.debug("mapping artifacts location '{}' => {}".format(local_path, final_path))

        # The rendered location may be URL, but also it may be something completely different.
        # Try to treat it like the URL, but ignore failures - ``treat_url`` would fail when
        # the string didn't start with schema, for example.
        try:
            return gluetool.utils.treat_url(final_path, logger=self.logger)

        except:  # noqa: E722  # do not use bare 'except'
            return final_path

    def execute(self):
        # type: () -> None
        if not self.coldstore_url:
            self.warn('Cold store URL seems to be empty')
            return

        self.info('For the pipeline artifacts, see {}'.format(self.coldstore_url))

# Copyright Contributors to the Testing Farm project. # SPDX-License-Identifier: Apache-2.0 # noqa Provides - and logs - "cold store" URL - an URL somewhere in the wild that, when opened,     contains artifacts produced by this particular pipeline invocation. When set, it will be rendered to provide the **final** location of **pipeline** artifacts.                     It has access to common eval context, with ``ARTIFACTS_LOCATION`` representing **current**                     - local, on the machine running the pipeline - location of an artifact.                     (default: %(default)s). # type: () -> str # type: () -> Dict[str, str] # To render cold store URL, we need eval context. When asked to provide eval context, we want to # include cold store URL. Voila, infinite recursion: eval_context => dasboard_url => eval_context => ... # noqa URL of the "cold store" page containing artifacts of this particula pipeline. # type: (str, Optional[ContextAdapter], Optional[Dict[str, Any]]) -> str Convert **local** location of a pipeline artifact - e.g. a test log generated by a module - into         a **final** location. The final location may live in a coldstore or some place else, or even be         equal to the local one.          The goal is to provide a method for transparently rendering final locations based on coldstore         and pipeline runner properties (availability, URLs, etc.). Imagine that pipeline is running in         the environment with coldstore available, next time it has access only to a Jenkins instance,         third time it's running on user's laptop. Each time, modules need a single point to convert the         local path to something point to the same file, but when the pipeline finishes, i.e. coldstore         location, Jenkins ``/artifact/...`` URL or ``file://...`` URL.          :param str local_path: current, local, location of the artifact. Passed to the template as             a ``ARTIFACTS_LOCATION`` variable.         :param logger: logger to use for logging. If not set, this module's logger is used.         :param dict context: context to use. If not set, global eval context is acquired. It is enhanced             with ``ARTIFACTS_LOCATION`` variable before use.         :returns: final location of the artifact. # The rendered location may be URL, but also it may be something completely different. # Try to treat it like the URL, but ignore failures - ``treat_url`` would fail when # the string didn't start with schema, for example. # noqa: E722  # do not use bare 'except' # type: () -> None