Differences From Artifact [1d2be7d94e]:

To Artifact [6e210a4c05]:


17
18
19
20
21
22
23


24
25
26
27
28
29
30
# 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.
#




import sys
import re
import pluginconf
try:
    from distutils.spawn import find_executable
except ImportError:







>
>







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
# 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

    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.









    """
    
    """ 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"]):









        self.have = {
            "python": {"version": sys.version}
        }

        # inject virtual modules
        for name, meta in add.items():
            if isinstance(meta, bool):







|












>
>
>
>
>
>
>
>
>










>
>
>
>
>
>
>
>
>







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

    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
            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):

        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):

        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







>

















>







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