| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- import logging
- from pathlib import Path
- import ap_git
- from utils import TaskRunner
- from metadata_manager.versions_manager.models import RemoteInfo, VersionInfo
- from metadata_manager.versions_manager.providers import (
- VersionsProvider,
- build_default_providers,
- )
- from metadata_manager.vehicles_manager import VehiclesManager as vehm
- REMOTES_SCHEMA_PATH = Path(__file__).resolve().parent.parent / "remotes.schema.json"
- def _release_type_dedup_priority(release_type: str) -> int:
- """Lower value wins when multiple releases share the same version_id."""
- match release_type:
- case "stable":
- return 0
- case "beta":
- return 1
- case "latest":
- return 2
- case "tag":
- return 3
- case _:
- return 99
- class VersionsManager:
- """
- Version manager merges version metadata from different pluggable providers.
- """
- __singleton = None
- def __init__(
- self,
- ap_repo: ap_git.GitRepo,
- remotes_json_path: str,
- manifest_json=None,
- providers: list[VersionsProvider] | None = None,
- ):
- if vehm.get_singleton() is None:
- raise RuntimeError("VehiclesManager should be initialised first")
- if VersionsManager.__singleton:
- raise RuntimeError("VersionsManager must be a singleton.")
- self.logger = logging.getLogger(__name__)
- if providers is None:
- if manifest_json is None:
- raise ValueError("manifest_json is required when providers is omitted")
- providers = build_default_providers(
- manifest_json=manifest_json,
- remotes_json_path=remotes_json_path,
- schema_path=str(REMOTES_SCHEMA_PATH),
- )
- self._providers = providers
- self.repo = ap_repo
- self._remotes_json_path = remotes_json_path
- self.__task__runner = TaskRunner(tasks=((self.refresh_all, 1200),))
- VersionsManager.__singleton = self
- def start(self) -> None:
- self.logger.info("Starting VersionsManager background refresh jobs.")
- self.__task__runner.start()
- def stop(self) -> None:
- self.logger.info("Stopping VersionsManager background refresh jobs.")
- self.__task__runner.stop()
- def refresh_all(self) -> None:
- for provider in self._providers:
- try:
- provider.refresh()
- except Exception as exc:
- self.logger.error(
- "Provider %s refresh failed: %s", provider.name, exc
- )
- self._sync_remotes_with_ap_repo()
- def get_all_remotes_info(self) -> list[RemoteInfo]:
- remotes = {}
- for provider in self._providers:
- for remote in provider.get_remotes():
- remotes[remote.name] = remote
- return list(remotes.values())
- def get_remote_info(self, remote_name: str) -> RemoteInfo | None:
- return next(
- (remote for remote in self.get_all_remotes_info()
- if remote.name == remote_name),
- None,
- )
- def get_versions_for_vehicle(self, vehicle_id: str) -> list[VersionInfo]:
- if vehicle_id is None:
- raise ValueError("Vehicle ID is a required parameter.")
- vehicle = vehm.get_singleton().get_vehicle_by_id(vehicle_id)
- if vehicle is None:
- raise ValueError(f"Invalid vehicle ID '{vehicle_id}'.")
- by_version_id: dict[str, VersionInfo] = {}
- for provider in self._providers:
- for version in provider.get_versions(vehicle_id):
- existing = by_version_id.get(version.version_id)
- if existing is None:
- by_version_id[version.version_id] = version
- continue
- if _release_type_dedup_priority(version.release_type) < (
- _release_type_dedup_priority(existing.release_type)
- ):
- by_version_id[version.version_id] = version
- return list(by_version_id.values())
- def is_version_listed(self, vehicle_id: str, version_id: str) -> bool:
- if vehicle_id is None:
- raise ValueError("vehicle_id is a required parameter.")
- if version_id is None:
- raise ValueError("version_id is a required parameter.")
- return version_id in [
- version.version_id
- for version in self.get_versions_for_vehicle(vehicle_id=vehicle_id)
- ]
- def get_version_info(self, vehicle_id: str, version_id: str) -> VersionInfo | None:
- return next(
- (
- version
- for version in self.get_versions_for_vehicle(vehicle_id=vehicle_id)
- if version.version_id == version_id
- ),
- None,
- )
- def _sync_remotes_with_ap_repo(self) -> None:
- remotes = tuple(
- (remote.name, remote.url)
- for remote in self.get_all_remotes_info()
- )
- if remotes:
- self.repo.remote_add_bulk(remotes=remotes, force=True)
- @staticmethod
- def get_singleton():
- return VersionsManager.__singleton
|