[Solo] implement the "solo {smart,pkg}" command.

This commit is contained in:
Fabio Erculiani
2012-09-30 19:00:58 +02:00
parent 4bcb12656e
commit 1b1bfcafa2
2 changed files with 510 additions and 11 deletions

510
client/solo/commands/pkg.py Normal file
View File

@@ -0,0 +1,510 @@
# -*- 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 argparse
import tempfile
import shutil
from entropy.const import etpConst, const_setup_directory, \
const_convert_to_unicode
from entropy.i18n import _
from entropy.output import darkgreen, teal, brown, purple, darkred, blue
import entropy.tools
import entropy.dep
from solo.commands.descriptor import SoloCommandDescriptor
from solo.commands.command import SoloCommand
class SoloPkg(SoloCommand):
"""
Main Solo Smart command.
"""
NAME = "pkg"
ALIASES = ["smart"]
ALLOW_UNPRIVILEGED = False
INTRODUCTION = """\
Execute advanced tasks on Entropy packages and the running system.
"""
SEE_ALSO = ""
def __init__(self, args):
SoloCommand.__init__(self, args)
self._nsargs = None
self._commands = {}
self._savedir = etpConst['entropyunpackdir']
self._ask = False
def man(self):
"""
Overridden from SoloCommand.
"""
return self._man()
def _get_parser(self):
"""
Overridden from SoloCommand.
"""
_commands = {}
descriptor = SoloCommandDescriptor.obtain_descriptor(
SoloPkg.NAME)
parser = argparse.ArgumentParser(
description=descriptor.get_description(),
formatter_class=argparse.RawDescriptionHelpFormatter,
prog="%s %s" % (sys.argv[0], SoloPkg.NAME))
subparsers = parser.add_subparsers(
title="action",
description=_("execute advanced tasks on packages"),
help=_("available commands"))
def _add_ask_to_parser(p):
p.add_argument(
"--ask", action="store_true",
default=self._ask,
help=_("ask before making any changes"))
def _argparse_easygoing_valid_entropy_path(string):
if os.path.isfile(string) and os.path.exists(string):
return string
msg = "%s: %s" % (
_("not a valid Entropy package file"),
string)
raise argparse.ArgumentTypeError(msg)
quickpkg_parser = subparsers.add_parser(
"quickpkg", help=_("generate packages from "
"the installed system"))
quickpkg_parser.add_argument(
"packages", nargs='+', metavar="<package>",
help=_("installed package name"))
quickpkg_parser.add_argument(
"--savedir", metavar="<path>",
type=self._argparse_is_valid_directory,
default=self._savedir,
help=_("destination directory "
"where to save generated packages"))
_add_ask_to_parser(quickpkg_parser)
quickpkg_parser.set_defaults(func=self._quickpkg)
_commands["quickpkg"] = {}
inflate_parser = subparsers.add_parser(
"inflate", help=_("transform SPM package files "
"into Entropy ones"))
inflate_parser.add_argument(
"files", nargs='+', metavar="<file>",
type=_argparse_easygoing_valid_entropy_path,
help=_("SPM package file path"))
inflate_parser.add_argument(
"--savedir", metavar="<path>",
type=self._argparse_is_valid_directory,
default=self._savedir,
help=_("destination directory "
"where to save generated packages"))
_add_ask_to_parser(inflate_parser)
inflate_parser.set_defaults(func=self._inflate)
_commands["inflate"] = {}
deflate_parser = subparsers.add_parser(
"deflate", help=_("transform Entropy package files "
"into SPM ones"))
deflate_parser.add_argument(
"files", nargs='+', metavar="<file>",
type=self._argparse_is_valid_entropy_package,
help=_("Entropy package file path"))
deflate_parser.add_argument(
"--savedir", metavar="<path>",
type=self._argparse_is_valid_directory,
default=self._savedir,
help=_("destination directory "
"where to save generated packages"))
_add_ask_to_parser(deflate_parser)
deflate_parser.set_defaults(func=self._deflate)
_commands["deflate"] = {}
extract_parser = subparsers.add_parser(
"extract", help=_("extract Entropy metadata "
"from Entropy packages"))
extract_parser.add_argument(
"files", nargs='+', metavar="<file>",
type=_argparse_easygoing_valid_entropy_path,
help=_("Entropy package file path"))
extract_parser.add_argument(
"--savedir", metavar="<path>",
type=self._argparse_is_valid_directory,
default=self._savedir,
help=_("destination directory "
"where to save generated packages"))
_add_ask_to_parser(extract_parser)
extract_parser.set_defaults(func=self._extract)
_commands["extract"] = {}
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.
"""
outcome = []
parser = self._get_parser()
# navigate through commands, finding the list of commands
if not self._args:
# show all the commands
outcome += sorted(self._commands.keys())
commands = self._commands
for index, item in enumerate(self._args):
if item in commands:
commands = self._commands[item]
if index == (len(self._args) - 1):
# if this is the last one, generate
# proper outcome elements.
outcome += sorted(commands.keys())
# reset last_arg so that outcome list
# won't be filtered
last_arg = ""
elif index == (len(self._args) - 1):
# if this is the last one, and item
# is not in commands, outcome becomes
# commands.keys()
outcome += sorted(commands.keys())
# no need to break here
else:
# item not in commands, but that's not the
# last one, we must generate proper outcome
# elements and stop right after
outcome += sorted(commands.keys())
break
return self._bashcomp(sys.stdout, last_arg, outcome)
def _scan_packages(self, entropy_client, packages, installed=False):
"""
Scan the list of package names filtering out unmatched
entries.
"""
found_pkgs = []
for package in packages:
if installed:
repo = entropy_client.installed_repository()
repo_id = repo.repository_id()
package_id, _pkg_rc = repo.atomMatch(package)
else:
package_id, repo_id = entropy_client.atom_match(package)
if package_id == -1:
mytxt = "!!! %s: %s %s." % (
purple(_("Warning")),
teal(const_convert_to_unicode(package)),
purple(_("is not available")),
)
entropy_client.output(
"!!!", level="warning", importance=1)
entropy_client.output(
mytxt, level="warning", importance=1)
entropy_client.output(
"!!!", level="warning", importance=1)
continue
found_pkgs.append((package_id, repo_id))
return found_pkgs
def _quickpkg(self, entropy_client):
"""
Solo Pkg Quickpkg command.
"""
packages = self._nsargs.packages
ask = self._ask
savedir = self._nsargs.savedir
if not os.path.isdir(savedir) and not os.path.exists(savedir):
# this is validated by the parser
# but not in case of no --savedir provided
const_setup_directory(savedir)
if not os.path.exists(savedir):
entropy_client.output(
"%s: %s" % (
brown(_("broken directory path")),
savedir,), level="error", importance=1)
return 1
entropy_repository = entropy_client.installed_repository()
pkg_matches = self._scan_packages(entropy_client, packages,
installed=True)
if not pkg_matches:
return 1
entropy_client.output(
"%s:" % (
brown(_("This is the list of packages "
"that would be considered")),
))
for pkg in pkg_matches:
pkg_id, pkg_repo = pkg
repo = entropy_client.open_repository(pkg_repo)
atom = repo.retrieveAtom(pkg_id)
entropy_client.output(
"[%s] %s" % (
brown(pkg_repo),
darkgreen(atom),),
header=" ")
if ask:
q_rc = entropy_client.ask_question(
_("Would you like to continue ?"))
if q_rc == _("No"):
return 0
for pkg in pkg_matches:
pkg_id, pkg_repo = pkg
repo = entropy_client.open_repository(pkg_repo)
atom = repo.retrieveAtom(pkg_id)
entropy_client.output(
"%s: %s" % (
teal(_("generating package")),
purple(atom),),
header=brown(" @@ "), back=True)
pkg_data = repo.getPackageData(pkg_id)
file_path = entropy_client.generate_package(
pkg_data, save_directory=savedir)
if file_path is None:
entropy_client.output(
"%s: %s" % (
darkred(_("package file creation error")),
blue(atom),),
level="error", importance=1)
return 3
entropy_client.output(
"[%s] %s: %s" % (
darkgreen(atom),
teal(_("package generated")),
purple(file_path),),
header=brown(" ## "))
return 0
def _inflate(self, entropy_client):
"""
Solo Pkg Inflate command.
"""
files = self._nsargs.files
ask = self._ask
savedir = self._nsargs.savedir
if not os.path.isdir(savedir) and not os.path.exists(savedir):
# this is validated by the parser
# but not in case of no --savedir provided
const_setup_directory(savedir)
if not os.path.exists(savedir):
entropy_client.output(
"%s: %s" % (
brown(_("broken directory path")),
savedir,), level="error", importance=1)
return 1
spm = entropy_client.Spm()
for _file in files:
entropy_client.output(
"%s: %s" % (
teal(_("working on package file")),
purple(_file)),
header=darkred(" @@ "),
back=True)
file_name = os.path.basename(_file)
package_path = os.path.join(savedir, file_name)
if os.path.realpath(_file) != os.path.realpath(package_path):
# make a copy first
shutil.copy2(_file, package_path)
pkg_data = spm.extract_package_metadata(package_path)
entropy_client.output(
"%s: %s" % (
teal(_("package file extraction complete")),
purple(package_path)),
header=darkred(" @@ "),
back=True)
# append development revision number
# and create final package file name
pkg_data['revision'] = etpConst['spmetprev']
download_dirpath = entropy.tools.create_package_dirpath(
pkg_data['branch'], nonfree=False, restricted=False)
download_name = entropy.dep.create_package_filename(
pkg_data['category'], pkg_data['name'],
pkg_data['version'], pkg_data['versiontag'],
ext=etpConst['packagesext'],
revision=pkg_data['revision'])
pkg_data['download'] = download_dirpath + "/" + download_name
# migrate to the proper format
final_path = os.path.join(savedir, download_name)
if package_path != final_path:
shutil.move(package_path, final_path)
package_path = final_path
tmp_fd, tmp_path = tempfile.mkstemp(
prefix="equo.smart.inflate.",
dir=savedir)
os.close(tmp_fd)
# attach entropy metadata to package file
repo = entropy_client.open_generic_repository(tmp_path)
repo.initializeRepository()
package_id = repo.addPackage(
pkg_data, revision=pkg_data['revision'])
repo.commit()
repo.close()
entropy_client.output(
"%s: %s" % (
teal(_("package metadata generation complete")),
purple(package_path)),
header=darkred(" @@ "),
back=True)
entropy.tools.aggregate_entropy_metadata(
package_path, tmp_path)
os.remove(tmp_path)
entropy_client.output(
"%s: %s" % (
teal(_("package file generated at")),
purple(package_path)),
header=darkred(" @@ "))
return 0
def _deflate(self, entropy_client):
"""
Solo Pkg Deflate command.
"""
files = self._nsargs.files
ask = self._ask
savedir = self._nsargs.savedir
if not os.path.isdir(savedir) and not os.path.exists(savedir):
# this is validated by the parser
# but not in case of no --savedir provided
const_setup_directory(savedir)
if not os.path.exists(savedir):
entropy_client.output(
"%s: %s" % (
brown(_("broken directory path")),
savedir,), level="error", importance=1)
return 1
for _file in files:
entropy_client.output(
"%s: %s" % (
teal(_("working on package file")),
purple(_file)),
header=darkred(" @@ "),
back=True)
file_name = os.path.basename(_file)
package_path = os.path.join(savedir, file_name)
ext_rc = entropy.tools.remove_entropy_metadata(
_file, package_path)
if not ext_rc:
entropy_client.output(
"%s: %s" % (
teal(_("error during metadata extraction")),
purple(_file)),
header=darkred(" @@ "),
level="error", importance=1)
return 1
entropy_client.output(
"%s: %s" % (
teal(_("package file generated")),
purple(package_path)),
header=darkred(" @@ "))
return 0
def _extract(self, entropy_client):
"""
Solo Pkg Extract command.
"""
files = self._nsargs.files
ask = self._ask
savedir = self._nsargs.savedir
if not os.path.isdir(savedir) and not os.path.exists(savedir):
# this is validated by the parser
# but not in case of no --savedir provided
const_setup_directory(savedir)
if not os.path.exists(savedir):
entropy_client.output(
"%s: %s" % (
brown(_("broken directory path")),
savedir,), level="error", importance=1)
return 1
for _file in files:
entropy_client.output(
"%s: %s" % (
teal(_("working on package file")),
purple(_file)),
header=darkred(" @@ "),
back=True)
file_name = os.path.basename(_file)
package_path = os.path.join(
savedir, file_name + ".db")
ext_rc = entropy.tools.dump_entropy_metadata(
_file, package_path)
if not ext_rc:
entropy_client.output(
"%s: %s" % (
teal(_("error during metadata extraction")),
purple(_file)),
header=darkred(" @@ "),
level="error", importance=1)
return 1
entropy_client.output(
"%s: %s" % (
teal(_("metadata file generated")),
purple(package_path)),
header=darkred(" @@ "))
return 0
SoloCommandDescriptor.register(
SoloCommandDescriptor(
SoloPkg,
SoloPkg.NAME,
_("execute advanced tasks on packages"))
)

View File

@@ -2,17 +2,6 @@ Backlog (raw)
1.0:
smart
package
quickpkg
--savedir
inflate
--savedir
deflate
--savedir
extract
--savedir
rescue
check
vacuum