Merge pull request #50 from Enlik/equo-mark
[solo.commands.mark] new command
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
equo-mark(1)
|
||||
============
|
||||
:man source: equo {equoversion}
|
||||
:man manual: equo {equoversion}
|
||||
|
||||
|
||||
NAME
|
||||
----
|
||||
equo-mark - set properties on installed packages
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
equo mark [-h] {auto,manual} ...
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
------------
|
||||
Set properties on installed packages
|
||||
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
"equo mark" supports the following options which alters its behaviour.
|
||||
|
||||
|
||||
OPTIONAL ARGUMENTS
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
*--help*::
|
||||
show this help message and exit
|
||||
|
||||
ACTION
|
||||
~~~~~~
|
||||
*auto*::
|
||||
mark package as installed to satisfy a dependency
|
||||
|
||||
*manual*::
|
||||
mark package as installed by user
|
||||
|
||||
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
Fabio Erculiani (lxnay@sabayon.org)
|
||||
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to https://bugs.sabayon.org or directly to the author at
|
||||
lxnay@sabayon.org.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
equo(1)
|
||||
@@ -68,6 +68,9 @@ COMMANDS
|
||||
*lxnay*::
|
||||
bow to lxnay
|
||||
|
||||
*mark*::
|
||||
set properties on installed packages
|
||||
|
||||
*mask*::
|
||||
mask one or more packages
|
||||
|
||||
@@ -117,7 +120,7 @@ COMMANDS
|
||||
unmask one or more packages
|
||||
|
||||
*unusedpackages [unused]*::
|
||||
look for unused packages (pay attention)
|
||||
show unused packages (pay attention)
|
||||
|
||||
*update [up]*::
|
||||
update repositories
|
||||
@@ -145,9 +148,9 @@ lxnay@sabayon.org.
|
||||
SEE ALSO
|
||||
--------
|
||||
equo-cache(1), equo-cleanup(1), equo-conf(1), equo-config(1), equo-deptest(1)
|
||||
equo-download(1), equo-hop(1), equo-install(1), equo-libtest(1), equo-mask(1)
|
||||
equo-match(1), equo-notice(1), equo-pkg(1), equo-preservedlibs(1), equo-query(1)
|
||||
equo-remove(1), equo-repo(1), equo-rescue(1), equo-search(1), equo-security(1)
|
||||
equo-source(1), equo-status(1), equo-ugc(1), equo-unmask(1), equo-unusedpackages(1)
|
||||
equo-update(1), equo-upgrade(1)
|
||||
equo-download(1), equo-hop(1), equo-install(1), equo-libtest(1), equo-mark(1)
|
||||
equo-mask(1), equo-match(1), equo-notice(1), equo-pkg(1), equo-preservedlibs(1)
|
||||
equo-query(1), equo-remove(1), equo-repo(1), equo-rescue(1), equo-search(1)
|
||||
equo-security(1), equo-source(1), equo-status(1), equo-ugc(1), equo-unmask(1)
|
||||
equo-unusedpackages(1), equo-update(1), equo-upgrade(1)
|
||||
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Slawomir Nizio <slawomir.nizio@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Slawomir Nizio
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Command Line Client}.
|
||||
|
||||
"""
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
from entropy.i18n import _
|
||||
from entropy.const import etpConst, const_convert_to_unicode
|
||||
from entropy.output import darkred, red, blue, brown, teal, purple
|
||||
|
||||
from solo.commands.descriptor import SoloCommandDescriptor
|
||||
from solo.commands.command import SoloCommand, exclusivelock
|
||||
|
||||
|
||||
class SoloMark(SoloCommand):
|
||||
"""
|
||||
Main Solo Mark command.
|
||||
"""
|
||||
|
||||
NAME = "mark"
|
||||
ALIASES = []
|
||||
ALLOW_UNPRIVILEGED = False
|
||||
|
||||
INTRODUCTION = """\
|
||||
Set properties on installed packages
|
||||
"""
|
||||
SEE_ALSO = ""
|
||||
|
||||
def __init__(self, args):
|
||||
SoloCommand.__init__(self, args)
|
||||
self._commands = {}
|
||||
|
||||
def man(self):
|
||||
"""
|
||||
Overridden from SoloCommand.
|
||||
"""
|
||||
return self._man()
|
||||
|
||||
def _get_parser(self):
|
||||
"""
|
||||
Overridden from SoloCommand.
|
||||
"""
|
||||
_commands = {}
|
||||
descriptor = SoloCommandDescriptor.obtain_descriptor(
|
||||
SoloMark.NAME)
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=descriptor.get_description(),
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
prog="%s %s" % (sys.argv[0], SoloMark.NAME))
|
||||
|
||||
subparsers = parser.add_subparsers(
|
||||
title="action",
|
||||
description=_("specify property to mark on a package"),
|
||||
help=_("available commands"))
|
||||
|
||||
def _add_standard_arguments(p, _cmd_dict):
|
||||
p.add_argument(
|
||||
"packages", nargs='+',
|
||||
metavar="<package>", help=_("package name"))
|
||||
|
||||
p.add_argument(
|
||||
"--pretend", "-p", action="store_true",
|
||||
default=False,
|
||||
help=_("show what would be done"))
|
||||
_cmd_dict["--pretend"] = {}
|
||||
_cmd_dict["-p"] = {}
|
||||
|
||||
p.add_argument(
|
||||
"--ignore-missing", action="store_true",
|
||||
default=False,
|
||||
help=_("ignore packages that are not installed on system"))
|
||||
_cmd_dict["--ignore-missing"] = {}
|
||||
|
||||
# It behaves differently than --multimatch from match.py,
|
||||
# thus a different name.
|
||||
p.add_argument(
|
||||
"--multiple-versions", action="store_true",
|
||||
default=False,
|
||||
help=_("allow matching multiple versions of a package"))
|
||||
_cmd_dict["--multiple-versions"] = {}
|
||||
|
||||
auto_parser = subparsers.add_parser(
|
||||
"auto",
|
||||
help=_("mark package as installed to satisfy a dependency"))
|
||||
_cmd_dict = {}
|
||||
_add_standard_arguments(auto_parser, _cmd_dict)
|
||||
auto_parser.set_defaults(func=self._auto)
|
||||
_commands["auto"] = _cmd_dict
|
||||
|
||||
manual_parser = subparsers.add_parser(
|
||||
"manual",
|
||||
help=_("mark package as installed by user"))
|
||||
_cmd_dict = {}
|
||||
_add_standard_arguments(manual_parser, _cmd_dict)
|
||||
manual_parser.set_defaults(func=self._manual)
|
||||
_commands["manual"] = _cmd_dict
|
||||
|
||||
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_exclusive, [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)
|
||||
|
||||
@exclusivelock
|
||||
def _auto(self, entropy_client, inst_repo):
|
||||
source_key = "automatic_dependency"
|
||||
return self._apply_source(
|
||||
entropy_client, inst_repo, source_key, **self._get_opts())
|
||||
|
||||
@exclusivelock
|
||||
def _manual(self, entropy_client, inst_repo):
|
||||
source_key = "user"
|
||||
return self._apply_source(
|
||||
entropy_client, inst_repo, source_key, **self._get_opts())
|
||||
|
||||
def _get_opts(self):
|
||||
opts = {
|
||||
'packages': self._nsargs.packages,
|
||||
'pretend': self._nsargs.pretend,
|
||||
'ignore_missing': self._nsargs.ignore_missing,
|
||||
'multiple_versions': self._nsargs.multiple_versions
|
||||
}
|
||||
return opts
|
||||
|
||||
def _apply_source(self, entropy_client, inst_repo,
|
||||
source_key, packages, pretend,
|
||||
ignore_missing, multiple_versions):
|
||||
|
||||
source = etpConst['install_sources'][source_key]
|
||||
|
||||
reverse_install_sources = {
|
||||
0: _("unknown"),
|
||||
1: _("manual"),
|
||||
2: _("dependency")
|
||||
}
|
||||
other_source = _("other")
|
||||
|
||||
source_txt = reverse_install_sources.get(source, other_source)
|
||||
|
||||
packages = entropy_client.packages_expand(packages)
|
||||
package_ids = {}
|
||||
|
||||
allfound = True
|
||||
for package in packages:
|
||||
if package in package_ids:
|
||||
continue
|
||||
pkg_ids, _rc = inst_repo.atomMatch(
|
||||
package, multiMatch=multiple_versions)
|
||||
|
||||
if not multiple_versions:
|
||||
pkg_ids = set([pkg_ids])
|
||||
|
||||
if _rc == 0:
|
||||
package_ids[package] = pkg_ids
|
||||
else:
|
||||
allfound = False
|
||||
entropy_client.output(
|
||||
"!!! %s: %s %s." % (
|
||||
purple(_("Warning")),
|
||||
teal(const_convert_to_unicode(package)),
|
||||
purple(_("is not installed")),
|
||||
))
|
||||
|
||||
if not allfound:
|
||||
entropy_client.output(
|
||||
darkred(_("Some packages were not found")),
|
||||
level="info" if ignore_missing else "error",
|
||||
importance=1)
|
||||
if not ignore_missing:
|
||||
return 1
|
||||
|
||||
for package in packages:
|
||||
if package not in package_ids:
|
||||
# Package was not found.
|
||||
continue
|
||||
|
||||
for pkg_id in package_ids[package]:
|
||||
|
||||
pkg_atom = inst_repo.retrieveAtom(pkg_id)
|
||||
current_source = inst_repo.getInstalledPackageSource(pkg_id)
|
||||
current_source_txt = reverse_install_sources.get(
|
||||
current_source, other_source)
|
||||
|
||||
if current_source == source:
|
||||
txt = "%s: %s" % (
|
||||
brown(pkg_atom),
|
||||
_("no change"))
|
||||
entropy_client.output(
|
||||
txt,
|
||||
header=blue(" @@ "))
|
||||
else:
|
||||
txt = "%s: %s => %s" % (
|
||||
brown(pkg_atom),
|
||||
current_source_txt,
|
||||
source_txt)
|
||||
entropy_client.output(
|
||||
txt,
|
||||
header=red(" !! "))
|
||||
|
||||
if not pretend:
|
||||
inst_repo.setInstalledPackageSource(pkg_id, source)
|
||||
|
||||
return 0
|
||||
|
||||
SoloCommandDescriptor.register(
|
||||
SoloCommandDescriptor(
|
||||
SoloMark,
|
||||
SoloMark.NAME,
|
||||
_("set properties on installed packages"))
|
||||
)
|
||||
@@ -4772,6 +4772,18 @@ class EntropyRepositoryBase(TextInterface, EntropyRepositoryPluginStore):
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def setInstalledPackageSource(self, package_id, source):
|
||||
"""
|
||||
Set package source. Please refer to I{getInstalledPackageSource()} for
|
||||
more details about this field.
|
||||
|
||||
@param package_id: package indentifier
|
||||
@type package_id: int
|
||||
@param source: install source identified
|
||||
@type slot: int
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def dropInstalledPackageFromStore(self, package_id):
|
||||
"""
|
||||
Note: this is used by installed packages repository (also known as
|
||||
|
||||
@@ -5059,6 +5059,14 @@ class EntropySQLRepository(EntropyRepositoryBase):
|
||||
return source[0]
|
||||
return None
|
||||
|
||||
def setInstalledPackageSource(self, package_id, source):
|
||||
"""
|
||||
Reimplemented from EntropyRepositoryBase.
|
||||
"""
|
||||
self._cursor().execute("""
|
||||
UPDATE installedtable SET source = ? WHERE idpackage = ?
|
||||
""", (source, package_id,))
|
||||
|
||||
def dropInstalledPackageFromStore(self, package_id):
|
||||
"""
|
||||
Reimplemented from EntropyRepositoryBase.
|
||||
|
||||
@@ -2329,6 +2329,15 @@ class EntropySQLiteRepository(EntropySQLRepository):
|
||||
del cached
|
||||
return obj
|
||||
|
||||
def setInstalledPackageSource(self, package_id, source):
|
||||
"""
|
||||
Reimplemented from EntropySQLRepository.
|
||||
We must handle live cache.
|
||||
"""
|
||||
super(EntropySQLiteRepository, self).setInstalledPackageSource(
|
||||
package_id, source)
|
||||
self._clearLiveCache("getInstalledPackageSource")
|
||||
|
||||
def dropInstalledPackageFromStore(self, package_id):
|
||||
"""
|
||||
Reimplemented from EntropySQLRepository.
|
||||
|
||||
Reference in New Issue
Block a user