]> Frank Brehm's Git Trees - pixelpark/puppetmaster-webhooks.git/commitdiff
Reading forge cache file
authorFrank Brehm <frank.brehm@pixelpark.com>
Tue, 19 Mar 2019 11:10:53 +0000 (12:10 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Tue, 19 Mar 2019 11:10:53 +0000 (12:10 +0100)
lib/webhooks/forge/mod_dict.py
lib/webhooks/show_modules.py

index e42fa3c8e1fc758e1f4de5cac112eecc57fcf749..483341f5ed1d4f8ec9e66802baa1fb24e1fee895 100644 (file)
@@ -24,11 +24,11 @@ from collections import MutableMapping
 from functools import cmp_to_key
 
 # Third party modules
-
+import six
 from six import reraise
 
 # Own modules
-from fb_tools.common import to_bool, to_bytes
+from fb_tools.common import to_bool, to_bytes, pp
 from fb_tools.obj import FbBaseObject
 
 from .mod_info import ForgeModuleInfo
@@ -37,7 +37,7 @@ from ..errors import BaseHookError
 
 from ..xlate import XLATOR
 
-__version__ = '0.2.2'
+__version__ = '0.3.0'
 
 LOG = logging.getLogger(__name__)
 
@@ -51,6 +51,39 @@ class ForgeModuleDictError(BaseHookError):
     pass
 
 
+# =============================================================================
+class DatafileNotExistingError(ForgeModuleDictError, IOError):
+
+    # -------------------------------------------------------------------------
+    def __init__(self, data_file):
+
+        msg = _("Data file of forge modules cache is not existing")
+        super(DatafileNotExistingError, self).__init__(
+            errno.ENOENT, msg, str(data_file))
+
+
+# =============================================================================
+class DatafileIsDirError(ForgeModuleDictError, IOError):
+
+    # -------------------------------------------------------------------------
+    def __init__(self, data_file):
+
+        msg = _("Data file of forge modules cache is a directory")
+        super(DatafileIsDirError, self).__init__(
+            errno.EISDIR, msg, str(data_file))
+
+
+# =============================================================================
+class DatafileAccessError(ForgeModuleDictError, IOError):
+
+    # -------------------------------------------------------------------------
+    def __init__(self, data_file):
+
+        msg = _("Data file of forge modules cache is not readable")
+        super(DatafileAccessError, self).__init__(
+            errno.EACCES, msg, str(data_file))
+
+
 # =============================================================================
 class ParentNotExistingError(ForgeModuleDictError, IOError):
 
@@ -106,6 +139,14 @@ class ForgeModuleDict(MutableMapping, FbBaseObject):
     default_data_dir = root_path / 'var' / 'lib' / 'webhooks'
     default_data_file = Path('forge-modules.js')
     default_json_indent = 4
+    default_charset = 'utf-8'
+
+    open_args = {}
+    if six.PY3:
+        open_args = {
+            'encoding': default_charset,
+            'errors': 'surrogateescape',
+        }
 
     # -------------------------------------------------------------------------
     # __init__() method required to create instance from class.
@@ -241,6 +282,8 @@ class ForgeModuleDict(MutableMapping, FbBaseObject):
         res['json_indent'] = self.json_indent
         res['simulate'] = self.simulate
         res['sort_by_name'] = self.sort_by_name
+        res['default_charset'] = self.default_charset
+        res['open_args'] = self.open_args
         res['items'] = {}
         res['keys'] = []
         for full_name in self.keys():
@@ -480,6 +523,25 @@ class ForgeModuleDict(MutableMapping, FbBaseObject):
             res[full_name] = self._map[full_name].to_data()
         return res
 
+    # -------------------------------------------------------------------------
+    def from_data(self, data):
+        """Converting the given dict (read from a cache file) and re-instantiate
+            the appropriate module infos."""
+
+        if self.verbose > 1:
+            LOG.debug(_("Converting Python objects into a dict of {} objects.").format(
+                'ForgeModuleInfo'))
+
+        self.clear()
+        for full_name in data.keys():
+            mdata = data[full_name]
+            mod = ForgeModuleInfo.from_data(
+                mdata, appname=self.appname, verbose=self.verbose, base_dir=self.base_dir)
+            self.append(mod)
+
+        if self.verbose > 3:
+            LOG.debug("Re-instantiated forge module infos:\n" + pp(self.as_dict()))
+
     # -------------------------------------------------------------------------
     def write_file(self, output_file=None):
 
@@ -544,6 +606,40 @@ class ForgeModuleDict(MutableMapping, FbBaseObject):
             src=str(tmp_file), tgt=str(output_file)))
         tmp_file.rename(output_file)
 
+    # -------------------------------------------------------------------------
+    def read_file(self, data_file=None):
+
+        if data_file is None:
+            data_file = self.data_file
+        if not data_file.is_absolute():
+            data_file = self.data_dir / self.data_file
+        data_file = Path(os.path.abspath(str(data_file)))
+        fd = None
+
+        if not data_file.exists():
+            raise DatafileNotExistingError(data_file)
+        if data_file.is_dir():
+            raise DatafileIsDirError(data_file)
+        if not os.access(str(data_file), os.R_OK):
+            raise DatafileAccessError(data_file)
+
+        LOG.info(_("Trying to read {!r} ...").format(str(data_file)))
+
+        file_content = None
+        if six.PY3:
+            with open(str(data_file), 'r', **self.open_args) as fh:
+                file_content = fh.read()
+        else:
+            with open(str(data_file), 'r') as fh:
+                file_content = fh.read()
+
+        if self.verbose > 1:
+            LOG.debug(_("Deserialize file content to Python objects."))
+        data = json.loads(file_content)
+        if self.verbose > 3:
+            LOG.debug(_("File content as Python objects:") + '\n' + pp(data))
+
+        self.from_data(data)
 
 # =============================================================================
 if __name__ == "__main__":
index 44dfc79c4e4516dec1f0e6785fd01beadfb79001..40cc33a734a78faefd5b263604512d455c272cd8 100644 (file)
@@ -24,6 +24,7 @@ from . import __version__
 
 from .errors import BaseHookError, UncriticalHookError
 from .base_app import BaseHookApp
+from .forge.mod_dict import ForgeModuleDictError
 from .xlate import XLATOR
 
 LOG = logging.getLogger(__name__)
@@ -190,6 +191,14 @@ class ShowModulesApp(BaseHookApp):
             self.print_out("#" * len_title)
             self.print_out('')
 
+        self.init_puppet_environments()
+        self.collect_local_modules()
+
+        if not self.read_forge_cache():
+            self.exit(7)
+            return
+        return
+
         module_infos = []
         try:
             module_infos = self.read_cache_file()
@@ -198,6 +207,18 @@ class ShowModulesApp(BaseHookApp):
         else:
             self.output_modules(module_infos)
 
+    # -------------------------------------------------------------------------
+    def read_forge_cache(self):
+
+        self.init_forge_module_dict()
+        try:
+            self.forge_modules.read_file()
+        except ForgeModuleDictError as e:
+            LOG.error(_("Got a {cn} reading input data as JSON: {e}").format(
+                cn=e.__class__.__name__, e=e))
+            return False
+        return True
+
     # -------------------------------------------------------------------------
     def output_modules(self, module_infos):