CuraPackageManager.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. import os
  4. from typing import Any, cast, Dict, List, Set, Tuple, TYPE_CHECKING, Optional
  5. from UM.Logger import Logger
  6. from UM.PluginRegistry import PluginRegistry
  7. from cura.CuraApplication import CuraApplication # To find some resource types.
  8. from cura.Settings.GlobalStack import GlobalStack
  9. from UM.PackageManager import PackageManager # The class we're extending.
  10. from UM.Resources import Resources # To find storage paths for some resource types.
  11. from UM.i18n import i18nCatalog
  12. catalog = i18nCatalog("cura")
  13. if TYPE_CHECKING:
  14. from UM.Qt.QtApplication import QtApplication
  15. from PyQt6.QtCore import QObject
  16. class CuraPackageManager(PackageManager):
  17. def __init__(self, application: "QtApplication", parent: Optional["QObject"] = None) -> None:
  18. super().__init__(application, parent)
  19. self._local_packages: Optional[List[Dict[str, Any]]] = None
  20. self._local_packages_ids: Optional[Set[str]] = None
  21. self.installedPackagesChanged.connect(self._updateLocalPackages)
  22. def _updateLocalPackages(self) -> None:
  23. self._local_packages = self.getAllLocalPackages()
  24. self._local_packages_ids = set(pkg["package_id"] for pkg in self._local_packages)
  25. @property
  26. def local_packages(self) -> List[Dict[str, Any]]:
  27. """locally installed packages, lazy execution"""
  28. if self._local_packages is None:
  29. self._updateLocalPackages()
  30. # _updateLocalPackages always results in a list of packages, not None.
  31. # It's guaranteed to be a list now.
  32. return cast(List[Dict[str, Any]], self._local_packages)
  33. @property
  34. def local_packages_ids(self) -> Set[str]:
  35. """locally installed packages, lazy execution"""
  36. if self._local_packages_ids is None:
  37. self._updateLocalPackages()
  38. # _updateLocalPackages always results in a list of packages, not None.
  39. # It's guaranteed to be a list now.
  40. return cast(Set[str], self._local_packages_ids)
  41. def initialize(self) -> None:
  42. self._installation_dirs_dict["materials"] = Resources.getStoragePath(CuraApplication.ResourceTypes.MaterialInstanceContainer)
  43. self._installation_dirs_dict["qualities"] = Resources.getStoragePath(CuraApplication.ResourceTypes.QualityInstanceContainer)
  44. super().initialize()
  45. def getMaterialFilePackageId(self, file_name: str, guid: str) -> str:
  46. """Get the id of the installed material package that contains file_name"""
  47. for material_package in [f for f in os.scandir(self._installation_dirs_dict["materials"]) if f.is_dir()]:
  48. package_id = material_package.name
  49. for root, _, file_names in os.walk(material_package.path):
  50. if file_name not in file_names:
  51. # File with the name we are looking for is not in this directory
  52. continue
  53. with open(root + "/" + file_name, encoding="utf-8") as f:
  54. # Make sure the file we found has the same guid as our material
  55. # Parsing this xml would be better but the namespace is needed to search it.
  56. parsed_guid = PluginRegistry.getInstance().getPluginObject("XmlMaterialProfile").getMetadataFromSerialized(
  57. f.read(), "GUID")
  58. if guid == parsed_guid:
  59. return package_id
  60. Logger.error("Could not find package_id for file: {} with GUID: {} ".format(file_name, guid))
  61. return ""
  62. def getMachinesUsingPackage(self, package_id: str) -> Tuple[List[Tuple[GlobalStack, str, str]], List[Tuple[GlobalStack, str, str]]]:
  63. """Returns a list of where the package is used
  64. It loops through all the package contents and see if some of the ids are used.
  65. :param package_id: package id to search for
  66. :return: empty if it is never used, otherwise a list consisting of 3-tuples
  67. """
  68. ids = self.getPackageContainerIds(package_id)
  69. container_stacks = self._application.getContainerRegistry().findContainerStacks()
  70. global_stacks = [container_stack for container_stack in container_stacks if isinstance(container_stack, GlobalStack)]
  71. machine_with_materials = []
  72. machine_with_qualities = []
  73. for container_id in ids:
  74. for global_stack in global_stacks:
  75. for extruder_nr, extruder_stack in enumerate(global_stack.extruderList):
  76. if container_id in (extruder_stack.material.getId(), extruder_stack.material.getMetaData().get("base_file")):
  77. machine_with_materials.append((global_stack, str(extruder_nr), container_id))
  78. if container_id == extruder_stack.quality.getId():
  79. machine_with_qualities.append((global_stack, str(extruder_nr), container_id))
  80. return machine_with_materials, machine_with_qualities
  81. def getAllLocalPackages(self) -> List[Dict[str, Any]]:
  82. """ Returns an unordered list of all the package_info of installed, to be installed, or bundled packages"""
  83. packages: List[Dict[str, Any]] = []
  84. for packages_to_add in self.getAllInstalledPackagesInfo().values():
  85. packages.extend(packages_to_add)
  86. return packages