- import re
-
- from configs import dify_config
- from core.helper import marketplace
- from core.plugin.entities.plugin import PluginDependency, PluginInstallationSource
- from core.plugin.impl.plugin import PluginInstaller
- from models.provider_ids import ModelProviderID, ToolProviderID
-
- # Compile regex pattern for version extraction at module level for better performance
- _VERSION_REGEX = re.compile(r":(?P<version>[0-9]+(?:\.[0-9]+){2}(?:[+-][0-9A-Za-z.-]+)?)(?:@|$)")
-
-
- class DependenciesAnalysisService:
- @classmethod
- def analyze_tool_dependency(cls, tool_id: str) -> str:
- """
- Analyze the dependency of a tool.
-
- Convert the tool id to the plugin_id
- """
- try:
- return ToolProviderID(tool_id).plugin_id
- except Exception as e:
- raise e
-
- @classmethod
- def analyze_model_provider_dependency(cls, model_provider_id: str) -> str:
- """
- Analyze the dependency of a model provider.
-
- Convert the model provider id to the plugin_id
- """
- try:
- return ModelProviderID(model_provider_id).plugin_id
- except Exception as e:
- raise e
-
- @classmethod
- def get_leaked_dependencies(cls, tenant_id: str, dependencies: list[PluginDependency]) -> list[PluginDependency]:
- """
- Check dependencies, returns the leaked dependencies in current workspace
- """
- required_plugin_unique_identifiers = []
- for dependency in dependencies:
- required_plugin_unique_identifiers.append(dependency.value.plugin_unique_identifier)
-
- manager = PluginInstaller()
-
- # get leaked dependencies
- missing_plugins = manager.fetch_missing_dependencies(tenant_id, required_plugin_unique_identifiers)
- missing_plugin_unique_identifiers = {plugin.plugin_unique_identifier: plugin for plugin in missing_plugins}
-
- leaked_dependencies = []
- for dependency in dependencies:
- unique_identifier = dependency.value.plugin_unique_identifier
- if unique_identifier in missing_plugin_unique_identifiers:
- # Extract version for Marketplace dependencies
- if dependency.type == PluginDependency.Type.Marketplace:
- version_match = _VERSION_REGEX.search(unique_identifier)
- if version_match:
- dependency.value.version = version_match.group("version")
-
- # Create and append the dependency (same for all types)
- leaked_dependencies.append(
- PluginDependency(
- type=dependency.type,
- value=dependency.value,
- current_identifier=missing_plugin_unique_identifiers[unique_identifier].current_identifier,
- )
- )
-
- return leaked_dependencies
-
- @classmethod
- def generate_dependencies(cls, tenant_id: str, dependencies: list[str]) -> list[PluginDependency]:
- """
- Generate dependencies through the list of plugin ids
- """
- dependencies = list(set(dependencies))
- manager = PluginInstaller()
- plugins = manager.fetch_plugin_installation_by_ids(tenant_id, dependencies)
- result = []
- for plugin in plugins:
- if plugin.source == PluginInstallationSource.Github:
- result.append(
- PluginDependency(
- type=PluginDependency.Type.Github,
- value=PluginDependency.Github(
- repo=plugin.meta["repo"],
- version=plugin.meta["version"],
- package=plugin.meta["package"],
- github_plugin_unique_identifier=plugin.plugin_unique_identifier,
- ),
- )
- )
- elif plugin.source == PluginInstallationSource.Marketplace:
- result.append(
- PluginDependency(
- type=PluginDependency.Type.Marketplace,
- value=PluginDependency.Marketplace(
- marketplace_plugin_unique_identifier=plugin.plugin_unique_identifier
- ),
- )
- )
- elif plugin.source == PluginInstallationSource.Package:
- result.append(
- PluginDependency(
- type=PluginDependency.Type.Package,
- value=PluginDependency.Package(plugin_unique_identifier=plugin.plugin_unique_identifier),
- )
- )
- elif plugin.source == PluginInstallationSource.Remote:
- raise ValueError(
- f"You used a remote plugin: {plugin.plugin_unique_identifier} in the app, please remove it first"
- " if you want to export the DSL."
- )
- else:
- raise ValueError(f"Unknown plugin source: {plugin.source}")
-
- return result
-
- @classmethod
- def generate_latest_dependencies(cls, dependencies: list[str]) -> list[PluginDependency]:
- """
- Generate the latest version of dependencies
- """
- dependencies = list(set(dependencies))
- if not dify_config.MARKETPLACE_ENABLED:
- return []
- deps = marketplace.batch_fetch_plugin_manifests(dependencies)
- return [
- PluginDependency(
- type=PluginDependency.Type.Marketplace,
- value=PluginDependency.Marketplace(marketplace_plugin_unique_identifier=dep.latest_package_identifier),
- )
- for dep in deps
- ]
|