CuraPackageManager.py 5.1 KB

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