erm_json_lite.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import json
  2. import re
  3. from functools import cmp_to_key
  4. from .semver import Version, VersionRange
  5. class ErmJsonLite(object):
  6. """
  7. Basic implementation to read `erm-packages.json`.
  8. It doesn't use any models, works with only raw JSON types: lists, dicts, strings
  9. """
  10. class ResourceType(object):
  11. NPM_PACKAGE = "NPM_PACKAGE"
  12. NODE_JS = "NODE_JS"
  13. data = None
  14. @staticmethod
  15. def get_versions_of(er_resource):
  16. # type: (dict) -> list[Version]
  17. """
  18. Return all versions of the resource in ASC order (from older to latest)
  19. """
  20. unsorted = er_resource.get("versions").keys()
  21. # We have to sort because in python 2 the order of keys in a dict is not guaranteed
  22. versions = sorted(unsorted, key=cmp_to_key(Version.cmp))
  23. return [Version.from_str(v) for v in versions]
  24. @classmethod
  25. def load(cls, path):
  26. # type: (str) -> ErmJsonLite
  27. erm_json = cls()
  28. with open(path, encoding='utf-8') as f:
  29. erm_json.data = dict()
  30. for k, v in json.load(f).items():
  31. # Ignore comments (when key starts with `_`), used for banner
  32. if not k.startswith("_"):
  33. erm_json.data[k] = v
  34. return erm_json
  35. @staticmethod
  36. def canonize_name(resource_name):
  37. # type: (str) -> str
  38. """
  39. Canonize resource name
  40. For example:
  41. hermione -> hermione
  42. super-package -> super_package
  43. @yatool/nots -> yatool_nots
  44. """
  45. return re.sub(r"\W+", "_", resource_name).strip("_")
  46. def get_resource(self, resource_name):
  47. # type: (str) -> dict
  48. """
  49. Return resource by his name
  50. """
  51. er_resource = self.data.get(resource_name)
  52. if not er_resource:
  53. raise Exception("Requested resource {} is not a toolchain item".format(resource_name))
  54. return er_resource
  55. def get_sb_resources(self, resource_name, version):
  56. # type: (str, Version) -> list[dict]
  57. """
  58. Return a list of SB resources for ER version
  59. """
  60. er_resource = self.get_resource(resource_name)
  61. return er_resource.get("versions").get(str(version)).get("resources")
  62. def is_resource_multiplatform(self, resource_name):
  63. # type: (str) -> bool
  64. """
  65. Return True if resource is multiplatform, False otherwise
  66. """
  67. er_resource = self.get_resource(resource_name)
  68. return er_resource.get("multiplatform", False)
  69. def list_npm_packages(self):
  70. # type: () -> list[str]
  71. """
  72. Returns a list of the names of the npm tools used in the toolchain
  73. """
  74. result = []
  75. for resource_name, resource in self.data.items():
  76. if resource.get("type") == self.ResourceType.NPM_PACKAGE:
  77. result.append(resource_name)
  78. return result
  79. def select_version_of(self, resource_name, range_str=None):
  80. # type: (str, str|None) -> Version|None
  81. er_resource = self.get_resource(resource_name)
  82. if range_str is None:
  83. return Version.from_str(er_resource.get("default"))
  84. version_range = VersionRange.from_str(range_str)
  85. # assuming the version list is sorted from the lowest to the highest version,
  86. # we stop the loop as early as possible and hence return the lowest compatible version
  87. for version in self.get_versions_of(er_resource):
  88. if version_range.is_satisfied_by(version):
  89. return version
  90. return None
  91. def use_resource_directly(self, resource_name):
  92. # type: (str) -> bool
  93. er_resource = self.get_resource(resource_name)
  94. return er_resource.get("useDirectly", False)