]> Frank Brehm's Git Trees - pixelpark/puppet-tools.git/commitdiff
Extending class PuppetfileModuleInfo in dpx_puppettools.pfile_moduleinfo
authorFrank Brehm <frank.brehm@pixelpark.com>
Tue, 7 Feb 2023 17:13:09 +0000 (18:13 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Tue, 7 Feb 2023 17:13:09 +0000 (18:13 +0100)
lib/dpx_puppettools/pfile_moduleinfo.py

index 6da775598023cff91bf119500f8e84a6a6cce8b7..95d9c821e4f903b3cbd194c556227f83737ac0b6 100644 (file)
@@ -29,7 +29,7 @@ from .xlate import XLATOR
 from .base_moduleinfo import BaseModuleInfoError, BaseModuleInfo
 
 
-__version__ = '0.1.0'
+__version__ = '0.2.0'
 
 LOG = logging.getLogger(__name__)
 
@@ -56,12 +56,23 @@ class PuppetfileModuleInfo(BaseModuleInfo):
     default_repo_type = 'forge'
     valid_repo_types = ('forge', 'git', 'svn', 'tarball', 'local')
 
+    re_mod_pf_line = re.compile(r'\s*mod\s+\'([^\']+)\'\s*,\s*(\S+.*)\s*$', re.IGNORECASE)
+    re_pf_line_version = re.compile(r"^\s*'([^']+)'")
+    re_def_token = re.compile(r'^\s*(?:,\s*)?([^,]+)(?:\s*,|$)')
+    re_empty = re.compile(r'^\s*(?:,\s*)?$')
+    re_key_val_pair = re.compile(r'^\s*:?([a-z]+)\s*=>\s*[\'"]([^\'"]+)[\'"]\s*$', re.IGNORECASE)
+    re_key_val_pair_unquoted = re.compile(r'^\s*:?([a-z]+)\s*=>\s*(\S+)\s*$', re.IGNORECASE)
+    re_v_at_start = re.compile(r"^v", re.IGNORECASE)
+
+    re_newline = re.compile(r'(?:\r\n?|\n\r?)+')
+
     # -------------------------------------------------------------------------
     def __init__(
         self, appname=None, verbose=0, version=__version__, base_dir=None,
             initialized=None, name=None, vendor=None, full_name=None,
             repo_type=None, repo=None, ref=None, use_control_branch=False,
-            forge_version=None, default_branch=None):
+            forge_version=None, default_branch=None, exclude_spec=False,
+            install_path=None):
 
         self._repo_type = self.default_repo_type
         self._repo = None
@@ -69,6 +80,8 @@ class PuppetfileModuleInfo(BaseModuleInfo):
         self._use_control_branch = False
         self._forge_version = None
         self._default_branch = None
