PGMR: More general flexibility for os compat check
* Don't restrict the list of compatibility values to check against
to only those we have mapped, also support unmapped more exotic
ones.
* Allow 1:1 check against sys.platform values (with startswith).
Combined with the above that allows very granular compatibility
modelling ("freebsd11", "freebsd12") if required.
* Instead of only whitelisting ("linux", "freebsd") now also black
listing is possible ("!windows").
A detected os must match all provided whitelist elements (if the
whitelist is empty that is considered always the case) and none of
the backlist elements (if the blacklist is empty that is also
considered always the case).
See the included unit tests for examples of how this works.
This commit is contained in:
parent
956d9581c5
commit
346f818707
5 changed files with 101 additions and 8 deletions
|
|
@ -571,6 +571,10 @@ class PluginManager(object):
|
|||
key = entry.name
|
||||
elif entry.is_file() and entry.name.endswith(".py"):
|
||||
key = entry.name[:-3] # strip off the .py extension
|
||||
if key.startswith("__"):
|
||||
# might be an __init__.py in our plugins folder, or something else we don't want
|
||||
# to handle
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
|
||||
|
|
|
|||
1
src/octoprint/plugins/__init__.py
Normal file
1
src/octoprint/plugins/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
# make our plugins testable
|
||||
|
|
@ -808,20 +808,37 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
|
||||
return True
|
||||
|
||||
def _is_os_compatible(self, current_os, compatibility_entries):
|
||||
@staticmethod
|
||||
def _is_os_compatible(current_os, compatibility_entries):
|
||||
"""
|
||||
Tests if the ``current_os`` or ``sys.platform`` matches any of the provided ``compatibility_entries``.
|
||||
Tests if the ``current_os`` or ``sys.platform`` are blacklisted or whitelisted in ``compatibility_entries``
|
||||
"""
|
||||
general_match = current_os in filter(lambda x: x in self.__class__.OPERATING_SYSTEMS.keys(), compatibility_entries)
|
||||
exact_match = sys.platform in compatibility_entries
|
||||
return general_match or exact_match
|
||||
if len(compatibility_entries) == 0:
|
||||
# shortcut - no compatibility info means we are compatible
|
||||
return True
|
||||
|
||||
def _get_os(self):
|
||||
for identifier, platforms in self.__class__.OPERATING_SYSTEMS.items():
|
||||
negative_entries = map(lambda x: x[1:], filter(lambda x: x.startswith("!"), compatibility_entries))
|
||||
positive_entries = filter(lambda x: not x.startswith("!"), compatibility_entries)
|
||||
|
||||
negative_match = False
|
||||
if negative_entries:
|
||||
# check if we are blacklisted
|
||||
negative_match = current_os in negative_entries or any(map(lambda x: sys.platform.startswith(x), negative_entries))
|
||||
|
||||
positive_match = True
|
||||
if positive_entries:
|
||||
# check if we are whitelisted
|
||||
positive_match = current_os in positive_entries or any(map(lambda x: sys.platform.startswith(x), positive_entries))
|
||||
|
||||
return positive_match and not negative_match
|
||||
|
||||
@classmethod
|
||||
def _get_os(cls):
|
||||
for identifier, platforms in cls.OPERATING_SYSTEMS.items():
|
||||
if (callable(platforms) and platforms(sys.platform)) or (isinstance(platforms, list) and sys.platform in platforms):
|
||||
return identifier
|
||||
else:
|
||||
return "unknown"
|
||||
return "unmapped"
|
||||
|
||||
def _get_octoprint_version_string(self):
|
||||
return VERSION
|
||||
|
|
|
|||
10
tests/plugins/__init__.py
Normal file
10
tests/plugins/__init__.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# coding=utf-8
|
||||
"""
|
||||
Unit tests for bundled plugins.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
__author__ = "Gina Häußge <osd@foosel.net>"
|
||||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||
__copyright__ = "Copyright (C) 2017 The OctoPrint Project - Released under terms of the AGPLv3 License"
|
||||
61
tests/plugins/test_pluginmanager.py
Normal file
61
tests/plugins/test_pluginmanager.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# coding=utf-8
|
||||
"""
|
||||
Unit tests for bundled plugin "PluginManager".
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
__author__ = "Gina Häußge <osd@foosel.net>"
|
||||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||
__copyright__ = "Copyright (C) 2017 The OctoPrint Project - Released under terms of the AGPLv3 License"
|
||||
|
||||
import unittest
|
||||
import mock
|
||||
import ddt
|
||||
|
||||
from octoprint.plugins.pluginmanager import PluginManagerPlugin
|
||||
|
||||
@ddt.ddt
|
||||
class PluginManagerPluginTests(unittest.TestCase):
|
||||
|
||||
@ddt.data(
|
||||
("linux", "linux2", [], True),
|
||||
("linux", "linux2", ["linux", "freebsd"], True),
|
||||
("windows", "win32", ["linux", "freebsd"], False),
|
||||
("linux", "linux2", ["!windows"], True),
|
||||
("windows", "win32", ["!windows"], False),
|
||||
("unmapped", "os2", [], True),
|
||||
("unmapped", "os2", ["linux", "freebsd"], False),
|
||||
("unmapped", "os2", ["!os2"], False),
|
||||
("unmapped", "sunos5", ["linux", "freebsd", "sunos"], True),
|
||||
("unmapped", "sunos5", ["!sunos", "!os2"], False),
|
||||
|
||||
# both black and white listing at the same time usually doesn't
|
||||
# make a whole lot of sense, but let's test it anyhow
|
||||
("linux", "linux2", ["!windows", "linux", "freebsd"], True),
|
||||
("linux", "linux2", ["!windows", "freebsd"], False),
|
||||
("windows", "win32", ["!windows", "linux", "freebsd"], False),
|
||||
("unmapped", "sunos5", ["!windows", "linux", "freebsd"], False)
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_is_os_compatible(self, current_os, sys_platform, entries, expected):
|
||||
with mock.patch("sys.platform", sys_platform):
|
||||
actual = PluginManagerPlugin._is_os_compatible(current_os, entries)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@ddt.data(
|
||||
("win32", "windows"),
|
||||
("linux2", "linux"),
|
||||
("darwin", "macos"),
|
||||
("linux", "linux"),
|
||||
("linux3", "linux"),
|
||||
("freebsd", "freebsd"),
|
||||
("freebsd2342", "freebsd"),
|
||||
("os2", "unmapped"),
|
||||
("sunos5", "unmapped")
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_get_os(self, sys_platform, expected):
|
||||
with mock.patch("sys.platform", sys_platform):
|
||||
actual = PluginManagerPlugin._get_os()
|
||||
self.assertEqual(actual, expected)
|
||||
Loading…
Reference in a new issue