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.
britney2-ubuntu/britney2/console.py

126 lines
5.2 KiB

import code
import collections
class SubInterpreterExit(SystemExit):
pass
def fuzzy_match(string, collection, thing_being_matched):
if len(collection) < 1:
raise ValueError("No valid candidates to match!?")
matches = collection
if string:
if string in collection:
return string
matches = [x for x in collection if string in x]
if not matches:
raise ValueError("No matches for %s (%s), possible valid values are: %s" % (
string, thing_being_matched, sorted(collection)))
if string is not None and len(matches) > 1:
matches = [x for x in collection if x.starts(string)]
if len(matches) > 1:
if string is None:
raise ValueError("More than one item and no search criteria for %s, possible valid values are: %s" % (
thing_being_matched, sorted(matches)))
raise ValueError("Too many matches for %s (%s), matching candidates are: %s" % (
string, thing_being_matched, sorted(matches)))
return next(iter(matches))
class ConsoleUtils(object):
def __init__(self, britney):
self._britney = britney
self._pkgid_cache = collections.defaultdict(list)
self._build_cache()
def _build_cache(self):
for pkg_id in self._britney.all_binaries:
self._pkgid_cache[pkg_id.package_name].append(pkg_id)
def pkg_id(self, package_name, package_version=None, package_architecture=None, *,
fuzzy_match_version=True, fuzzy_match_arch=True):
"""Look up BinaryPackageID
Example:
pkg_id("lintian", "2.5", "amd64") -> BinaryPackageID("lintian", "2.5.10", "amd64")
(Note that difference in version is intentional and a part of the fuzzy matching)
:param package_name: Name of the package (e.g. "lintian")
:param package_version: Version of the package (e.g. "2.5")
:param package_architecture: Architecture of the package (note arch:all packages are always split
in to a per-architecture package)
:param fuzzy_match_version: If true, any version string is accepted as long as it uniquely identified
the package.
:param fuzzy_match_arch: If true, any architecture string is accepted as long as it uniquely identified
the package.
:return: Exactly one BinaryPackageId
"""
if package_name not in self._pkgid_cache:
raise ValueError("Unknown package name: %s" % package_name)
package_candidates = self._pkgid_cache[package_name]
unique_versions = {x.version for x in package_candidates}
real_version = package_version
if package_version is None or package_version not in unique_versions:
if not fuzzy_match_version:
if unique_versions is None:
raise ValueError("unique_versions cannot be None when fuzzy_match_version is False")
raise ValueError("Unknown version %s, valid options are: %s" % (
package_version, sorted(unique_versions)))
real_version = fuzzy_match(package_architecture, unique_versions, 'package_version')
unique_architectures = {x.architecture for x in package_candidates if x.version == real_version}
real_architecture = package_architecture
if package_architecture is None or package_architecture not in unique_architectures:
if not fuzzy_match_arch:
if package_architecture is None:
raise ValueError("package_architecture cannot be None when fuzzy_match_arch is False")
raise ValueError("Unknown architecture %s" % package_architecture)
real_architecture = fuzzy_match(package_architecture, unique_architectures, 'package_architecture')
match = [x for x in package_candidates if x.version == real_version and x.architecture == real_architecture]
if len(match) != 1:
if not match:
raise ValueError("Package %s, version %s (%s) is not available on architecture %s (%s)" %
package_name, package_version, real_version, package_architecture, real_architecture)
raise ValueError("The terms %s, %s (%s) and %s (%s) did not result in a unique package!? All matches: %s" %
package_name, package_version, real_version, package_architecture, real_architecture,
sorted(match))
return match[0]
def console_quit():
raise SubInterpreterExit()
def run_python_console(britney_obj):
console_utils = ConsoleUtils(britney_obj)
console_locals = {
'britney': britney_obj,
'__name__': '__console__',
'__doc__': None,
'all_bin_pkg_ids': britney_obj.all_binaries.keys(),
'pkg_id': console_utils.pkg_id,
'quit': console_quit,
'exit': console_quit,
}
console = code.InteractiveConsole(locals=console_locals)
banner = """\
Interactive python (REPL) shell in britney.
Locals available
* britney: Instance of the Britney object.
* all_bin_pkg_ids: Set of all BinaryPackageIDs
* pkg_id: Lookup a BinaryPackageID
* quit()/exit(): leave this REPL console.
"""
try:
console.interact(banner=banner, exitmsg='')
except SubInterpreterExit:
pass