+        self._exclude_spec = False
+        self._install_path = None
 
         super(ModuleInfo, self).__init__(
             appname=appname, verbose=verbose, version=version, base_dir=base_dir,
@@ -82,6 +95,8 @@ class PuppetfileModuleInfo(BaseModuleInfo):
         self.use_control_branch = use_control_branch
         self.forge_version = forge_version
         self.default_branch = default_branch
+        self.exclude_spec = exclude_spec
+        self.install_path = install_path
 
         if initialized:
             self.initialized = True
@@ -156,10 +171,33 @@ class PuppetfileModuleInfo(BaseModuleInfo):
     def use_control_branch(self, value):
         self._use_control_branch = to_bool(value)
 
+    # -------------------------------------------------------------------------
+    @property
+    def exclude_spec(self):
+        """Should the 'spec' subdirectory excluded on checkiung out?"""
+        return self._exclude_spec
+
+    @exclude_spec.setter
+    def exclude_spec(self, value):
+        self._exclude_spec = to_bool(value)
+
+    # -------------------------------------------------------------------------
+    @property
+    def install_path(self):
+        """Installing the module in a different directory than the module name."""
+        return self._install_path
+
+    @install_path.setter
+    def install_path(self, value):
+        if value is None:
+            self._install_path = None
+            return
+        self._install_path = to_str(value)
+
     # -------------------------------------------------------------------------
     @property
     def default_branch(self):
-        """The The default branch name of the repository, if the branch name
+        """The default branch name of the repository, if the branch name
         of the control branch does not exists."""
         return self._default_branch
 
@@ -181,12 +219,14 @@ class PuppetfileModuleInfo(BaseModuleInfo):
 
         res = super(ModuleInfo, self).as_dict(short=short)
 
-        res['repo_type'] = self.repo_type
-        res['repo'] = self.repo
+        res['default_branch'] = self.default_branch
+        res['exclude_spec'] = self.exclude_spec
+        res['forge_version'] = self.forge_version
+        res['install_path'] = self.install_path
         res['ref'] = self.ref
+        res['repo'] = self.repo
+        res['repo_type'] = self.repo_type
         res['use_control_branch'] = self.use_control_branch
-        res['forge_version'] = self.forge_version
-        res['default_branch'] = self.default_branch
 
         return res
 
@@ -196,12 +236,14 @@ class PuppetfileModuleInfo(BaseModuleInfo):
 
         res = super(ModuleInfo, self).to_data()
 
-        res['repo_type'] = self.repo_type
-        res['repo'] = self.repo
+        res['default_branch'] = self.default_branch
+        res['exclude_spec'] = self.exclude_spec
+        res['forge_version'] = self.forge_version
+        res['install_path'] = self.install_path
         res['ref'] = self.ref
+        res['repo'] = self.repo
+        res['repo_type'] = self.repo_type
         res['use_control_branch'] = self.use_control_branch
-        res['forge_version'] = self.forge_version
-        res['default_branch'] = self.default_branch
 
         return res
 
@@ -227,6 +269,10 @@ class PuppetfileModuleInfo(BaseModuleInfo):
             module_info.forge_version = self.forge_version
         if self.default_branch:
             module_info.repo_type = self.default_branch
+        if self.exclude_spec:
+            module_info.exclude_spec = self.exclude_spec
+        if self.install_path:
+            module_info.install_path = self.install_path
 
         module_info.initialized = self.initialized
         return module_info
@@ -272,6 +318,147 @@ class PuppetfileModuleInfo(BaseModuleInfo):
         if 'default_branch' in data:
             module_info.default_branch = data['default_branch']
 
+        if 'exclude_spec' in data:
+            module_info.exclude_spec = data['exclude_spec']
+
+        if 'install_path' in data:
+            module_info.install_path = data['install_path']
+
+        return module_info
+
+    # -------------------------------------------------------------------------
+    @classmethod
+    def get_module_definitions(cls, mod_def, verbose=0):
+
+        if verbose > 3:
+            LOG.debug("Analyzing definitions from:\n{}".format(mod_def))
+        tokens = []
+        defs = {}
+
+        rest = mod_def
+        while not cls.re_empty.search(rest):
+            if verbose > 4:
+                LOG.debug("Current def rest: {!r}.".format(rest))
+
+            match = cls.re_def_token.search(rest)
+            if match:
+                token = match.group(1)
+                rest = cls.re_def_token.sub('', rest)
+                tokens.append(token)
+                continue
+
+            match = cls.re_key_val_pair_unquoted.search(rest)
+            if match:
+                token = match.group(1)
+                rest = cls.re_key_val_pair_unquoted.sub('', rest)
+                token = match.group(1)
+                continue
+
+            LOG.warn(_("Could not analyze definitions in {!r}.").format(rest))
+            break
+
+        if verbose > 4:
+            LOG.debug("Got def tokens:\n{}".format(pp(tokens)))
+
+        for token in tokens:
+            match = cls.re_key_val_pair.match(token)
+            if match:
+                key = match.group(1)
+                val = match.group(2)
+                defs[key] = val
+            else:
+                LOG.warn(_("Could not analyze definition token {!r}.").format(token))
+
+        if verbose > 4:
+            LOG.debug("Got definitions:\n{}".format(pp(defs)))
+
+        return defs
+
+    # -------------------------------------------------------------------------
+    @classmethod
+    def init_from_puppetfile_line(cls, line, env, appname=None, verbose=0, base_dir=None):
+
+        # Removing all newlines
+        mline = self.re_newline.sub(' ', line)
+
+        match = cls.re_mod_pf_line.search(mline)
+        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
+
+        match = cls.re_pf_line_version.search(mod_def)
+        if match:
+            module_info.repo_type = 'forge'
+            module_info.forge_version = match.group(1)
+        else:
+            definitions = cls.get_module_definitions(mod_def, verbose=verbose)
+
+            if 'type' in definitions:
+                module_info.repo_type = definitions['type']
+
+            if 'git' in definitions:
+                module_info.repo = definitions['git']
+                module_info.repo_type = 'git'
+
+            if 'svn' in definitions:
+                module_info.repo = definitions['svn']
+                module_info.repo_type = 'svn'
+
+            if 'local' in definitions:
+                if definitions['local']
+
+            if 'source' in definitions:
+                module_info.repo = definitions['source']
+
+            if 'tag' in definitions:
+                module_info.ref = definitions['tag']
+
+            if 'ref' in definitions:
+                module_info.ref = definitions['ref']
+
+            if 'branch' in definitions:
+                branch = definitions['branch']
+                if branch == ':control_branch':
+                    module_info.use_control_branch = True
+                else:
+                    module_info.ref = branch
+
+            if 'commit' in definitions:
+                module_info.ref = definitions['commit'}
+
+            if 'version' in definitions:
+                module_info.ref = definitions['version']
+
+            if 'default_branch' in definitions:
+                module_info.default_branch = definitions['default_branch']
+
+            if 'exclude_spec' in definitions:
+                module_info.exclude_spec = to_bool(definitions['exclude_spec'])
+
+            if 'install_path' in definitions:
+                module_info.install_path = definitions['install_path']
+
+
+        module_info.initialized = True
+
+        if verbose > 3:
+            LOG.debug("Initialized {c} object:\n{s}".format(
+                c=module_info.__class__.__name__, s=pp(module_info.as_dict())))
+
         return module_info