Files
entropy/client/kernel-switcher
2020-01-24 23:23:07 +01:00

215 lines
7.1 KiB
Python
Executable File

#!/usr/bin/python
import sys
import os
from os import path as osp
_base = osp.dirname(osp.dirname(osp.realpath(__file__)))
if os.path.isfile(osp.join(_base, "entropy-in-vcs-checkout")):
sys.path.insert(0, osp.join(_base, "entropy_path_loader"))
import entropy_path_loader
del osp
import argparse
import functools
from entropy.locks import EntropyResourcesLock
from entropy.output import brown, print_warning, print_error, teal
from entropy.i18n import _
from entropy.client.interfaces import Client
import entropy.dep
import entropy.tools
from _entropy.solo.commands.install import SoloInstall
from _entropy.solo.utils import print_package_info
import kswitch
class SabayonSwitcher(argparse.Namespace):
def __init__(self, app_name='kernel-switcher'):
argparse.Namespace.__init__(self)
self.quiet = False
self.verbose = False
self.ask = False
self.pretend = False
self.from_running = False
self.called_method = None
self.kernel = None
self._etp_client = None
self.parser = argparse.ArgumentParser(
description=_("Sabayon Kernel Switcher"),
formatter_class=argparse.RawDescriptionHelpFormatter,
prog=app_name
)
self.subparsers = self.parser.add_subparsers(
title=app_name,
description=_("available commands"))
self._add_switch_sub_command()
self._add_list_sub_command()
self._add_help_sub_command()
def _add_switch_sub_command(self):
switch_parser = self.subparsers.add_parser(
"switch", help=_("install a new or just another kernel"))
switch_parser.set_defaults(called_method=self._switch)
switch_parser.add_argument(
"--from-running", action="store_true",
default=False,
dest='from_running',
help=_("use 'uname -r' to determine the running kernel"))
switch_parser.add_argument(
"kernel", metavar="<kernel>",
help=_("the new kernel package dependency name"))
self._add_standard_args(switch_parser, False)
def _add_list_sub_command(self):
list_parser = self.subparsers.add_parser(
"list", help=_("list kernels"))
list_parser.set_defaults(called_method=self._list)
self._add_standard_args(list_parser, True)
def _add_help_sub_command(self):
help_parser = self.subparsers.add_parser(
"help", help=_("this help"))
help_parser.set_defaults(called_method=self._print_help)
def _print_help(self):
self.parser.print_help()
@staticmethod
def _add_standard_args(_parser, restricted):
_parser.add_argument("--quiet", "-q", action="store_true",
default=False,
help=_("quiet mode"))
_parser.add_argument("--verbose", "-v", action="store_true",
default=False,
help=_("verbose mode"))
if not restricted:
_parser.add_argument("--ask", "-a", action="store_true",
default=False,
help=_("ask confirmation"))
_parser.add_argument("--pretend", "-p", action="store_true",
default=False,
help=_("just show what would be done"))
def _wrap_locked_api(method):
@functools.wraps(method)
def wrapper(self, *method_args, **method_kwargs):
lock = EntropyResourcesLock(output=Client)
try:
lock.acquire_shared()
acquired = True
self._etp_client = Client()
ans = method(self, *method_args, **method_kwargs)
finally:
if self._etp_client is not None:
self._etp_client.shutdown()
self._etp_client = None
if acquired:
lock.release()
return ans
return wrapper
@_wrap_locked_api
def _switch(self):
def _install(etp_client, matches):
install = SoloInstall([])
inst_rc, _show_cfg_upd = install._install_action(
etp_client, True, True,
self.pretend, self.ask, self.verbose,
self.quiet, False, False, False, False, False,
False, False, 1, [], package_matches=list(matches))
if _show_cfg_upd:
install._show_config_files_update(etp_client)
install._show_preserved_libraries(etp_client)
if self.pretend:
# this won't trigger any post install action
return 1
return inst_rc
switcher = kswitch.KernelSwitcher(self._etp_client)
kernel_package = self.kernel
pkg_id, pkg_repo = self._etp_client.atom_match(kernel_package)
if pkg_id == -1:
print_error("%s: %s" % (
brown(_("Package does not exist")),
teal(kernel_package),))
return 1
kernel_match = (pkg_id, pkg_repo)
kernel_matches = switcher.list()
if kernel_match not in kernel_matches:
print_error(
"%s: %s" % (brown(_("Not a kernel")),
teal(kernel_package),))
return 1
try:
return switcher.switch(
kernel_match, _install,
from_running=self.from_running)
except kswitch.CannotFindRunningKernel:
print_error(
brown(_("Cannot find your currently running kernel.")))
print_error(
brown(_("Try without --from-running.")))
return 1
@_wrap_locked_api
def _list(self):
switcher = kswitch.KernelSwitcher(self._etp_client)
kernels = switcher.list()
if not kernels:
print_warning(_("No kernel packages found"))
return 1
inst_repo = self._etp_client.installed_repository()
with inst_repo.shared():
for pkg_id, pkg_repo in kernels:
repo = self._etp_client.open_repository(pkg_repo)
print_package_info(
pkg_id, self._etp_client, repo,
show_repo_if_quiet=True,
extended=self.verbose,
quiet=self.quiet)
return 0
def main(self, argv):
try:
self.parser.parse_args(argv[1:], namespace=self)
except IOError:
self.parser.print_help()
return 1
try:
if self.called_method is None:
self.parser.print_help()
rc = 1
elif self.called_method in (self._switch, self._list) and \
not entropy.tools.is_root():
print_error(
brown(_("superuser access required")))
rc = 1
else:
rc = self.called_method()
except KeyboardInterrupt:
rc = 1
return rc
if __name__ == "__main__":
app = SabayonSwitcher(
app_name=os.path.basename(sys.argv[0])
)
ret = app.main(sys.argv)
raise SystemExit(ret)