17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
+
+
|
# DependencyValidation().depends()/.valid()
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Probes a new plugins` depends: list against installed base modules.
# Utilizes each version: fields and allows for virtual modules, or
# alternatives and honors alias: names.
#
""" Dependency validation and consistency checker for updates """
import sys
import re
import pluginconf
try:
from distutils.spawn import find_executable
except ImportError:
|
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
# Minimal depends: probing
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
class DependencyValidation(object):
"""
Now this definitely requires customization. Each plugin can carry
a list of (soft-) dependency names.
# depends: config, appcore >= 2.0, bin:wkhtmltoimage, python < 3.5
\# depends: config, appcore >= 2.0, bin:wkhtmltoimage, python < 3.5
Here only in-application modules are honored, system references
ignored. Unknown plugin names are also skipped. A real install
helper might want to auto-tick them on, etc. This example is just
meant for probing downloadable plugins.
The .valid() helper only asserts the api: string, or skips existing
modules, and if they're more recent.
While .depends() compares minimum versions against existing modules.
In practice there's little need for full-blown dependency resolving
for application-level modules.
Attributes
----------
api : list
allowed api: identifiers for .valid() stream checks
log : logging
warning handler
have : dict
accumulated list of existing/virtual plugins
"""
""" supported APIs """
api = ["python", "streamtuner2"]
""" debugging """
log = logging.getLogger("pluginconf.dependency")
# prepare list of known plugins and versions
def __init__(self, add={}, core=["st2", "uikit", "config", "action"]):
"""
Parameters
----------
add : dict
name to pmd list of existing/core/virtual plugins (can define
versions or own dependencies)
core : list
name list of virtual plugins
"""
self.have = {
"python": {"version": sys.version}
}
# inject virtual modules
for name, meta in add.items():
if isinstance(meta, bool):
|
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
+
+
|
if meta.get("alias"):
for alias in re.split(r"\s*[,;]\s*", meta["alias"]):
self.have[alias] = self.have[name]
# basic plugin pre-screening (skip __init__, filter by api:,
# exclude installed & same-version plugins)
def valid(self, new_plugin):
""" check plugin info from repository stream (fields there $name, $file, $dist, api, id, depends, etc) """
if not "$name" in new_plugin:
self.log.warning(".valid() checks online plugin lists, requires $name")
id = new_plugin.get("$name", "__invalid")
have_ver = self.have.get(id, {}).get("version", "0")
if id.find("__") == 0:
self.log.debug("wrong/no id")
elif new_plugin.get("api") not in self.api:
self.log.debug("not in allowed APIs")
elif {new_plugin.get("status"), new_plugin.get("priority")} & {"obsolete", "broken"}:
self.log.debug("wrong status (obsolete/broken)")
elif have_ver >= new_plugin.get("version", "0.0"):
self.log.debug("newer version already installed")
else:
return True
# Verify depends: and breaks: against existing plugins/modules
def depends(self, plugin):
""" test depends: and breaks: """
result = True
if plugin.get("depends"):
result &= self.and_or(self.split(plugin["depends"]), self.have)
if plugin.get("breaks"):
result &= self.neither(self.split(plugin["breaks"]), self.have)
self.log.debug("plugin '%s' matching requirements: %i", plugin["id"], result)
return result
|