Files
entropy/client/solo/commands/query.py
2013-08-23 10:57:36 +02:00

1591 lines
55 KiB
Python

# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Command Line Client}.
"""
import os
import sys
import re
import argparse
from entropy.const import etpConst, const_convert_to_unicode, \
const_convert_to_rawstring
from entropy.i18n import _, ngettext
from entropy.output import darkgreen, darkred, blue, teal, purple, brown, \
bold
import entropy.tools
from solo.commands.descriptor import SoloCommandDescriptor
from solo.commands.command import SoloCommand
from solo.utils import print_package_info, print_table, get_file_mime, \
graph_packages, revgraph_packages
class SoloQuery(SoloCommand):
"""
Main Solo Query command.
"""
NAME = "query"
ALIASES = ["q"]
ALLOW_UNPRIVILEGED = True
INTRODUCTION = """\
Repository query tools.
"""
SEE_ALSO = ""
def __init__(self, args):
SoloCommand.__init__(self, args)
self._nsargs = None
self._commands = {}
def man(self):
"""
Overridden from SoloCommand.
"""
return self._man()
def _get_parser(self):
"""
Overridden from SoloCommand.
"""
_commands = {}
descriptor = SoloCommandDescriptor.obtain_descriptor(
SoloQuery.NAME)
parser = argparse.ArgumentParser(
description=descriptor.get_description(),
formatter_class=argparse.RawDescriptionHelpFormatter,
prog="%s %s" % (sys.argv[0], SoloQuery.NAME))
self._setup_verbose_quiet_parser(parser)
subparsers = parser.add_subparsers(
title="action", description=_("repository query tools"),
help=_("available commands"))
belongs_parser = subparsers.add_parser(
"belongs",
help=_("resolve what package a file belongs to"))
belongs_parser.add_argument(
"files", nargs='+', metavar="<file>",
help=_("file path"))
self._setup_verbose_quiet_parser(belongs_parser)
belongs_parser.set_defaults(func=self._belongs)
_commands["belongs"] = {}
changelog_parser = subparsers.add_parser(
"changelog",
help=_("show package changelog"))
changelog_parser.add_argument(
"packages", nargs='+', metavar="<package>",
help=_("package name"))
self._setup_verbose_quiet_parser(changelog_parser)
changelog_parser.set_defaults(func=self._changelog)
_commands["changelog"] = {}
revdeps_parser = subparsers.add_parser(
"revdeps",
help=_("show reverse dependencies of package"))
revdeps_parser.add_argument(
"packages", nargs='+', metavar="<package>",
help=_("package name"))
self._setup_verbose_quiet_parser(revdeps_parser)
revdeps_parser.set_defaults(func=self._revdeps)
_commands["revdeps"] = {}
desc_parser = subparsers.add_parser(
"description",
help=_("search package by description"))
desc_parser.add_argument(
"descriptions", nargs='+', metavar="<description>",
help=_("description keyword"))
desc_parser.set_defaults(func=self._description)
self._setup_verbose_quiet_parser(desc_parser)
_commands["description"] = {}
files_parser = subparsers.add_parser(
"files",
help=_("show files owned by package"))
files_parser.add_argument(
"packages", nargs='+', metavar="<package>",
help=_("package name"))
files_parser.set_defaults(func=self._files)
self._setup_verbose_quiet_parser(files_parser)
_commands["files"] = {}
installed_parser = subparsers.add_parser(
"installed",
help=_("search installed packages"))
installed_parser.add_argument(
"packages", nargs='+', metavar="<package>",
help=_("package name"))
installed_parser.set_defaults(func=self._installed)
self._setup_verbose_quiet_parser(installed_parser)
_commands["installed"] = {}
lic_parser = subparsers.add_parser(
"license",
help=_("show packages using the given license"))
lic_parser.add_argument(
"licenses", nargs='+', metavar="<license>",
help=_("license name"))
lic_parser.set_defaults(func=self._license)
self._setup_verbose_quiet_parser(lic_parser)
_commands["license"] = {}
list_parser = subparsers.add_parser(
"list", help=_("list packages"))
self._setup_verbose_quiet_parser(list_parser)
list_d = {}
_commands["list"] = list_d
list_subparsers = list_parser.add_subparsers(
title="action", description=_("list packages"),
help=_("available commands"))
installed_parser = list_subparsers.add_parser(
"installed", help=_("list installed packages"))
installed_parser.add_argument(
"--by-user", action="store_true", default=False,
help=_("only list packages installed by user"))
installed_parser.add_argument(
"repos", metavar="<repo>", nargs="*",
help=_("only list packages installed from given repositories"))
self._setup_verbose_quiet_parser(installed_parser)
installed_parser.set_defaults(func=self._list_installed)
list_d["installed"] = {
"--by-user": {},
}
available_parser = list_subparsers.add_parser(
"available", help=_("list available packages"))
available_parser.add_argument(
"repos", metavar="<repo>", nargs="+",
help=_("only list packages from given repositories"))
self._setup_verbose_quiet_parser(available_parser)
available_parser.set_defaults(func=self._list_available)
list_d["available"] = {}
mime_parser = subparsers.add_parser(
"mimetype",
help=_("show packages able to handle the given mimetype"))
mime_parser.add_argument(
"mimes", nargs='+', metavar="<mime>",
help=_("mimetype"))
mime_parser.add_argument(
"--installed", action="store_true", default=False,
help=_("only show installed packages"))
self._setup_verbose_quiet_parser(mime_parser)
mime_parser.set_defaults(func=self._mimetype)
_commands["mimetype"] = {
"--installed": {},
}
associate_parser = subparsers.add_parser(
"associate",
help=_("associate file to packages able to handle it"))
associate_parser.add_argument(
"files", nargs='+', metavar="<file>",
help=_("file path"))
associate_parser.add_argument(
"--installed", action="store_true", default=False,
help=_("only show installed packages"))
self._setup_verbose_quiet_parser(associate_parser)
associate_parser.set_defaults(func=self._associate)
_commands["associate"] = {
"--installed": {},
}
needed_parser = subparsers.add_parser(
"needed",
help=_("show runtime libraries needed by the given package"))
needed_parser.add_argument(
"packages", nargs='+', metavar="<package>",
help=_("package name"))
self._setup_verbose_quiet_parser(needed_parser)
needed_parser.set_defaults(func=self._needed)
_commands["needed"] = {}
orphans_parser = subparsers.add_parser(
"orphans",
help=_("search files not belonging to any packages"))
orphans_parser.set_defaults(func=self._orphans)
_commands["orphans"] = {}
required_parser = subparsers.add_parser(
"required",
help=_("show packages requiring the given library name"))
required_parser.add_argument(
"libraries", nargs='+', metavar="<library>",
help=_("library name (example: libdl.so.2)"))
self._setup_verbose_quiet_parser(required_parser)
required_parser.set_defaults(func=self._required)
_commands["required"] = {}
sets_parser = subparsers.add_parser(
"sets",
help=_("search package sets"))
sets_parser.add_argument(
"sets", nargs='*', metavar="<set>",
help=_("set name"))
self._setup_verbose_quiet_parser(sets_parser)
sets_parser.set_defaults(func=self._sets)
_commands["sets"] = {}
slot_parser = subparsers.add_parser(
"slot",
help=_("show packages owning the given slot"))
slot_parser.add_argument(
"slots", nargs='+', metavar="<slot>",
help=_("slot name"))
self._setup_verbose_quiet_parser(slot_parser)
slot_parser.set_defaults(func=self._slot)
_commands["slot"] = {}
tags_parser = subparsers.add_parser(
"tags",
help=_("show packages owning the given tag"))
tags_parser.add_argument(
"tags", nargs='+', metavar="<tag>",
help=_("tag name"))
self._setup_verbose_quiet_parser(tags_parser)
tags_parser.set_defaults(func=self._tags)
_commands["tags"] = {}
revs_parser = subparsers.add_parser(
"revisions",
help=_("show packages at the given revision"))
revs_parser.add_argument(
"revisions", nargs='+', metavar="<revision>",
help=_("revision name"))
self._setup_verbose_quiet_parser(revs_parser)
revs_parser.set_defaults(func=self._revisions)
_commands["revisions"] = {}
graph_parser = subparsers.add_parser(
"graph",
help=_("show the direct dependencies graph "
"for the given package"))
graph_parser.add_argument(
"packages", nargs='+', metavar="<package>",
help=_("package name"))
graph_parser.add_argument(
"--complete", action="store_true", default=False,
help=_("include system packages, build-time dependencies "
"and circular dependencies information"))
self._setup_verbose_quiet_parser(graph_parser)
graph_parser.set_defaults(func=self._graph)
_commands["graph"] = {
"--complete": {},
}
revgraph_parser = subparsers.add_parser(
"revgraph",
help=_("show the inverse dependencies graph "
"for the given package"))
revgraph_parser.add_argument(
"packages", nargs='+', metavar="<package>",
help=_("package name"))
revgraph_parser.add_argument(
"--complete", action="store_true", default=False,
help=_("include system packages, build-time dependencies "
"and circular dependencies information"))
self._setup_verbose_quiet_parser(revgraph_parser)
revgraph_parser.set_defaults(func=self._revgraph)
_commands["revgraph"] = {
"--complete": {},
}
updates_parser = subparsers.add_parser(
"updates",
help=_("show the number of updates available"))
self._setup_verbose_quiet_parser(updates_parser)
updates_parser.set_defaults(func=self._updates)
_commands["updates"] = {}
self._commands = _commands
return parser
def parse(self):
"""
Parse command
"""
parser = self._get_parser()
try:
nsargs = parser.parse_args(self._args)
except IOError as err:
sys.stderr.write("%s\n" % (err,))
return parser.print_help, []
# Python 3.3 bug #16308
if not hasattr(nsargs, "func"):
return parser.print_help, []
self._nsargs = nsargs
return self._call_locked, [nsargs.func]
def bashcomp(self, last_arg):
"""
Overridden from SoloCommand.
"""
self._get_parser() # this will generate self._commands
outcome = ["--quiet", "-q", "--verbose", "-v"]
return self._hierarchical_bashcomp(
last_arg, outcome, self._commands)
def _belongs(self, entropy_client):
"""
Solo Query Belongs command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
files = self._nsargs.files
entropy_repository = entropy_client.installed_repository()
if not quiet:
entropy_client.output(
darkgreen(_("Belong Search")),
header=darkred(" @@ "))
results = {}
flatresults = {}
reverse_symlink_map = entropy_client.Settings(
)['system_rev_symlinks']
for xfile in files:
results[xfile] = set()
pkg_ids = entropy_repository.searchBelongs(xfile)
if not pkg_ids:
# try real path if possible
pkg_ids = entropy_repository.searchBelongs(
os.path.realpath(xfile))
if not pkg_ids:
# try using reverse symlink mapping
for sym_dir in reverse_symlink_map:
if xfile.startswith(sym_dir):
for sym_child in reverse_symlink_map[sym_dir]:
my_file = sym_child+xfile[len(sym_dir):]
pkg_ids = entropy_repository.searchBelongs(
my_file)
if pkg_ids:
break
for pkg_id in pkg_ids:
if not flatresults.get(pkg_id):
results[xfile].add(pkg_id)
flatresults[pkg_id] = True
if results:
key_sorter = lambda x: entropy_repository.retrieveAtom(x)
for result in results:
# print info
xfile = result
result = results[result]
for pkg_id in sorted(result, key = key_sorter):
if quiet:
entropy_client.output(
entropy_repository.retrieveAtom(pkg_id),
level="generic")
else:
print_package_info(pkg_id, entropy_client,
entropy_repository, installed_search = True,
extended = verbose, quiet = quiet)
if not quiet:
toc = []
toc.append(("%s:" % (
blue(_("Keyword")),), purple(xfile)))
toc.append((
"%s:" % (
blue(_("Found")),), "%s %s" % (
len(result),
brown(ngettext("entry", "entries",
len(result))),)))
print_table(entropy_client, toc)
return 0
def _changelog(self, entropy_client):
"""
Solo Query Changelog command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
packages = self._nsargs.packages
entropy_repository = entropy_client.installed_repository()
if not quiet:
entropy_client.output(
darkgreen(_("ChangeLog Search")),
header=darkred(" @@ "))
for package in packages:
repo = entropy_repository
if entropy_repository is not None:
pkg_id, rc = entropy_repository.atomMatch(package)
if rc != 0:
entropy_client.output(
"%s: %s" % (
darkred(_("No match for")),
bold(package),))
continue
else:
pkg_id, r_id = entropy_client.atom_match(package)
if pkg_id == -1:
entropy_client.output(
"%s: %s" % (
darkred(_("No match for")),
bold(package),))
continue
repo = entropy_client.open_repository(r_id)
repo_atom = repo.retrieveAtom(pkg_id)
if quiet:
entropy_client.output(
"%s :" % (repo_atom,),
level="generic")
else:
entropy_client.output(
"%s: %s" % (
blue(_("Package")),
bold(repo_atom),
),
header=" "
)
changelog = repo.retrieveChangelog(pkg_id)
if not changelog or (changelog == "None"):
# == "None" is a bug, see:
# 685b865453d552d37ce3a9559f4cefb9a88f8beb
entropy_client.output(
_("No ChangeLog available"),
level="generic")
else:
entropy_client.output(changelog, level="generic")
entropy_client.output("=" * 80)
if not quiet:
# check developer repo mode
repo_conf = entropy_client.Settings().get_setting_files_data(
)['repositories']
dev_repo = entropy_client.Settings(
)['repositories']['developer_repo']
if not dev_repo:
entropy_client.output(
"%s ! [%s]" % (
brown(_("Attention: developer-repo "
"option not enabled")),
blue(repo_conf),
),
level=bold(" !!! "))
return 0
def _revdeps(self, entropy_client):
"""
Solo Query Revdeps command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
packages = self._nsargs.packages
entropy_repository = entropy_client.installed_repository()
settings = entropy_client.Settings()
if not quiet:
entropy_client.output(
darkgreen(_("Reverse Dependencies Search")),
header=darkred(" @@ "))
include_build_deps = False
excluded_dep_types = None
if include_build_deps:
excluded_dep_types.append(
etpConst['dependency_type_ids']['bdepend_id'])
for package in packages:
result = entropy_repository.atomMatch(package)
match_in_repo = False
repo_masked = False
if result[0] == -1:
match_in_repo = True
result = entropy_client.atom_match(package)
if result[0] == -1:
result = entropy_client.atom_match(
package, mask_filter = False)
if result[0] != -1:
repo_masked = True
if result[0] != -1:
repo = entropy_repository
if match_in_repo:
repo = entropy_client.open_repository(result[1])
key_sorter = lambda x: repo.retrieveAtom(x)
found_atom = repo.retrieveAtom(result[0])
if repo_masked:
package_id_masked, idmasking_reason = repo.maskFilter(
result[0])
search_results = repo.retrieveReverseDependencies(
result[0], exclude_deptypes = excluded_dep_types)
for pkg_id in sorted(search_results, key = key_sorter):
print_package_info(pkg_id, entropy_client, repo,
installed_search = True, strict_output = quiet,
extended = verbose, quiet = quiet)
if not quiet:
masking_reason = ''
if repo_masked:
masking_reason = ", %s" % (
settings['pkg_masking_reasons'].get(
idmasking_reason),
)
repo_masked_str = const_convert_to_unicode(
repo_masked)
mask_str = bold(repo_masked_str) + masking_reason
toc = []
toc.append(("%s:" % (
blue(_("Keyword")),), purple(package)))
toc.append(("%s:" % (
blue(_("Matched")),), teal(found_atom)))
toc.append(("%s:" % (
blue(_("Masked")),), mask_str))
if match_in_repo:
where = "%s %s" % (
_("from repository"), result[1])
else:
where = _("from the installed packages repository")
entry_str = ngettext(
"entry", "entries", len(search_results))
toc.append(
("%s:" % (blue(_("Found")),),
"%s %s %s" % (
len(search_results),
brown(entry_str),
where,)
))
print_table(entropy_client, toc)
return 0
def _description(self, entropy_client):
"""
Solo Query Description command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
descriptions = self._nsargs.descriptions
entropy_repository = entropy_client.installed_repository()
settings = entropy_client.Settings()
found = False
if not quiet:
entropy_client.output(
darkgreen(_("Description Search")),
header=darkred(" @@ "))
repo_number = 0
for repo_id in entropy_client.repositories():
repo_number += 1
repo_data = settings['repositories']['available'][repo_id]
if not quiet:
header = const_convert_to_unicode(" #") + \
const_convert_to_unicode(repo_number) + \
const_convert_to_unicode(" ")
entropy_client.output(
"%s" % (
bold(repo_data['description']),
),
header=blue(header))
repo = entropy_client.open_repository(repo_id)
found = self._search_descriptions(
descriptions, entropy_client, repo, quiet, verbose)
if not quiet and not found:
entropy_client.output(
darkgreen("%s." % (_("No matches"),)),
header=darkred(" @@ "))
return 0
def _search_descriptions(self, descriptions,
entropy_client, entropy_repository,
quiet, verbose):
key_sorter = lambda x: entropy_repository.retrieveAtom(x)
found = 0
for desc in descriptions:
pkg_ids = entropy_repository.searchDescription(
desc, just_id = True)
if not pkg_ids:
continue
found += len(pkg_ids)
for pkg_id in sorted(pkg_ids, key = key_sorter):
if quiet:
entropy_client.output(
entropy_repository.retrieveAtom(pkg_id))
else:
print_package_info(
pkg_id, entropy_client,
entropy_repository,
extended = verbose, strict_output = False,
quiet = False)
if not quiet:
toc = []
toc.append(("%s:" % (blue(_("Keyword")),), purple(desc)))
toc.append(("%s:" % (blue(_("Found")),), "%s %s" % (
len(pkg_ids),
brown(ngettext("entry", "entries", len(pkg_ids))),)))
print_table(entropy_client, toc)
return found
def _files(self, entropy_client):
"""
Solo Query Files command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
packages = self._nsargs.packages
entropy_repository = entropy_client.installed_repository()
if not quiet:
entropy_client.output(
darkgreen(_("Files Search")),
header=darkred(" @@ "))
for package in packages:
pkg_id, pkg_rc = entropy_repository.atomMatch(package)
if pkg_id == -1:
continue
atom = entropy_repository.retrieveAtom(pkg_id)
files = entropy_repository.retrieveContentIter(
pkg_id, order_by="file")
files_len = 0
if quiet:
for xfile, ftype in files:
files_len += 1
entropy_client.output(xfile, level="generic")
else:
for xfile, ftype in files:
files_len += 1
entropy_client.output(
brown(xfile),
header=blue(" ### "))
if not quiet:
toc = []
toc.append(("%s:" % (blue(_("Package")),), purple(atom)))
toc.append(("%s:" % (blue(_("Found")),), "%s %s" % (
files_len, brown(_("files")),)))
print_table(entropy_client, toc)
return 0
def _installed(self, entropy_client):
"""
Solo Query Installed command.
Alias of "solo search --installed".
"""
from solo.commands.search import SoloSearch
search = SoloSearch(
self._nsargs, quiet=self._nsargs.quiet,
verbose=self._nsargs.verbose,
installed=True, packages=self._nsargs.packages)
return search.search(entropy_client)
def _license(self, entropy_client):
"""
Solo Query License command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
licenses = self._nsargs.licenses
settings = entropy_client.Settings()
if not quiet:
entropy_client.output(
darkgreen(_("License Search")),
header=darkred(" @@ "))
found = False
repo_number = 0
for repo_id in entropy_client.repositories():
repo_number += 1
repo_data = settings['repositories']['available'][repo_id]
if not quiet:
header = const_convert_to_unicode(" #") + \
const_convert_to_unicode(repo_number) + \
const_convert_to_unicode(" ")
entropy_client.output(
"%s" % (
bold(repo_data['description']),
),
header=blue(header))
repo = entropy_client.open_repository(repo_id)
key_sorter = lambda x: repo.retrieveAtom(x)
for mylicense in licenses:
results = repo.searchLicense(mylicense, just_id = True)
if not results:
continue
found = True
for pkg_id in sorted(results, key = key_sorter):
print_package_info(
pkg_id, entropy_client, repo,
extended = verbose,
strict_output = quiet,
quiet = quiet)
if not quiet:
res_txt = ngettext("entry", "entries", len(results))
toc = []
toc.append(
("%s:" % (blue(_("Keyword")),),
purple(mylicense)))
toc.append(
("%s:" % (blue(_("Found")),),
"%s %s" % (len(results), brown(res_txt),)))
print_table(entropy_client, toc)
if not quiet and not found:
entropy_client.output(
darkgreen("%s." % (_("No matches"),)),
header=darkred(" @@ "))
return 0
def _list_packages(self, entropy_client, entropy_repository,
filter_funcs):
"""
List packages in repository. The filter functions determine
what packages shall be listed.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
settings = entropy_client.Settings()
if not quiet:
entropy_client.output(
darkgreen(_("Listing Packages")),
header=darkred(" @@ "))
repository_id = entropy_repository.repository_id()
pkg_ids = entropy_repository.listAllPackageIds(
order_by = "atom")
for filter_func in filter_funcs:
pkg_mtc = filter(
filter_func,
[(x, repository_id) for x in pkg_ids])
pkg_ids = [x[0] for x in pkg_mtc]
for pkg_id in pkg_ids:
atom = entropy_repository.retrieveAtom(pkg_id)
if atom is None:
continue
if not verbose:
atom = entropy.dep.dep_getkey(atom)
branchinfo = ""
sizeinfo = ""
if verbose:
branch = entropy_repository.retrieveBranch(pkg_id)
branchinfo = darkgreen(" [") + darkred(branch) + \
darkgreen("] ")
mysize = entropy_repository.retrieveOnDiskSize(pkg_id)
mysize = entropy.tools.bytes_into_human(mysize)
sizeinfo = brown(" [") + purple(mysize) + brown("]")
if not quiet:
entropy_client.output(
"%s%s%s %s" % (
blue(const_convert_to_unicode(pkg_id)),
sizeinfo,
branchinfo,
atom),
header=darkred("# "))
else:
entropy_client.output(atom, level="generic")
if not pkg_ids and not quiet:
entropy_client.output(
darkgreen("%s." % (_("No matches"),)),
header=darkred(" @@ "))
return 0
def _list_installed(self, entropy_client):
"""
Solo Query List Installed command.
"""
repositories = self._nsargs.repos
by_user = self._nsargs.by_user
def by_user_filter(pkg_match):
pkg_id, pkg_repo = pkg_match
repo_db = entropy_client.open_repository(pkg_repo)
source_id = repo_db.getInstalledPackageSource(
pkg_id)
return source_id == etpConst['install_sources']['user']
def by_repoid_filter(pkg_match):
pkg_id, pkg_repo = pkg_match
repo_db = entropy_client.open_repository(pkg_repo)
inst_pkg_repo = repo_db.getInstalledPackageRepository(
pkg_id)
return inst_pkg_repo in repositories
filter_funcs = []
if by_user:
filter_funcs.append(by_user_filter)
if repositories:
filter_funcs.append(by_repoid_filter)
return self._list_packages(entropy_client,
entropy_client.installed_repository(),
filter_funcs)
def _list_available(self, entropy_client):
"""
Solo Query List Available command.
"""
repositories = self._nsargs.repos
quiet = self._nsargs.quiet
entropy_repositories = entropy_client.repositories()
exit_st = 1
for repository_id in repositories:
if repository_id not in entropy_repositories:
if not quiet:
entropy_client.output(
"%s: %s" % (
teal(_("Repository is not available")),
repository_id,),
header=purple(" !!! "),
level="warning", importance=1)
exit_st = 1
break
repo = entropy_client.open_repository(repository_id)
exit_st = self._list_packages(entropy_client, repo, [])
if exit_st != 0:
break
return exit_st
def _search_mimetype(self, entropy_client, associate=False):
"""
Solo Query Mimetype command.
"""
installed = self._nsargs.installed
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
settings = entropy_client.Settings()
inst_repo = entropy_client.installed_repository()
inst_repo_id = inst_repo.repository_id()
if associate:
mimetypes = self._nsargs.files
else:
mimetypes = self._nsargs.mimes
if not quiet:
entropy_client.output(
darkgreen(_("Searching Mimetype")),
header=darkred(" @@ "))
found = False
for mimetype in mimetypes:
if associate:
# consider mimetype a file path
mimetype = get_file_mime(mimetype)
if mimetype is None:
continue
if not quiet:
entropy_client.output(
bold(mimetype),
header=blue(" # "))
if installed:
matches = [(x, inst_repo_id) for x in \
entropy_client.search_installed_mimetype(mimetype)]
else:
matches = entropy_client.search_available_mimetype(
mimetype)
if matches:
found = True
key_sorter = lambda x: \
entropy_client.open_repository(x[1]).retrieveAtom(x[0])
for pkg_id, pkg_repo in sorted(matches, key = key_sorter):
repo = entropy_client.open_repository(pkg_repo)
print_package_info(pkg_id, entropy_client, repo,
extended = verbose, quiet = quiet)
if not quiet:
entry_str = ngettext("entry", "entries", len(matches))
toc = []
toc.append(("%s:" % (
blue(_("Keyword")),), purple(mimetype)))
toc.append((
"%s:" % (blue(_("Found")),),
"%s %s" % (
len(matches),
brown(entry_str))
))
print_table(entropy_client, toc)
if not quiet and not found:
entropy_client.output(
darkgreen("%s." % (_("No matches"),)),
header=darkred(" @@ "))
return 0
def _mimetype(self, entropy_client):
"""
Solo Query Mimetype command.
"""
return self._search_mimetype(
entropy_client,
associate=False)
def _associate(self, entropy_client):
"""
Solo Query Associate command.
"""
return self._search_mimetype(
entropy_client,
associate=True)
def _needed(self, entropy_client):
"""
Solo Query Needed command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
packages = self._nsargs.packages
entropy_repository = entropy_client.installed_repository()
if not quiet:
entropy_client.output(
darkgreen(_("Needed Libraries Search")),
header=darkred(" @@ "))
for package in packages:
pkg_id, pkg_rc = entropy_repository.atomMatch(package)
if pkg_id == -1:
continue
atom = entropy_repository.retrieveAtom(pkg_id)
neededs = entropy_repository.retrieveNeeded(
pkg_id, extended=True)
for needed, elfclass in neededs:
if verbose:
needed = "%s %s" % (needed, elfclass)
if quiet:
entropy_client.output(
needed, level="generic")
else:
entropy_client.output(
darkred(const_convert_to_unicode(needed)),
header=blue(" # "))
if not quiet:
toc = []
toc.append(("%s:" % (blue(_("Package")),), purple(atom)))
toc.append(("%s:" % (blue(_("Found")),), "%s %s" % (
len(neededs), brown(_("libraries")),)))
print_table(entropy_client, toc)
return 0
def _orphans(self, entropy_client):
"""
Solo Query Orphans command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
settings = entropy_client.Settings()
entropy_repository = entropy_client.installed_repository()
if not quiet:
entropy_client.output(
darkgreen(_("Orphans Search")),
header=darkred(" @@ "))
reverse_symlink_map = settings['system_rev_symlinks']
system_dirs_mask = [x for x in settings['system_dirs_mask'] \
if entropy.tools.is_valid_path(x)]
# make sure we're all rawstring.
system_dirs_mask = [const_convert_to_rawstring(x) for x in \
system_dirs_mask]
system_dirs_mask_regexp = []
for mask in settings['system_dirs_mask']:
reg_mask = re.compile(mask)
system_dirs_mask_regexp.append(reg_mask)
file_data = set()
dirs = settings['system_dirs']
count = 0
for xdir in dirs:
# make sure it's bytes (raw encoding
# as per EntropyRepository.retrieveContent())
xdir = const_convert_to_rawstring(
xdir,
from_enctype=etpConst['conf_raw_encoding'])
try:
wd = os.walk(xdir)
except RuntimeError: # maximum recursion?
continue
for currentdir, subdirs, files in wd:
found_files = set()
for filename in files:
filename = os.path.join(currentdir, filename)
# filter symlinks, broken ones will be reported
if os.path.islink(filename) and \
os.path.lexists(filename):
continue
do_cont = False
for mask in system_dirs_mask:
if filename.startswith(mask):
do_cont = True
break
if do_cont:
continue
for mask in system_dirs_mask_regexp:
if mask.match(filename):
do_cont = True
break
if do_cont:
continue
count += 1
filename_utf = const_convert_to_unicode(filename)
if not quiet and ((count == 0) or (count % 500 == 0)):
count = 0
if len(filename_utf) > 50:
fname = filename_utf[:40] + \
const_convert_to_unicode("...") + \
filename_utf[-10:]
else:
fname = filename_utf
entropy_client.output(
"%s: %s" % (
blue(_("Analyzing")),
fname),
header=darkred(" @@ "),
back=True)
found_files.add(filename_utf)
if found_files:
file_data |= found_files
totalfiles = len(file_data)
if not quiet:
entropy_client.output(
"%s: %s" % (
blue(_("Analyzed directories")),
" ".join(settings['system_dirs']),),
header=darkred(" @@ "))
entropy_client.output(
"%s: %s" % (
blue(_("Masked directories")),
" ".join(settings['system_dirs_mask']),),
header=darkred(" @@ "))
entropy_client.output(
"%s: %s" % (
blue(_("Number of files collected on the filesystem")),
bold(const_convert_to_unicode(totalfiles)),),
header=darkred(" @@ "))
entropy_client.output(
"%s: %s" % (
blue(_("Now searching among installed packages")),
bold(const_convert_to_unicode(totalfiles)),),
header=darkred(" @@ "))
pkg_ids = entropy_repository.listAllPackageIds()
length = str(len(pkg_ids))
count = 0
def gen_cont(pkg_id):
for path, ftype in entropy_repository.retrieveContentIter(
pkg_id):
# reverse sym
for sym_dir in reverse_symlink_map:
if path.startswith(sym_dir):
for sym_child in reverse_symlink_map[sym_dir]:
yield sym_child+path[len(sym_dir):]
# real path also
dirname_real = os.path.realpath(os.path.dirname(path))
yield os.path.join(dirname_real, os.path.basename(path))
yield path
for pkg_id in pkg_ids:
if not quiet:
count += 1
atom = entropy_repository.retrieveAtom(pkg_id)
if atom is None:
continue
entropy_client.output(
"%s: %s" % (
blue(_("Checking")),
bold(atom),),
header=darkred(" @@ "),
count=(count, length),
back=True)
# remove from file_data
file_data -= set(gen_cont(pkg_id))
orphanedfiles = len(file_data)
fname = "/tmp/entropy-orphans.txt"
if not quiet:
entropy_client.output(
"%s: %s" % (
blue(_("Number of total files")),
bold(const_convert_to_unicode(totalfiles))
),
header=darkred(" @@ "))
entropy_client.output(
"%s: %s" % (
blue(_("Number of matching files")),
bold(const_convert_to_unicode(
totalfiles - orphanedfiles))
),
header=darkred(" @@ "))
entropy_client.output(
"%s: %s" % (
blue(_("Number of orphaned files")),
bold(const_convert_to_unicode(orphanedfiles))
),
header=darkred(" @@ "))
entropy_client.output(
"%s: %s" % (
blue(_("Writing file to disk")),
bold(const_convert_to_unicode(fname))
),
header=darkred(" @@ "))
sizecount = 0
file_data = list(file_data)
file_data.sort(reverse = True)
with open(fname, "wb") as f_out:
for myfile in file_data:
myfile = const_convert_to_rawstring(myfile)
mysize = 0
try:
mysize += os.stat(myfile).st_size
except OSError:
mysize = 0
sizecount += mysize
f_out.write(myfile + const_convert_to_rawstring("\n"))
if quiet:
entropy_client.output(myfile, level="generic")
f_out.flush()
humansize = entropy.tools.bytes_into_human(sizecount)
if not quiet:
entropy_client.output(
"%s: %s" % (
blue(_("Total space wasted")),
bold(humansize)),
header=darkred(" @@ "))
else:
entropy_client.output(humansize, level="generic")
return 0
def _required(self, entropy_client):
"""
Solo Query Required command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
libraries = self._nsargs.libraries
entropy_repository = entropy_client.installed_repository()
if not quiet:
entropy_client.output(
darkgreen(_("Required Packages Search")),
header=darkred(" @@ "))
key_sorter = lambda x: entropy_repository.retrieveAtom(x)
for library in libraries:
results = entropy_repository.searchNeeded(
library, like = True)
for pkg_id in sorted(results, key = key_sorter):
print_package_info(
pkg_id, entropy_client, entropy_repository,
installed_search=True, strict_output=True,
extended=verbose, quiet=quiet)
if not quiet:
toc = []
entity_str = ngettext("package", "packages", len(results))
toc.append((
"%s:" % (blue(_("Library")),),
purple(library)))
toc.append((
"%s:" % (
blue(_("Found")),),
"%s %s" % (
len(results),
brown(entity_str),)))
print_table(entropy_client, toc)
return 0
def _sets(self, entropy_client):
"""
Solo Query Sets command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
items = self._nsargs.sets
if not items:
items.append("*")
if not quiet:
entropy_client.output(
darkgreen(_("Package Set Search")),
header=darkred(" @@ "))
sets = entropy_client.Sets()
count = 0
found = False
for item in items:
results = sets.search(item)
key_sorter = lambda x: x[1]
for repo, set_name, set_data in sorted(
results, key = key_sorter):
count += 1
found = True
if not quiet:
entropy_client.output(
bold(set_name),
header=blue(" #%d " % (count,)))
elements = sorted(set_data)
for element in elements:
entropy_client.output(
brown(element),
header=" ")
else:
for element in sorted(set_data):
entropy_client.output(
element, level="generic")
if not quiet:
toc = []
entity_str = ngettext("entry", "entries", count)
toc.append(("%s:" % (blue(_("Keyword")),), purple(item)))
toc.append(("%s:" % (blue(_("Found")),), "%s %s" % (
count, brown(entity_str),)))
print_table(entropy_client, toc)
if not quiet and not found:
entropy_client.output(
darkgreen("%s." % (_("No matches"),)),
header=darkred(" @@ "))
return 0
def _slot(self, entropy_client):
"""
Solo Query Slot command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
slots = self._nsargs.slots
settings = entropy_client.Settings()
if not quiet:
entropy_client.output(
darkgreen(_("Slot Search")),
header=darkred(" @@ "))
found = False
# search inside each available database
repo_number = 0
for repo_id in entropy_client.repositories():
repo_number += 1
repo_data = settings['repositories']['available'][repo_id]
if not quiet:
header = const_convert_to_unicode(" #") + \
const_convert_to_unicode(repo_number) + \
const_convert_to_unicode(" ")
entropy_client.output(
"%s" % (
bold(repo_data['description']),
),
header=blue(header))
repo = entropy_client.open_repository(repo_id)
for slot in slots:
results = repo.searchSlotted(slot, just_id = True)
key_sorter = lambda x: repo.retrieveAtom(x)
for pkg_id in sorted(results, key = key_sorter):
found = True
print_package_info(pkg_id, entropy_client, repo,
extended=verbose, strict_output=quiet,
quiet=quiet)
if not quiet:
toc = []
entity_str = ngettext("entry", "entries", len(results))
toc.append((
"%s:" % (blue(_("Keyword")),),
purple(slot)))
toc.append((
"%s:" % (blue(_("Found")),),
"%s %s" % (
len(results),
brown(entity_str),)))
print_table(entropy_client, toc)
if not quiet and not found:
entropy_client.output(
darkgreen("%s." % (_("No matches"),)),
header=darkred(" @@ "))
return 0
def _tags(self, entropy_client):
"""
Solo Query Tags command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
tags = self._nsargs.tags
settings = entropy_client.Settings()
if not quiet:
entropy_client.output(
darkgreen(_("Tag Search")),
header=darkred(" @@ "))
found = False
# search inside each available database
repo_number = 0
for repo_id in entropy_client.repositories():
repo_number += 1
repo_data = settings['repositories']['available'][repo_id]
if not quiet:
header = const_convert_to_unicode(" #") + \
const_convert_to_unicode(repo_number) + \
const_convert_to_unicode(" ")
entropy_client.output(
"%s" % (
bold(repo_data['description']),
),
header=blue(header))
repo = entropy_client.open_repository(repo_id)
for tag in tags:
results = repo.searchTaggedPackages(tag)
key_sorter = lambda x: repo.retrieveAtom(x)
for pkg_id in sorted(results, key = key_sorter):
found = True
print_package_info(pkg_id, entropy_client, repo,
extended=verbose, strict_output=quiet,
quiet=quiet)
if not quiet:
toc = []
entity_str = ngettext("entry", "entries", len(results))
toc.append((
"%s:" % (blue(_("Keyword")),),
purple(tag)))
toc.append((
"%s:" % (blue(_("Found")),),
"%s %s" % (
len(results),
brown(entity_str),)))
print_table(entropy_client, toc)
if not quiet and not found:
entropy_client.output(
darkgreen("%s." % (_("No matches"),)),
header=darkred(" @@ "))
return 0
def _revisions(self, entropy_client):
"""
Solo Query Revisions command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
revisions = self._nsargs.revisions
settings = entropy_client.Settings()
entropy_repository = entropy_client.installed_repository()
if not quiet:
entropy_client.output(
darkgreen(_("Revision Search")),
header=darkred(" @@ "))
found = False
key_sorter = lambda x: entropy_repository.retrieveAtom(x)
for revision in revisions:
results = entropy_repository.searchRevisionedPackages(
revision)
found = True
for pkg_id in sorted(results, key = key_sorter):
print_package_info(
pkg_id, entropy_client, entropy_repository,
extended=verbose, strict_output=quiet,
installed_search=True, quiet=quiet)
if not quiet:
toc = []
entity_str = ngettext("entry", "entries", len(results))
toc.append((
"%s:" % (blue(_("Keyword")),),
purple(revision)))
toc.append((
"%s:" % (blue(_("Found")),),
"%s %s" % (
len(results),
brown(entity_str),)))
print_table(entropy_client, toc)
if not quiet and not found:
entropy_client.output(
darkgreen("%s." % (_("No matches"),)),
header=darkred(" @@ "))
return 0
def _graph(self, entropy_client):
"""
Solo Query Graph command.
"""
packages = self._nsargs.packages
quiet = self._nsargs.quiet
complete = self._nsargs.complete
return graph_packages(
packages, entropy_client,
complete=complete, quiet=quiet)
def _revgraph(self, entropy_client):
"""
Solo Query Revgraph command.
"""
packages = self._nsargs.packages
quiet = self._nsargs.quiet
complete = self._nsargs.complete
return revgraph_packages(
packages, entropy_client,
complete=complete, quiet=quiet)
def _updates(self, entropy_client):
"""
Solo Query Updates command.
"""
quiet = self._nsargs.quiet
verbose = self._nsargs.verbose
if not quiet:
entropy_client.output(
brown(_("Available Updates")),
header=darkred(" @@ "))
outcome = entropy_client.calculate_updates(quiet=True)
update, remove = outcome['update'], outcome['remove']
fine, critical_f = outcome['fine'], outcome['critical_found']
if quiet:
entropy_client.output(
"%d" % (len(update),),
level="generic")
return 0
toc = []
toc.append((
darkgreen(_("Packages to update:")),
bold(const_convert_to_unicode(len(update)))))
toc.append((
darkred(_("Packages to remove:")),
bold(const_convert_to_unicode(len(remove)))))
if verbose:
toc.append((
blue(_("Packages already up-to-date:")),
bold(const_convert_to_unicode(len(fine)))))
toc.append((
purple(_("Critical updates found:")),
teal(const_convert_to_unicode(str(critical_f)))))
print_table(entropy_client, toc)
return 0
SoloCommandDescriptor.register(
SoloCommandDescriptor(
SoloQuery,
SoloQuery.NAME,
_("repository query tools"))
)