<commit_before>#   Copyright 2011 Red Hat, Inc.
#
#   Licensed 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.

import libxml2
import os.path
import json
import logging
from imgfac.ApplicationConfiguration import ApplicationConfiguration
from imgfac.BuildJob import BuildJob
from imgfac.BuildWatcher import BuildWatcher
from imgfac.ImageWarehouse import ImageWarehouse
from imgfac.PushWatcher import PushWatcher
from imgfac.Singleton import Singleton
from imgfac.Template import Template
from imgfac.JobRegistry import JobRegistry
# Yes - we already import libxml2 - xml is built in - there is no harm here and I like the API
from xml.etree.ElementTree import fromstring

class BuildDispatcher(Singleton):

    def _singleton_init(self):
        self.log = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__))
        self.warehouse = ImageWarehouse(ApplicationConfiguration().configuration['warehouse'])
        self.job_registry = JobRegistry()

    def import_image(self, image_id, build_id, target_identifier, image_desc, target, provider):
        image_id = self._ensure_image_with_template(image_id, Template('<template></template>'), image_desc)
        build_id = self._ensure_build(image_id, build_id)

        target_image_id = self._ensure_target_image(build_id, target)
        provider_image_id = self._ensure_provider_image(target_image_id, provider, target_identifier)

        self._commit_build(image_id, build_id)

        return (image_id, build_id, target_image_id, provider_image_id)

    def build_image_for_targets(self, image_id, build_id, template, targets, job_cls = BuildJob, *args, **kwargs):
        if image_id and not targets:
            targets = self._targets_for_image_id(image_id)

        template = self._load_template(image_id, build_id, template)

        image_id = self._ensure_image_with_template(image_id, template)
        build_id = self._ensure_build(image_id, build_id)

        watcher = BuildWatcher(image_id, build_id, len(targets), self.warehouse)

        jobs = []
        for target in targets:
            job = job_cls(template, target, image_id, build_id, *args, **kwargs)
            job.build_image(watcher)
            jobs.append(job)

        self.job_registry.register(jobs)

        return jobs

    def push_image_to_providers(self, image_id, build_id, providers, credentials, job_cls = BuildJob, *args, **kwargs):
        if not build_id:
            build_id = self._latest_unpushed(image_id)

        watcher = PushWatcher(image_id, build_id, len(providers), self.warehouse)

        jobs = []
        for provider in providers:
            target = self._map_provider_to_target(provider)

            target_image_id = self._target_image_for_build_and_target(build_id, target)

            template = self._template_for_target_image_id(target_image_id)

            job = job_cls(template, target, image_id, build_id, *args, **kwargs)
            job.push_image(target_image_id, provider, credentials, watcher)
            jobs.append(job)

        self.job_registry.register(jobs)

        return jobs

    def get_dynamic_provider_data(self, provider):
        # Get provider details for RHEV-M or VSphere
        # First try to interpret this as an ad-hoc/dynamic provider def
        # If this fails, try to find it in one or the other of the config files
        # If this all fails return None
        # We use this in the builders as well so I have made it "public"

        try:
            xml_et = fromstring(provider)
            return xml_et.attrib
        except:
            pass

        try:
            jload = json.loads(provider)
            return jload
        except ValueError:
            pass

        rhevm_data = self._return_dynamic_provider_data(provider, "rhevm")
        if rhevm_data:
            rhevm_data['target'] = "rhevm"
            rhevm_data['name'] = provider
            return rhevm_data

        vsphere_data = self._return_dynamic_provider_data(provider, "vsphere")
        if vsphere_data:
            vsphere_data['target'] = "vsphere"
            vsphere_data['name'] = provider
            return vsphere_data
        
        # It is not there
        return None

    def _xml_node(self, xml, xpath):
        nodes = libxml2.parseDoc(xml).xpathEval(xpath)
        if not nodes:
            return None
        return nodes[0].content

    def _ensure_image_with_template(self, image_id, template, image_desc=None):
        if not (type(template) == Template):
            template = Template(template)
        if not image_desc:
            name = self._xml_node(template.xml, '/template/name')
            if name:
                image_desc = '<image><name>%s</name></image>' % name
            else:
                image_desc = '<image/>'
        if not template.identifier:
            template.identifier = self.warehouse.store_template(template.xml)
        return self._ensure_image(image_id, image_desc, template.identifier)

    def _ensure_image(self, image_id, image_desc, template_id=None):
        if image_id:
            return image_id
        else:
            return self.warehouse.store_image(None, image_desc, dict(template=template_id))

    def _ensure_build(self, image_id, build_id):
        if build_id:
            return build_id
        return self.warehouse.store_build(None, dict(image = image_id))

    def _ensure_target_image(self, build_id, target):
        target_image_id = self._target_image_for_build_and_target(build_id, target)
        if target_image_id:
            return target_image_id
        return self.warehouse.store_target_image(None, None, dict(build=build_id, target=target))

    def _ensure_provider_image(self, target_image_id, provider, target_identifier):
        provider_image_id = self._provider_image_for_target_image_and_provider(target_image_id, provider)
        if provider_image_id:
            self._set_provider_image_attr(provider_image_id, 'target_identifier', target_identifier)
        else:
            metadata = dict(target_image=target_image_id, provider=provider, target_identifier=target_identifier)
            return self.warehouse.create_provider_image(None, None, metadata)

    def _load_template(self, image_id, build_id, template):
        if not template:
            if build_id:
                template = self._template_for_build_id(build_id)
            if not template and image_id:
                template = self._template_for_image_id(image_id)
        return Template(template)

    def _commit_build(self, image_id, build_id):
        parent_id = self._latest_build(image_id)
        if parent_id:<commit_msg>Don't store empty templates on image import.<commit_after>#   Copyright 2011 Red Hat, Inc.
