d6295b3e00
using /tmp as TMPDIR is a no go, since on modern systems, /tmp is on tmpfs with a very limited amount of fs size assigned. Use /var/tmp/entropy (or /var/tmp as fallback) instead.
898 lines
28 KiB
Python
898 lines
28 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 errno
|
|
import sys
|
|
import argparse
|
|
|
|
from entropy.i18n import _
|
|
from entropy.output import red, bold, brown, blue, darkred, darkgreen, \
|
|
purple, teal
|
|
from entropy.const import etpConst, const_mkstemp
|
|
from entropy.exceptions import SystemDatabaseError
|
|
from entropy.db.exceptions import OperationalError, DatabaseError
|
|
from entropy.client.interfaces.db import InstalledPackagesRepository
|
|
|
|
from solo.commands.descriptor import SoloCommandDescriptor
|
|
from solo.commands.command import SoloCommand
|
|
|
|
import entropy.tools
|
|
|
|
|
|
class SoloRescue(SoloCommand):
|
|
"""
|
|
Main Solo Rescue command.
|
|
"""
|
|
|
|
NAME = "rescue"
|
|
ALIASES = []
|
|
ALLOW_UNPRIVILEGED = False
|
|
|
|
INTRODUCTION = """\
|
|
Tools to rescue the running system.
|
|
"""
|
|
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(
|
|
SoloRescue.NAME)
|
|
parser = argparse.ArgumentParser(
|
|
description=descriptor.get_description(),
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
prog="%s %s" % (sys.argv[0], SoloRescue.NAME))
|
|
|
|
subparsers = parser.add_subparsers(
|
|
title="action",
|
|
description=_("execute advanced tasks on packages"),
|
|
help=_("available commands"))
|
|
|
|
def _add_ask_to_parser(p, _cmd_dict):
|
|
p.add_argument(
|
|
"--ask", "-a", action="store_true",
|
|
default=False,
|
|
help=_("ask before making any changes"))
|
|
_cmd_dict["--ask"] = {}
|
|
_cmd_dict["-a"] = {}
|
|
|
|
def _add_pretend_to_parser(p, _cmd_dict):
|
|
p.add_argument(
|
|
"--pretend", "-p", action="store_true",
|
|
default=False,
|
|
help=_("show what would be done"))
|
|
_cmd_dict["--pretend"] = {}
|
|
_cmd_dict["-p"] = {}
|
|
|
|
check_parser = subparsers.add_parser(
|
|
"check", help=_("check installed packages "
|
|
"repository for errors"))
|
|
check_parser.set_defaults(func=self._check)
|
|
_commands["check"] = {}
|
|
|
|
vacuum_parser = subparsers.add_parser(
|
|
"vacuum",
|
|
help=_("compact the installed packages repository"))
|
|
vacuum_parser.set_defaults(func=self._vacuum)
|
|
_commands["vacuum"] = {}
|
|
|
|
generate_parser = subparsers.add_parser(
|
|
"generate",
|
|
help=_("re-generate the installed packages repository"
|
|
" using the Source Package Manager"))
|
|
generate_parser.set_defaults(func=self._generate)
|
|
_commands["generate"] = {}
|
|
|
|
spmuids_parser = subparsers.add_parser(
|
|
"spmuids",
|
|
help=_("re-generate SPM<->Entropy package UIDs mapping"))
|
|
spmuids_parser.set_defaults(func=self._spmuids)
|
|
_commands["spmuids"] = {}
|
|
|
|
spmsync_parser = subparsers.add_parser(
|
|
"spmsync",
|
|
help=_("update Entropy installed packages repository "
|
|
"merging Source Package Manager changes"))
|
|
_cmd_dict = {}
|
|
_commands["spmsync"] = _cmd_dict
|
|
mg_group = spmsync_parser.add_mutually_exclusive_group()
|
|
_add_ask_to_parser(mg_group, _cmd_dict)
|
|
_add_pretend_to_parser(mg_group, _cmd_dict)
|
|
spmsync_parser.set_defaults(func=self._spmsync)
|
|
|
|
backup_parser = subparsers.add_parser(
|
|
"backup",
|
|
help=_("create a backup of the installed packages repository"))
|
|
backup_parser.set_defaults(func=self._backup)
|
|
_commands["backup"] = {}
|
|
|
|
restore_parser = subparsers.add_parser(
|
|
"restore",
|
|
help=_("restore a backup of the installed "
|
|
"packages repository"))
|
|
restore_parser.set_defaults(func=self._restore)
|
|
_commands["restore"] = {}
|
|
|
|
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, []
|
|
|
|
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
|
|
return self._hierarchical_bashcomp(last_arg, [], self._commands)
|
|
|
|
def _check_repository(self, entropy_client, repo):
|
|
"""
|
|
Sanity check the Installed Packages repository.
|
|
"""
|
|
try:
|
|
repo.validate()
|
|
repo.integrity_check()
|
|
except SystemDatabaseError as err:
|
|
entropy_client.output(
|
|
"%s: %s" % (
|
|
darkred(_("Repository error")),
|
|
err,),
|
|
level="warning"
|
|
)
|
|
return 1
|
|
|
|
entropy_client.output(
|
|
"%s: %s" % (
|
|
brown(_("Sanity Check")),
|
|
darkgreen(_("installed packages repository")),
|
|
),
|
|
importance=1,
|
|
level="info"
|
|
)
|
|
|
|
scanning_txt = _("Scanning...")
|
|
count = 0
|
|
length = 0
|
|
package_ids = None
|
|
|
|
try:
|
|
package_ids = repo.listAllPackageIds()
|
|
length = len(package_ids)
|
|
except DatabaseError as err:
|
|
entropy.tools.print_traceback()
|
|
entropy_client.output(
|
|
"%s: %s" % (
|
|
darkred(_("Error")),
|
|
err,
|
|
),
|
|
importance=1,
|
|
level="warning"
|
|
)
|
|
return 1
|
|
|
|
_errors = False
|
|
for package_id in package_ids:
|
|
count += 1
|
|
entropy_client.output(
|
|
darkgreen(scanning_txt),
|
|
level="info",
|
|
back=True,
|
|
count=(count, length),
|
|
percent=True
|
|
)
|
|
try:
|
|
repo.getPackageData(package_id)
|
|
except Exception as err:
|
|
entropy.tools.print_traceback()
|
|
entropy_client.output(
|
|
"%s: %s" % (
|
|
darkred(_("Error checking package")),
|
|
err,
|
|
),
|
|
level="warning"
|
|
)
|
|
_errors = True
|
|
|
|
if _errors:
|
|
entropy_client.output(
|
|
"%s: %s" % (
|
|
brown(_("Sanity Check")),
|
|
bold(_("corrupted"))),
|
|
importance=1,
|
|
level="warning"
|
|
)
|
|
return 1
|
|
|
|
entropy_client.output(
|
|
"%s: %s" % (
|
|
brown(_("Sanity Check")),
|
|
bold(_("passed"))),
|
|
importance=1,
|
|
level="info"
|
|
)
|
|
return 0
|
|
|
|
def _check(self, entropy_client):
|
|
"""
|
|
Solo Smart Check command.
|
|
"""
|
|
return self._check_repository(
|
|
entropy_client,
|
|
entropy_client.installed_repository())
|
|
|
|
def _vacuum(self, entropy_client):
|
|
"""
|
|
Solo Smart Vacuum command.
|
|
"""
|
|
inst_repo = entropy_client.installed_repository()
|
|
|
|
entropy_client.output(
|
|
"%s..." % (
|
|
brown(_("Compacting the Installed Packages repository")),
|
|
),
|
|
importance=1,
|
|
level="info",
|
|
header=darkgreen(" @@ "),
|
|
back=True
|
|
)
|
|
inst_repo.dropAllIndexes()
|
|
inst_repo.vacuum()
|
|
inst_repo.commit()
|
|
|
|
entropy_client.output(
|
|
"%s." % (
|
|
brown(_("Compaction complete")),
|
|
),
|
|
importance=1,
|
|
level="info",
|
|
header=darkgreen(" @@ ")
|
|
)
|
|
return 0
|
|
|
|
def _backup_repository(self, entropy_client, repo, path):
|
|
"""
|
|
Create a backup of the given Repository.
|
|
"""
|
|
if not os.path.isfile(path):
|
|
# return True if the repository is not available
|
|
return True, None
|
|
repo_dir = os.path.dirname(path)
|
|
|
|
# make sure to commit any transaction before backing-up
|
|
repo.commit()
|
|
backed_up, msg = entropy_client.backup_repository(
|
|
repo.repository_id(), repo_dir)
|
|
return backed_up, msg
|
|
|
|
def _generate(self, entropy_client):
|
|
"""
|
|
Solo Smart Generate command.
|
|
"""
|
|
mytxt = "%s: %s" % (
|
|
brown(_("Attention")),
|
|
darkred(_("the Installed Packages repository "
|
|
"will be re-generated using the "
|
|
"Source Package Manager")),
|
|
)
|
|
entropy_client.output(
|
|
mytxt,
|
|
level="warning",
|
|
importance=1)
|
|
|
|
mytxt = "%s: %s" % (
|
|
brown(_("Attention")),
|
|
darkred(_("I am not joking, this is quite disruptive")),
|
|
)
|
|
entropy_client.output(
|
|
mytxt,
|
|
level="warning",
|
|
importance=1)
|
|
|
|
rc = entropy_client.ask_question(
|
|
" %s" % (_("Understood ?"),))
|
|
if rc == _("No"):
|
|
return 1
|
|
rc = entropy_client.ask_question(
|
|
" %s" % (_("Really ?"),) )
|
|
if rc == _("No"):
|
|
return 1
|
|
rc = entropy_client.ask_question(
|
|
" %s. %s" % (
|
|
_("This is your last chance"),
|
|
_("Ok?"),)
|
|
)
|
|
if rc == _("No"):
|
|
return 1
|
|
|
|
# clean caches
|
|
spm = entropy_client.Spm()
|
|
entropy_client.clear_cache()
|
|
inst_repo = entropy_client.installed_repository()
|
|
|
|
# try to get a list of current package ids, if possible
|
|
try:
|
|
package_ids = inst_repo.listAllPackageIds()
|
|
except Exception as err:
|
|
entropy.tools.print_traceback()
|
|
entropy_client.output(
|
|
"%s: %s" % (
|
|
darkred(_("Cannot read metadata")),
|
|
err,
|
|
),
|
|
level="warning"
|
|
)
|
|
package_ids = []
|
|
|
|
# try to collect current installed revisions if possible
|
|
# and do the same for digest
|
|
revisions_match = {}
|
|
digest_match = {}
|
|
for package_id in package_ids:
|
|
try:
|
|
atom = inst_repo.retrieveAtom(
|
|
package_id)
|
|
revisions_match[atom] = inst_repo.retrieveRevision(
|
|
package_id)
|
|
digest_match[atom] = inst_repo.retrieveDigest(
|
|
package_id)
|
|
except Exception as err:
|
|
entropy.tools.print_traceback()
|
|
entropy_client.output(
|
|
"%s: %s" % (
|
|
darkred(_("Cannot read metadata")),
|
|
err,
|
|
),
|
|
level="warning"
|
|
)
|
|
|
|
repo_path = entropy_client.installed_repository_path()
|
|
entropy_client.output(
|
|
darkgreen(_("Creating a backup of the current repository")),
|
|
level="info",
|
|
importance=1,
|
|
header=darkred(" @@ "))
|
|
entropy_client.output(
|
|
repo_path,
|
|
header=" ")
|
|
|
|
backed_up, msg = self._backup_repository(
|
|
entropy_client, inst_repo, repo_path)
|
|
if not backed_up:
|
|
mytxt = "%s: %s" % (
|
|
darkred(_("Cannot backup the repository")),
|
|
brown("%s" % msg),)
|
|
entropy_client.output(
|
|
mytxt,
|
|
level="error",
|
|
importance=1,
|
|
header=darkred(" @@ "))
|
|
return 1
|
|
|
|
entropy_client.close_installed_repository()
|
|
# repository will be re-opened automagically
|
|
# at the next access.
|
|
try:
|
|
os.remove(repo_path)
|
|
except OSError as err:
|
|
if err.errno != errno.ENOENT:
|
|
mytxt = "%s: %s" % (
|
|
purple(_("Cannot delete old repository")),
|
|
brown("%s" % err),)
|
|
entropy_client.output(
|
|
mytxt,
|
|
level="warning",
|
|
importance=1,
|
|
header=darkred(" @@ "))
|
|
return 1
|
|
|
|
entropy_client.output(
|
|
purple(_("Initializing a new repository")),
|
|
importance=1,
|
|
header=darkred(" @@ "))
|
|
entropy_client.output(
|
|
brown(repo_path),
|
|
header=" ")
|
|
|
|
# open a repository at the old path, if repo_path is
|
|
# not in place, Entropy will forward us to the in-RAM
|
|
# database (for sqlite), which is not what we want.
|
|
gen_repo = entropy_client.open_generic_repository(
|
|
repo_path, dbname=InstalledPackagesRepository.NAME,
|
|
xcache=False, skip_checks=True)
|
|
gen_repo.initializeRepository()
|
|
gen_repo.commit()
|
|
gen_repo.close()
|
|
|
|
entropy_client.reopen_installed_repository()
|
|
inst_repo = entropy_client.installed_repository()
|
|
|
|
entropy_client.output(
|
|
purple(_("Repository initialized, generating metadata")),
|
|
importance=1,
|
|
header=darkred(" @@ "))
|
|
|
|
spm_packages = spm.get_installed_packages()
|
|
total = len(spm_packages)
|
|
count = 0
|
|
# perf: reuse temp file
|
|
tmp_fd, tmp_path = const_mkstemp(
|
|
prefix="equo.rescue.generate")
|
|
os.close(tmp_fd)
|
|
|
|
for spm_package in spm_packages:
|
|
count += 1
|
|
|
|
# make sure the file is empty
|
|
with open(tmp_path, "w") as tmp_f:
|
|
tmp_f.flush()
|
|
|
|
entropy_client.output(
|
|
teal(spm_package),
|
|
count=(count, total),
|
|
back=True,
|
|
header=brown(" @@ "))
|
|
|
|
appended = spm.append_metadata_to_package(
|
|
spm_package, tmp_path)
|
|
if not appended:
|
|
entropy_client.output(
|
|
"%s: %s" % (
|
|
purple(_("Invalid package")),
|
|
teal(spm_package),),
|
|
importance=1,
|
|
header=darkred(" @@ "))
|
|
continue
|
|
|
|
try:
|
|
data = spm.extract_package_metadata(tmp_path)
|
|
except Exception as err:
|
|
entropy.tools.print_traceback()
|
|
entropy_client.output(
|
|
"%s, %s: %s" % (
|
|
teal(spm_package),
|
|
purple(_("Metadata generation error")),
|
|
err,
|
|
),
|
|
level="warning",
|
|
importance=1,
|
|
header=darkred(" @@ ")
|
|
)
|
|
continue
|
|
|
|
# Try to see if it's possible to use
|
|
# the revision of a possible old db
|
|
data['revision'] = etpConst['spmetprev']
|
|
# create atom string
|
|
atom = entropy.dep.create_package_atom_string(
|
|
data['category'],
|
|
data['name'],
|
|
data['version'],
|
|
data['versiontag'])
|
|
|
|
# now see if a revision is available
|
|
saved_rev = revisions_match.get(atom)
|
|
if saved_rev is not None:
|
|
saved_rev = saved_rev
|
|
data['revision'] = saved_rev
|
|
|
|
# set digest to "0" to disable entropy dependencies
|
|
# calculation check that forces the pkg to
|
|
# be pulled in if digest differs from the one on the repo
|
|
saved_digest = digest_match.get(atom, "0")
|
|
data['digest'] = saved_digest
|
|
|
|
package_id = inst_repo.addPackage(data,
|
|
revision = data['revision'])
|
|
inst_repo.storeInstalledPackage(package_id,
|
|
etpConst['spmdbid'])
|
|
inst_repo.commit()
|
|
|
|
try:
|
|
os.remove(tmp_path)
|
|
except OSError:
|
|
pass
|
|
|
|
entropy_client.output(
|
|
purple(_("Indexing metadata, please wait...")),
|
|
header=darkgreen(" @@ "), back=True
|
|
)
|
|
inst_repo.createAllIndexes()
|
|
entropy_client.output(
|
|
purple(_("Repository metadata generation complete")),
|
|
header=darkgreen(" @@ ")
|
|
)
|
|
return 0
|
|
|
|
def _spmsync(self, entropy_client):
|
|
"""
|
|
Solo Smart Spmsync command.
|
|
"""
|
|
ask = self._nsargs.ask
|
|
pretend = self._nsargs.pretend
|
|
spm = entropy_client.Spm()
|
|
|
|
entropy_client.output(
|
|
"%s..." % (
|
|
teal(_("Scanning Source Package Manager repository")),),
|
|
header=brown(" @@ "),
|
|
back=True)
|
|
|
|
spm_packages = spm.get_installed_packages()
|
|
installed_packages = []
|
|
for spm_package in spm_packages:
|
|
|
|
try:
|
|
spm_package_id = spm.resolve_spm_package_uid(
|
|
spm_package)
|
|
except KeyError as err:
|
|
entropy_client.output(
|
|
"%s: %s, %s" % (
|
|
darkred(_("Cannot find package")),
|
|
purple(spm_package),
|
|
err,),
|
|
level="warning",
|
|
importance=1)
|
|
continue
|
|
|
|
installed_packages.append(
|
|
(spm_package, spm_package_id,))
|
|
|
|
entropy_client.output(
|
|
"%s..." % (
|
|
teal(_("Scanning Entropy repository")),),
|
|
header=brown(" @@ "),
|
|
back=True)
|
|
|
|
installed_spm_uids = set()
|
|
to_be_added = set()
|
|
to_be_removed = set()
|
|
inst_repo = entropy_client.installed_repository()
|
|
|
|
# collect new packages
|
|
for spm_package, spm_package_id in installed_packages:
|
|
installed_spm_uids.add(spm_package_id)
|
|
if not inst_repo.isSpmUidAvailable(spm_package_id):
|
|
to_be_added.add((spm_package, spm_package_id))
|
|
|
|
# do some memoization to speed up the scanning
|
|
_spm_key_slot_map = {}
|
|
for _spm_pkg, _spm_pkg_id in to_be_added:
|
|
key = entropy.dep.dep_getkey(_spm_pkg)
|
|
obj = _spm_key_slot_map.setdefault(key, set())
|
|
|
|
try:
|
|
slot = spm.get_installed_package_metadata(
|
|
_spm_pkg, "SLOT")
|
|
# workaround for ebuilds without SLOT
|
|
if slot is None:
|
|
slot = '0'
|
|
obj.add(slot)
|
|
except KeyError:
|
|
continue
|
|
|
|
# packages to be removed from the database
|
|
repo_spm_uids = inst_repo.listAllSpmUids()
|
|
for spm_package_id, package_id in repo_spm_uids:
|
|
# skip packages without valid counter
|
|
if spm_package_id < 0:
|
|
continue
|
|
|
|
if spm_package_id in installed_spm_uids:
|
|
# legit, package is still there, skipskipskip
|
|
continue
|
|
|
|
if not to_be_added:
|
|
# there is nothing to check in to_be_added
|
|
to_be_removed.add(package_id)
|
|
continue
|
|
|
|
atom = inst_repo.retrieveAtom(package_id)
|
|
add = True
|
|
if atom:
|
|
atomkey = entropy.dep.dep_getkey(atom)
|
|
atomslot = inst_repo.retrieveSlot(package_id)
|
|
|
|
spm_slots = _spm_key_slot_map.get(atomkey)
|
|
if spm_slots is not None:
|
|
if atomslot in spm_slots:
|
|
# do not add to to_be_removed
|
|
add = False
|
|
|
|
if add:
|
|
to_be_removed.add(package_id)
|
|
|
|
if not to_be_removed and not to_be_added:
|
|
entropy_client.output(
|
|
darkgreen(_("Nothing to do")),
|
|
importance=1)
|
|
return 0
|
|
|
|
if to_be_removed:
|
|
entropy_client.output(
|
|
"%s:" % (
|
|
purple(_("These packages were removed")),
|
|
),
|
|
importance=1,
|
|
header=brown(" @@ "))
|
|
|
|
broken = set()
|
|
for package_id in to_be_removed:
|
|
atom = inst_repo.retrieveAtom(package_id)
|
|
if not atom:
|
|
broken.add(package_id)
|
|
continue
|
|
|
|
entropy_client.output(
|
|
darkred(atom),
|
|
header=brown(" # "))
|
|
to_be_removed -= broken
|
|
|
|
if to_be_removed and not pretend:
|
|
rc = _("Yes")
|
|
accepted = True
|
|
if ask:
|
|
rc = entropy_client.ask_question(">> %s" % (
|
|
_("Continue ?"),))
|
|
if rc != _("Yes"):
|
|
accepted = False
|
|
|
|
if accepted:
|
|
counter = 0
|
|
total = len(to_be_removed)
|
|
for package_id in to_be_removed:
|
|
counter += 1
|
|
atom = inst_repo.retrieveAtom(package_id)
|
|
entropy_client.output(
|
|
teal(atom),
|
|
count=(counter, total),
|
|
header=darkred(" --- "))
|
|
|
|
inst_repo.removePackage(package_id)
|
|
|
|
inst_repo.commit()
|
|
entropy_client.output(
|
|
darkgreen(_("Removal complete")),
|
|
importance=1,
|
|
header=brown(" @@ "))
|
|
|
|
if to_be_added:
|
|
entropy_client.output(
|
|
"%s:" % (
|
|
purple(_("These packages were added")),
|
|
),
|
|
importance=1,
|
|
header=brown(" @@ "))
|
|
|
|
for _spm_package, _spm_package_id in to_be_added:
|
|
entropy_client.output(
|
|
darkgreen(_spm_package),
|
|
header=brown(" # "))
|
|
|
|
if to_be_added and not pretend:
|
|
|
|
if ask:
|
|
rc = entropy_client.ask_question(">> %s" % (
|
|
_("Continue ?"),) )
|
|
if rc != _("Yes"):
|
|
return 1
|
|
|
|
total = len(to_be_added)
|
|
counter = 0
|
|
# perf: only create temp file once
|
|
tmp_fd, tmp_path = const_mkstemp(
|
|
prefix="equo.rescue.spmsync")
|
|
os.close(tmp_fd)
|
|
|
|
for _spm_package, _spm_package_id in to_be_added:
|
|
counter += 1
|
|
entropy_client.output(
|
|
teal(_spm_package),
|
|
count=(counter, total),
|
|
header=darkgreen(" +++ "))
|
|
|
|
# make sure the file is empty
|
|
with open(tmp_path, "w") as tmp_f:
|
|
tmp_f.flush()
|
|
|
|
appended = spm.append_metadata_to_package(
|
|
_spm_package, tmp_path)
|
|
if not appended:
|
|
entropy_client.output(
|
|
"%s: %s" % (
|
|
purple(_("Invalid package")),
|
|
teal(_spm_package),),
|
|
importance=1,
|
|
header=darkred(" @@ "))
|
|
continue
|
|
|
|
# now extract info
|
|
try:
|
|
data = spm.extract_package_metadata(tmp_path)
|
|
except Exception as err:
|
|
entropy.tools.print_traceback()
|
|
entropy_client.output(
|
|
"%s, %s: %s" % (
|
|
teal(spm_package),
|
|
purple(_("Metadata generation error")),
|
|
err,
|
|
),
|
|
level="warning",
|
|
importance=1,
|
|
header=darkred(" @@ ")
|
|
)
|
|
continue
|
|
|
|
# create atom string
|
|
atom = entropy.dep.create_package_atom_string(
|
|
data['category'],
|
|
data['name'],
|
|
data['version'],
|
|
data['versiontag'])
|
|
|
|
# look for atom in client database
|
|
package_ids = inst_repo.getPackageIds(atom)
|
|
old_package_ids = sorted(package_ids)
|
|
try:
|
|
_package_id = old_package_ids.pop()
|
|
data['revision'] = inst_repo.retrieveRevision(
|
|
_package_id)
|
|
except IndexError:
|
|
data['revision'] = etpConst['spmetprev']
|
|
|
|
# cleanup stale info
|
|
if "original_repository" in data:
|
|
del data['original_repository']
|
|
|
|
new_package_id = inst_repo.handlePackage(
|
|
data, forcedRevision = data['revision'])
|
|
inst_repo.storeInstalledPackage(new_package_id,
|
|
etpConst['spmdbid'])
|
|
|
|
inst_repo.commit()
|
|
try:
|
|
os.remove(tmp_path)
|
|
except OSError:
|
|
pass
|
|
|
|
entropy_client.output(
|
|
darkgreen(_("Update complete")),
|
|
importance=1,
|
|
header=brown(" @@ "))
|
|
|
|
return 0
|
|
|
|
def _spmuids(self, entropy_client):
|
|
"""
|
|
Solo Smart Spmuids command.
|
|
"""
|
|
entropy_client.output(
|
|
"%s..." % (
|
|
purple(_("Re-generating packages mapping")),),
|
|
header=brown(" @@ "),
|
|
back=True)
|
|
|
|
inst_repo = entropy_client.installed_repository()
|
|
inst_repo.regenerateSpmUidMapping()
|
|
|
|
entropy_client.output(
|
|
"%s..." % (
|
|
purple(_("Packages mapping re-generated")),),
|
|
header=brown(" @@ "))
|
|
return 0
|
|
|
|
def _backup(self, entropy_client):
|
|
"""
|
|
Solo Smart Backup command.
|
|
"""
|
|
inst_repo = entropy_client.installed_repository()
|
|
path = entropy_client.installed_repository_path()
|
|
dir_path = os.path.dirname(path)
|
|
|
|
status, _err_msg = entropy_client.backup_repository(
|
|
inst_repo.repository_id(), dir_path)
|
|
if status:
|
|
return 0
|
|
return 1
|
|
|
|
def _restore(self, entropy_client):
|
|
"""
|
|
Solo Smart Restore command.
|
|
"""
|
|
inst_repo = entropy_client.installed_repository()
|
|
path = entropy_client.installed_repository_path()
|
|
|
|
repo_list = entropy_client.installed_repository_backups()
|
|
if not repo_list:
|
|
entropy_client.output(
|
|
darkred(_("No backups found")),
|
|
header=brown(" @@ "),
|
|
level="warning",
|
|
importance=1)
|
|
return 1
|
|
|
|
repo_list_new = []
|
|
repo_data = []
|
|
for repo_path in repo_list:
|
|
try:
|
|
ts = os.path.getmtime(repo_path)
|
|
except OSError as err:
|
|
entropy.tools.print_traceback()
|
|
continue
|
|
h_ts = entropy.tools.convert_unix_time_to_human_time(ts)
|
|
repo_list_new.append("[%s] %s" % (h_ts, repo_path,))
|
|
repo_data.append(repo_path)
|
|
|
|
def fake_cb(s):
|
|
return s
|
|
|
|
input_params = [
|
|
('db', ('combo', (_('Select the repository to restore'),
|
|
repo_list_new),), fake_cb, True)
|
|
]
|
|
|
|
while True:
|
|
data = entropy_client.input_box(
|
|
darkred(
|
|
_("Entropy Installed Packages Repository backups")),
|
|
input_params, cancel_button = True)
|
|
if data is None:
|
|
return 1
|
|
|
|
myid, dbx = data['db']
|
|
try:
|
|
backup_path = repo_data.pop(myid-1)
|
|
except IndexError:
|
|
continue
|
|
if not os.path.isfile(backup_path):
|
|
continue
|
|
break
|
|
|
|
inst_repo.commit()
|
|
status, err_msg = entropy_client.restore_repository(
|
|
backup_path, path, inst_repo.repository_id())
|
|
if status:
|
|
return 0
|
|
return 1
|
|
|
|
SoloCommandDescriptor.register(
|
|
SoloCommandDescriptor(
|
|
SoloRescue,
|
|
SoloRescue.NAME,
|
|
_("tools to rescue the running system"))
|
|
)
|