<filename>jerikan/jerakia.py
"""Key-value store functions."""

import logging
import yaml
import functools
import os
import copy
from yaml import CSafeLoader as SafeLoader

logger = logging.getLogger(__name__)


class Jerakia(object):
    def __init__(self, schema, datapath, classifier, searchpaths):
        self.classifier = classifier
        self.schema = schema
        self.datapath = datapath
        with open(searchpaths) as code:
            g = {}
            exec(compile(code.read(), "searchpaths.py", "exec"), g)
            self.searchpaths = g['searchpaths']

    @functools.lru_cache(maxsize=None)
    def yaml_load(self, path):
        if not os.path.exists(path):
            return None
        with open(path) as input:
            return yaml.load(input, Loader=SafeLoader)

    @functools.lru_cache(maxsize=None)
    def lookup(self, device, namespace, key):
        """Lookup a value in Jerakia for a given device."""
        scope = self.classifier.scope(device)
        merge = self.schema.get(namespace, {}).get(key, {}).get("merge", None)
        assert merge in (None, "hash", "array")
        found = None
        for path in self.searchpaths(scope):
            path = os.path.join(self.datapath, path, f"{namespace}.yaml")
            data = self.yaml_load(path)
            if data is None or not key in data:
                continue
            current = copy.deepcopy(data[key])
            if merge is None:
                return current
            if found is None:
                found = current
            elif merge == "hash":
                current.update(found)
                found = current
            elif merge == "array":
                found.extend(current)
        return found
