Check-in [87e5798b35]
Overview
| Comment: | Support for #depends: and #breaks:, and optionally bin:… and python:… checks. | 
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive | 
| Timelines: | family | ancestors | descendants | both | trunk | 
| Files: | files | file ages | folders | 
| SHA1: | 87e5798b35df481c1b8288b9b43732fb | 
| User & Date: | mario on 2017-01-02 20:48:09 | 
| Other Links: | manifest | tags | 
Context
| 2017-01-03 | ||
| 20:11 | Introduce statusbar_img and GenericChannel.warn() function; albeit it allows any stock icon to be used. (May introduce a generalized background/foreground color wrapping.) check-in: 8b13ba0189 user: mario tags: trunk | |
| 2017-01-02 | ||
| 20:48 | Support for #depends: and #breaks:, and optionally bin:… and python:… checks. check-in: 87e5798b35 user: mario tags: trunk | |
| 20:47 | Guard empty streams["common"] dict. check-in: 4cbc0911f6 user: mario tags: trunk | |
Changes
Modified pluginconf.py from [edb9d7acf4] to [8ae013bd93].
| 1 2 3 4 5 6 | # encoding: UTF-8 # api: python # type: handler # category: io # title: Plugin configuration # description: Read meta data, pyz/package contents, module locating | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # encoding: UTF-8 # api: python # type: handler # category: io # title: Plugin configuration # description: Read meta data, pyz/package contents, module locating # version: 0.6.8 # priority: core # docs: http://fossil.include-once.org/streamtuner2/wiki/plugin+meta+data # config: - # # Provides plugin lookup and meta data extraction utility functions. # It's used to abstract module+option management in applications. # For consolidating internal use and external/tool accessibility. | 
| ︙ | ︙ | |||
| 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | 
import sys
import os
import re
import pkgutil
import inspect
try:
    from compat2and3 import gzip_decode
except:
    from gzip import decompress as gzip_decode  # Py3 only
import zipfile
import argparse
 | > | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | 
import sys
import os
import re
import pkgutil
import inspect
from compat2and3 import find_executable
try:
    from compat2and3 import gzip_decode
except:
    from gzip import decompress as gzip_decode  # Py3 only
import zipfile
import argparse
 | 
| ︙ | ︙ | |||
| 416 417 418 419 420 421 422 | 
        for name in core:
            self.have[name] = plugin_meta(module=name, extra_base=["config"])
        # aliases
        for name, meta in self.have.items():
            if meta.get("alias"):
                for alias in re.split("\s*[,;]\s*", meta["alias"]):
                    self.have[alias] = self.have[name]
 | < < < < < < < < < < < < < | > > > > > > > > > | | > > | > | | | < | < > | > | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 | 
        for name in core:
            self.have[name] = plugin_meta(module=name, extra_base=["config"])
        # aliases
        for name, meta in self.have.items():
            if meta.get("alias"):
                for alias in re.split("\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, newpl):
        id = newpl.get("$name", "__invalid")
        have_ver = self.have.get(id, {}).get("version", "0")
        if id.find("__") == 0:
            pass
        elif newpl.get("api") not in ("python", "streamtuner2"):
            pass
        elif set((newpl.get("status"), newpl.get("priority"))).intersection(set(("obsolete", "broken"))):
            pass
        elif have_ver >= newpl.get("version", "0.0"):
            pass
        else:
            return True
    # Verify depends: and breaks: against existing plugins/modules
    def depends(self, plugin):
        r = True
        if plugin.get("depends"):
            r &= self.and_or(self.split(plugin["depends"]), self.have)
        if plugin.get("breaks"):
            r &= self.neither(self.split(plugin["breaks"]), self.have)
        return r
    # Split trivial "pkg | alt, mod >= 1, uikit < 4.0" string into nested list [[dep],[alt,alt],[dep]]
    def split(self, dep_str):
        dep_cmp = []
        for alt_str in re.split(r"\s*[,;]+\s*", dep_str):
            alt_cmp = []
            # split alternatives |
            for part in re.split(r"\s*\|+\s*", alt_str):
                # skip deb:pkg-name, rpm:name, bin:name etc.
                if not len(part):
                    continue
                if part.find(":") >= 0:
                    self.have[part] = { "version": self.module_test(*part.split(":")) }
                # find comparison and version num
                part += " >= 0"
                m = re.search(r"([\w.:-]+)\s*\(?\s*([>=<!~]+)\s*([\d.]+([-~.]\w+)*)", part)
                if m and m.group(2):
                    alt_cmp.append([m.group(i) for i in (1, 2, 3)])
            if alt_cmp:
                dep_cmp.append(alt_cmp)
        return dep_cmp
    # Single comparison
    def cmp(self, d, have, absent=True):
        name, op, ver = d
        # absent=True is the relaxed check, will ignore unknown plugins // set absent=False or None for strict check (as in breaks: rule e.g.)
        if not have.get(name, {}).get("version"):
            return absent
        # curr = installed version
        curr = have[name]["version"]
        tbl = {
            ">=": curr >= ver,
            "<=": curr <= ver,
            "==": curr == ver,
            ">":  curr > ver,
            "<":  curr < ver,
            "!=": curr != ver,
        }
        r = tbl.get(op, True)
        #print "log.VERSION_COMPARE: ", name, " → (", curr, op, ver, ") == ", r
        return r
    # Compare nested structure of [[dep],[alt,alt]]
    def and_or(self, deps, have, r = True):
        #print deps
        return not False in [True in [self.cmp(d, have) for d in alternatives] for alternatives in deps]
    # Breaks/Conflicts: check [[or],[or]]
    def neither(self, deps, have):
        return not True in [self.cmp(d, have, absent=None) for cnd in deps for d in cnd]
    # Resolves/injects complex "bin:name" or "python:name" dependency URNs
    def module_test(self, type, name):
        return "1"  # disabled for now
        if "_" + type in dir(self):
            return "1" if bool(getattr(self, "_" + type)(name)) else "-1"
    # `bin:name` lookup
    def _bin(self, name):
        return find_executable(name)
    # `python:module` test
    def _python(self, name):
        return __import__("imp").find_module(name) is not None
# Add plugin defaults to conf.* store
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Utility function which applies plugin meta data to a config
# store. Which in the case of streamtuner2 is really just a
# dictionary `conf{}` and a plugin list in `conf.plugins{}`.
#
 | 
| ︙ | ︙ |