Source code for bandersnatch.filter
"""
Blacklist management
"""
from collections import defaultdict
from typing import Any, Dict, Iterable, List
import pkg_resources
from .configuration import BandersnatchConfig
# The API_REVISION is incremented if the plugin class is modified in a
# backwards incompatible way. In order to prevent loading older
# broken plugins that may be installed and will break due to changes to
# the methods of the classes.
PLUGIN_API_REVISION = 2
PROJECT_PLUGIN_RESOURCE = f"bandersnatch_filter_plugins.v{PLUGIN_API_REVISION}.project"
METADATA_PLUGIN_RESOURCE = (
f"bandersnatch_filter_plugins.v{PLUGIN_API_REVISION}.metadata"
)
RELEASE_PLUGIN_RESOURCE = f"bandersnatch_filter_plugins.v{PLUGIN_API_REVISION}.release"
RELEASE_FILE_PLUGIN_RESOURCE = (
f"bandersnatch_filter_plugins.v{PLUGIN_API_REVISION}.release_file"
)
loaded_filter_plugins: Dict[str, List["Filter"]] = defaultdict(list)
[docs]class Filter:
"""
Base Filter class
"""
name = "filter"
def __init__(self, *args: Any, **kwargs: Any) -> None:
self.configuration = BandersnatchConfig().config
if (
"plugins" not in self.configuration
or "enabled" not in self.configuration["plugins"]
):
return
split_plugins = self.configuration["plugins"]["enabled"].split("\n")
if "all" not in split_plugins and self.name not in split_plugins:
return
self.initialize_plugin()
[docs] def initialize_plugin(self) -> None:
"""
Code to initialize the plugin
"""
# The intialize_plugin method is run once to initialize the plugin. This should
# contain all code to set up the plugin.
# This method is not run in the fast path and should be used to do things like
# indexing filter databases, etc that will speed the operation of the filter
# and check_match methods that are called in the fast path.
pass
[docs] def filter(self, metadata: dict) -> bool:
"""
Check if the plugin matches based on the package's metadata.
Returns
=======
bool:
True if the values match a filter rule, False otherwise
"""
return False
[docs] def check_match(self, **kwargs: Any) -> bool:
"""
Check if the plugin matches based on the arguments provides.
Returns
=======
bool:
True if the values match a filter rule, False otherwise
"""
return False
[docs]class FilterProjectPlugin(Filter):
"""
Plugin that blocks sync operations for an entire project
"""
name = "project_plugin"
[docs]class FilterReleasePlugin(Filter):
"""
Plugin that modify the download of specific release or dist files
"""
name = "release_plugin"
[docs]class FilterReleaseFilePlugin(Filter):
"""
Plugin that modify the download of specific release or dist files
"""
name = "release_file_plugin"
[docs]def load_filter_plugins(entrypoint_group: str) -> Iterable[Filter]:
"""
Load all blacklist plugins that are registered with importlib.resources
Parameters
==========
entrypoint_group: str
The entrypoint group name to load plugins from
Returns
=======
List of Blacklist:
A list of objects derived from the Blacklist class
"""
global loaded_filter_plugins
enabled_plugins: List[str] = []
config = BandersnatchConfig().config
try:
config_blacklist_plugins = config["plugins"]["enabled"]
split_plugins = config_blacklist_plugins.split("\n")
if "all" in split_plugins:
enabled_plugins = ["all"]
else:
for plugin in split_plugins:
if not plugin:
continue
enabled_plugins.append(plugin)
except KeyError:
pass
# If the plugins for the entrypoint_group have been loaded return them
cached_plugins = loaded_filter_plugins.get(entrypoint_group)
if cached_plugins:
return cached_plugins
plugins = set()
for entry_point in pkg_resources.iter_entry_points(group=entrypoint_group):
plugin_class = entry_point.load()
plugin_instance = plugin_class()
if "all" in enabled_plugins or plugin_instance.name in enabled_plugins:
plugins.add(plugin_instance)
loaded_filter_plugins[entrypoint_group] = list(plugins)
return plugins
[docs]def filter_project_plugins() -> Iterable[Filter]:
"""
Load and return the release filtering plugin objects
Returns
-------
list of bandersnatch.filter.Filter:
List of objects derived from the bandersnatch.filter.Filter class
"""
return load_filter_plugins(PROJECT_PLUGIN_RESOURCE)
[docs]def filter_release_plugins() -> Iterable[Filter]:
"""
Load and return the release filtering plugin objects
Returns
-------
list of bandersnatch.filter.Filter:
List of objects derived from the bandersnatch.filter.Filter class
"""
return load_filter_plugins(RELEASE_PLUGIN_RESOURCE)
[docs]def filter_release_file_plugins() -> Iterable[Filter]:
"""
Load and return the release file filtering plugin objects
Returns
-------
list of bandersnatch.filter.Filter:
List of objects derived from the bandersnatch.filter.Filter class
"""
return load_filter_plugins(RELEASE_FILE_PLUGIN_RESOURCE)