Devuan deployment of britney2
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

126 lines
5.2 KiB

  1. import code
  2. import collections
  3. class SubInterpreterExit(SystemExit):
  4. pass
  5. def fuzzy_match(string, collection, thing_being_matched):
  6. if len(collection) < 1:
  7. raise ValueError("No valid candidates to match!?")
  8. matches = collection
  9. if string:
  10. if string in collection:
  11. return string
  12. matches = [x for x in collection if string in x]
  13. if not matches:
  14. raise ValueError("No matches for %s (%s), possible valid values are: %s" % (
  15. string, thing_being_matched, sorted(collection)))
  16. if string is not None and len(matches) > 1:
  17. matches = [x for x in collection if x.starts(string)]
  18. if len(matches) > 1:
  19. if string is None:
  20. raise ValueError("More than one item and no search criteria for %s, possible valid values are: %s" % (
  21. thing_being_matched, sorted(matches)))
  22. raise ValueError("Too many matches for %s (%s), matching candidates are: %s" % (
  23. string, thing_being_matched, sorted(matches)))
  24. return next(iter(matches))
  25. class ConsoleUtils(object):
  26. def __init__(self, britney):
  27. self._britney = britney
  28. self._pkgid_cache = collections.defaultdict(list)
  29. self._build_cache()
  30. def _build_cache(self):
  31. for pkg_id in self._britney.all_binaries:
  32. self._pkgid_cache[pkg_id.package_name].append(pkg_id)
  33. def pkg_id(self, package_name, package_version=None, package_architecture=None, *,
  34. fuzzy_match_version=True, fuzzy_match_arch=True):
  35. """Look up BinaryPackageID
  36. Example:
  37. pkg_id("lintian", "2.5", "amd64") -> BinaryPackageID("lintian", "2.5.10", "amd64")
  38. (Note that difference in version is intentional and a part of the fuzzy matching)
  39. :param package_name: Name of the package (e.g. "lintian")
  40. :param package_version: Version of the package (e.g. "2.5")
  41. :param package_architecture: Architecture of the package (note arch:all packages are always split
  42. in to a per-architecture package)
  43. :param fuzzy_match_version: If true, any version string is accepted as long as it uniquely identified
  44. the package.
  45. :param fuzzy_match_arch: If true, any architecture string is accepted as long as it uniquely identified
  46. the package.
  47. :return: Exactly one BinaryPackageId
  48. """
  49. if package_name not in self._pkgid_cache:
  50. raise ValueError("Unknown package name: %s" % package_name)
  51. package_candidates = self._pkgid_cache[package_name]
  52. unique_versions = {x.version for x in package_candidates}
  53. real_version = package_version
  54. if package_version is None or package_version not in unique_versions:
  55. if not fuzzy_match_version:
  56. if unique_versions is None:
  57. raise ValueError("unique_versions cannot be None when fuzzy_match_version is False")
  58. raise ValueError("Unknown version %s, valid options are: %s" % (
  59. package_version, sorted(unique_versions)))
  60. real_version = fuzzy_match(package_architecture, unique_versions, 'package_version')
  61. unique_architectures = {x.architecture for x in package_candidates if x.version == real_version}
  62. real_architecture = package_architecture
  63. if package_architecture is None or package_architecture not in unique_architectures:
  64. if not fuzzy_match_arch:
  65. if package_architecture is None:
  66. raise ValueError("package_architecture cannot be None when fuzzy_match_arch is False")
  67. raise ValueError("Unknown architecture %s" % package_architecture)
  68. real_architecture = fuzzy_match(package_architecture, unique_architectures, 'package_architecture')
  69. match = [x for x in package_candidates if x.version == real_version and x.architecture == real_architecture]
  70. if len(match) != 1:
  71. if not match:
  72. raise ValueError("Package %s, version %s (%s) is not available on architecture %s (%s)" %
  73. package_name, package_version, real_version, package_architecture, real_architecture)
  74. raise ValueError("The terms %s, %s (%s) and %s (%s) did not result in a unique package!? All matches: %s" %
  75. package_name, package_version, real_version, package_architecture, real_architecture,
  76. sorted(match))
  77. return match[0]
  78. def console_quit():
  79. raise SubInterpreterExit()
  80. def run_python_console(britney_obj):
  81. console_utils = ConsoleUtils(britney_obj)
  82. console_locals = {
  83. 'britney': britney_obj,
  84. '__name__': '__console__',
  85. '__doc__': None,
  86. 'all_bin_pkg_ids': britney_obj.all_binaries.keys(),
  87. 'pkg_id': console_utils.pkg_id,
  88. 'quit': console_quit,
  89. 'exit': console_quit,
  90. }
  91. console = code.InteractiveConsole(locals=console_locals)
  92. banner = """\
  93. Interactive python (REPL) shell in britney.
  94. Locals available
  95. * britney: Instance of the Britney object.
  96. * all_bin_pkg_ids: Set of all BinaryPackageIDs
  97. * pkg_id: Lookup a BinaryPackageID
  98. * quit()/exit(): leave this REPL console.
  99. """
  100. try:
  101. console.interact(banner=banner, exitmsg='')
  102. except SubInterpreterExit:
  103. pass