Coverage for r11k/puppetmodule/base.py: 82%
27 statements
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-13 23:29 +0100
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-13 23:29 +0100
1"""
2Abstract base class for Puppet module sources.
4Puppet modules can come from many places. Here we provide a common
5interface for how the rest of the program should be able to interact
6with them. A few implementation parts are here, for things that will
7be common among almost all module providers.
8"""
10from typing import (
11 Any,
12 Optional,
13)
14from semver import VersionInfo
15from r11k.puppet import PuppetMetadata
16import r11k.config
19class PuppetModule:
20 r"""
21 Abstract base class for all puppet modules.
23 Each implementation *must* implement the following:
24 - `_fetch_metadata`
25 - `publish`
26 - `versions`
28 ##### Protected fields
29 ###### `_fetch_metadata`
30 A method which retrieves the metadata from *somewhere*. The
31 property `metadata` by default caches this information.
33 :param name: Name of the module. Further meaning depends on the
34 implementation.
35 :param version: Version to use. Valid values depend on the
36 implementation.
37 :param config: Runtime configuration which may be used by
38 implementations to aid them in retrieving a module.
39 """
41 # pragma: no cover
42 def __init__(self,
43 name: str,
44 *,
45 version: Optional[str] = None,
46 config: r11k.config.Config = r11k.config.config):
47 self.name = name
48 self._og_name = name
49 self.version: Optional[str] = version
50 self._metadata: Optional[PuppetMetadata] = None
51 self.config = config
52 self.explicit: bool = False
54 @property
55 def metadata(self) -> PuppetMetadata:
56 """
57 Property containing the modules metadata.
59 The metadata almost always needs to be fetched from an
60 external source. Each implementation must implement
61 `_fetch_metadata` which solves this, while this property
62 ensures that `_fetch_metadata` is only called once.
63 """
64 if not self._metadata:
65 self._metadata = self._fetch_metadata()
66 return self._metadata
68 def _fetch_metadata(self) -> PuppetMetadata: # pragma: no cover
69 """Fetch metadata for a given module."""
70 raise NotImplementedError()
72 def publish(self, path: str) -> None: # pragma: no cover
73 """
74 Publish this module to the given path.
76 [Parameters]
77 path - absolute path to modules own directory, for example:
78 /etc/puppetlabs/code/environments/{env_name}/modules/{module_name}
80 :raises: `NotImplementedError`
81 """
82 raise NotImplementedError()
84 def versions(self) -> list[VersionInfo]: # pragma: no cover
85 """
86 List available versions of this module.
88 :raises: `NotImplementedError`
89 """
90 raise NotImplementedError()
92 def latest(self) -> VersionInfo:
93 """Return the latest available version."""
94 return max(self.versions())
96 @property
97 def module_path(self) -> str:
98 """Where module is located in file system."""
99 parts = self.name.split('-', 1)
100 if len(parts) == 1:
101 return parts[0]
102 else:
103 return parts[1]
105 def serialize(self) -> dict[str, Any]:
106 """
107 Serialize back into form from puppetfile.yaml.
109 Includes name, and version if set.
110 """
111 return {
112 'name': self.name,
113 **({'version': self.version}
114 if self.version else {})
115 }
117 def __repr__(self) -> str: # pragma: no cover
118 return f"PuppetModule('{self.name}', '{self.version}')"