From a90cfa523c6587b28d17941e715f606f28664252 Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Thu, 23 Aug 2018 15:35:17 +0200 Subject: [PATCH] Start reading Puppetfiles --- lib/webhooks/get_forge_modules.py | 57 ++++++++++++++++++++++++++++++- lib/webhooks/module_info.py | 54 +++++++++++++++++++++++++++-- 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/lib/webhooks/get_forge_modules.py b/lib/webhooks/get_forge_modules.py index a7ec0e3..1d39f0a 100644 --- a/lib/webhooks/get_forge_modules.py +++ b/lib/webhooks/get_forge_modules.py @@ -53,6 +53,9 @@ class GetForgeModulesApp(BaseHookApp): default_http_timeout = 30 max_http_timeout = 600 + re_comment = re.compile(r'^\s*#') + re_comma_at_end = re.compile(r',\s*$') + open_args = {} if six.PY3: open_args = { @@ -154,7 +157,59 @@ class GetForgeModulesApp(BaseHookApp): # ------------------------------------------------------------------------- def collect_local_modules(self): - pass + self.modules = {} + + for env in self.environments: + self.read_puppetfile(env) + + # ------------------------------------------------------------------------- + def read_puppetfile(self, env): + + puppetfile = os.path.join(self.puppet_root_env_dir, env, 'Puppetfile') + if self.verbose > 1: + LOG.debug("Searching {!r} ...".format(puppetfile)) + if not os.path.exists(puppetfile): + LOG.warn("Could not find {!r}.".format(puppetfile)) + return + if not os.access(puppetfile, os.R_OK): + LOG.warn("No read access to {!r}.".format(puppetfile)) + return + + LOG.debug("Reading {!r} ...".format(puppetfile)) + + with open(puppetfile, 'r', **self.open_args) as fh: + if self.verbose > 3: + LOG.debug("Class of opened file: {!r}".format(fh.__class__.__name__)) + prev_line = '' + for line in fh.readlines(): + + line = line.strip() + if not line: + continue + if self.re_comment.match(line): + continue + + if self.verbose > 3: + LOG.debug("Read line {!r}...".format(line)) + + prev_line += line + if self.re_comma_at_end.search(line): + continue + + if self.verbose > 2: + LOG.debug("Evaluating line {!r}...".format(prev_line)) + module_info = ModuleInfo.init_from_puppetfile_line( + appname=self.appname, verbose=self.verbose, base_dir=self.base_dir, + line=prev_line, env=env) + + prev_line = '' + + if prev_line: + if self.verbose > 2: + LOG.debug("Evaluating line {!r}...".format(prev_line)) + module_info = ModuleInfo.init_from_puppetfile_line( + appname=self.appname, verbose=self.verbose, base_dir=self.base_dir, + line=prev_line, env=env) # ------------------------------------------------------------------------- def init_puppet_environments(self): diff --git a/lib/webhooks/module_info.py b/lib/webhooks/module_info.py index 261ab5e..b8326c0 100644 --- a/lib/webhooks/module_info.py +++ b/lib/webhooks/module_info.py @@ -22,7 +22,7 @@ from .common import pp, to_str from .obj import BaseObjectError from .obj import BaseObject -__version__ = '0.1.0' +__version__ = '0.2.0' LOG = logging.getLogger(__name__) @@ -38,6 +38,7 @@ class ModuleInfo(BaseObject): """Class for encapsulating information about a Puppet module.""" re_split_name = re.compile(r'^\s*([a-z0-9]+)[-/_](\S+)\s*$', re.IGNORECASE) + re_mod_pf_line = re.compile(r'\s*mod\s+\'([^\']+)\'\s*,\s*(\S+.*)\s*$', re.IGNORECASE) # ------------------------------------------------------------------------- def __init__( @@ -69,7 +70,7 @@ class ModuleInfo(BaseObject): if _full_name: - match = re_split_name.match(_full_name) + match = self.re_split_name.match(_full_name) if not match: raise ModuleInfoError( "Could not analyze given full module name {!r}.".format( @@ -140,6 +141,55 @@ class ModuleInfo(BaseObject): else: self._full_name_orig = None + # ------------------------------------------------------------------------- + def as_dict(self, short=True): + """ + Transforms the elements of the object into a dict + + @return: structure as dict + @rtype: dict + """ + + res = super(ModuleInfo, self).as_dict() + + res['name'] = self.name + res['vendor'] = self.vendor + res['full_name'] = self.full_name + res['full_name_orig'] = self.full_name_orig + + return res + + # ------------------------------------------------------------------------- + @classmethod + def init_from_puppetfile_line( + cls, line, env, appname=None, verbose=0, base_dir=None): + + match = cls.re_mod_pf_line.search(line) + if not match: + if verbose > 2: + LOG.debug("Line {!r} is not a module definition line.".format(line)) + return None + + fullname_orig = match.group(1) + mod_def = match.group(2) + module_info = None + + try: + module_info = cls( + appname=appname, verbose=verbose, base_dir=base_dir, + full_name=fullname_orig, + ) + except ModuleInfoError as e: + LOG.warn("{c}: {e}".format(c=e.__class__.__name__, e=e)) + return None + + module_info.initialized = True + + if verbose > 2: + LOG.debug("Initialized {c} object:\n{s}".format( + c=module_info.__class__.__name__, s=pp(module_info.as_dict()))) + + return module_info # ============================================================================= -- 2.39.5