#
#   Licensed 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.

import libxml2
import os.path
import json
import logging
from imgfac.ApplicationConfiguration import ApplicationConfiguration
from imgfac.BuildJob import BuildJob
from imgfac.BuildWatcher import BuildWatcher
from imgfac.ImageWarehouse import ImageWarehouse
from imgfac.PushWatcher import PushWatcher
from imgfac.Singleton import Singleton
from imgfac.Template import Template
from imgfac.JobRegistry import JobRegistry
# Yes - we already import libxml2 - xml is built in - there is no harm here and I like the API
from xml.etree.ElementTree import fromstring

class BuildDispatcher(Singleton):

    def _singleton_init(self):
        self.log = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__))
        self.warehouse = ImageWarehouse(ApplicationConfiguration().configuration['warehouse'])
        self.job_registry = JobRegistry()

    def import_image(self, image_id, build_id, target_identifier, image_desc, target, provider):
        image_id = self._ensure_image(image_id, image_desc)
        build_id = self._ensure_build(image_id, build_id)

        target_image_id = self._ensure_target_image(build_id, target)
        provider_image_id = self._ensure_provider_image(target_image_id, provider, target_identifier)

        self._commit_build(image_id, build_id)

        return (image_id, build_id, target_image_id, provider_image_id)

    def build_image_for_targets(self, image_id, build_id, template, targets, job_cls = BuildJob, *args, **kwargs):
        if image_id and not targets:
            targets = self._targets_for_image_id(image_id)

        template = self._load_template(image_id, build_id, template)

        image_id = self._ensure_image_with_template(image_id, template)
        build_id = self._ensure_build(image_id, build_id)

        watcher = BuildWatcher(image_id, build_id, len(targets), self.warehouse)

        jobs = []
        for target in targets:
            job = job_cls(template, target, image_id, build_id, *args, **kwargs)
            job.build_image(watcher)
            jobs.append(job)

        self.job_registry.register(jobs)

        return jobs

    def push_image_to_providers(self, image_id, build_id, providers, credentials, job_cls = BuildJob, *args, **kwargs):
        if not build_id:
            build_id = self._latest_unpushed(image_id)

        watcher = PushWatcher(image_id, build_id, len(providers), self.warehouse)

        jobs = []
        for provider in providers:
            target = self._map_provider_to_target(provider)

            target_image_id = self._target_image_for_build_and_target(build_id, target)

            template = self._template_for_target_image_id(target_image_id)

            job = job_cls(template, target, image_id, build_id, *args, **kwargs)
            job.push_image(target_image_id, provider, credentials, watcher)
            jobs.append(job)

        self.job_registry.register(jobs)

        return jobs

    def get_dynamic_provider_data(self, provider):
        # Get provider details for RHEV-M or VSphere
        # First try to interpret this as an ad-hoc/dynamic provider def
        # If this fails, try to find it in one or the other of the config files
        # If this all fails return None
        # We use this in the builders as well so I have made it "public"

        try:
            xml_et = fromstring(provider)
            return xml_et.attrib
        except:
            pass

        try:
            jload = json.loads(provider)
            return jload
        except ValueError:
            pass

        rhevm_data = self._return_dynamic_provider_data(provider, "rhevm")
        if rhevm_data:
            rhevm_data['target'] = "rhevm"
            rhevm_data['name'] = provider
            return rhevm_data

        vsphere_data = self._return_dynamic_provider_data(provider, "vsphere")
        if vsphere_data:
            vsphere_data['target'] = "vsphere"
            vsphere_data['name'] = provider
            return vsphere_data
        
        # It is not there
        return None

    def _xml_node(self, xml, xpath):
        nodes = libxml2.parseDoc(xml).xpathEval(xpath)
        if not nodes:
            return None
        return nodes[0].content

    def _ensure_image_with_template(self, image_id, template, image_desc=None):
        if not (type(template) == Template):
            template = Template(template)
        if not image_desc:
            name = self._xml_node(template.xml, '/template/name')
            if name:
                image_desc = '<image><name>%s</name></image>' % name
            else:
                image_desc = '<image/>'
        if not template.identifier:
            template.identifier = self.warehouse.store_template(template.xml)
        return self._ensure_image(image_id, image_desc, template.identifier)

    def _ensure_image(self, image_id, image_desc, template_id=None):
        if image_id:
            return image_id
        elif(template_id):
            return self.warehouse.store_image(None, image_desc, dict(template=template_id))
        else:
            return self.warehouse.store_image(None, image_desc)

    def _ensure_build(self, image_id, build_id):
        if build_id:
            return build_id
        return self.warehouse.store_build(None, dict(image = image_id))

    def _ensure_target_image(self, build_id, target):
        target_image_id = self._target_image_for_build_and_target(build_id, target)
        if target_image_id:
            return target_image_id
        return self.warehouse.store_target_image(None, None, dict(build=build_id, target=target))

    def _ensure_provider_image(self, target_image_id, provider, target_identifier):
        provider_image_id = self._provider_image_for_target_image_and_provider(target_image_id, provider)
        if provider_image_id:
            self._set_provider_image_attr(provider_image_id, 'target_identifier', target_identifier)
        else:
            metadata = dict(target_image=target_image_id, provider=provider, target_identifier=target_identifier)
            return self.warehouse.create_provider_image(None, None, metadata)

    def _load_template(self, image_id, build_id, template):
        if not template:
            if build_id:
                template = self._template_for_build_id(build_id)
            if not template and image_id:
                template = self._template_for_image_id(image_id)
        return Template(template)

    def _commit_build(self, image_id, build_id):
        parent_id = self._latest_build(image_id)
        if parent_id:
{'fraction_non_alphanumeric': 0.07631780516677111, 'fraction_numerical': 0.0016711928138709003, 'mean_word_length': 2.932639649507119, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 26}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2327803', 'n_tokens_mistral': 4152, 'n_tokens_neox': 4052, 'n_words': 1054}