Files
entropy/server/eit/commands/pkgmove.py
2011-10-19 17:46:37 +02:00

213 lines
7.0 KiB
Python

# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Infrastructure Toolkit}.
"""
import sys
import os
import errno
import argparse
import tempfile
import codecs
import time
from entropy.i18n import _
from entropy.output import purple, teal
from eit.commands.descriptor import EitCommandDescriptor
from eit.commands.command import EitCommand
class EitPkgmove(EitCommand):
"""
Main Eit pkgmove command.
"""
NAME = "pkgmove"
ALIASES = []
def __init__(self, args):
EitCommand.__init__(self, args)
self._repository_id = None
def _get_parser(self):
""" Overridden from EitCommand """
descriptor = EitCommandDescriptor.obtain_descriptor(
EitPkgmove.NAME)
parser = argparse.ArgumentParser(
description=descriptor.get_description(),
formatter_class=argparse.RawDescriptionHelpFormatter,
prog="%s %s" % (sys.argv[0], EitPkgmove.NAME))
parser.add_argument("repo", default=None,
metavar="<repo>", help=_("repository"))
return parser
def parse(self):
parser = self._get_parser()
try:
nsargs = parser.parse_args(self._args)
except IOError:
return parser.print_help, []
self._repository_id = nsargs.repo
return self._call_locked, [self._pkgmove, self._repository_id]
def _pkgmove(self, entropy_server):
"""
Open $EDITOR and let user add/remove package moves.
"""
notice_text = """\
# This is the package move metadata for repository %s, read this:
# - the statements must start with either "move" or "slotmove".
# - move statement syntax:
# move <from package key> <to package key>
# - slotmove statement syntax:
# slotmove <package dependency> <from slot> <to slot>
# - the order of the statements is taken into consideration (KEPT!).
# - lines not starting with "move" or "slotmove" will be ignored.
# - any line starting with "#" will be ignored as well.
#
# Example:
# move app-foo/bar app-bar/foo
# slotmove >=x11-libs/foo-2.0 0 2.0
""" % (self._repository_id,)
tmp_path = None
repo = entropy_server.open_server_repository(
self._repository_id, read_only=False)
actions = repo.retrieveTreeUpdatesActions(self._repository_id)
new_actions = []
while True:
if tmp_path is None:
tmp_fd, tmp_path = tempfile.mkstemp(
prefix = 'entropy.server.pkgmove',
suffix = ".conf")
with os.fdopen(tmp_fd, "w") as tmp_f:
tmp_f.write(notice_text)
for action in actions:
tmp_f.write(action + "\n")
tmp_f.flush()
success = entropy_server.edit_file(tmp_path)
if not success:
# retry ?
os.remove(tmp_path)
return 1
del new_actions[:]
invalid_lines = []
with codecs.open(tmp_path, "r", encoding="utf-8") as tmp_f:
for line in tmp_f.readlines():
if line.startswith("#"):
# skip
continue
strip_line = line.strip()
if not strip_line:
# ignore
continue
if strip_line.startswith("move"):
split_line = strip_line.split()
if len(split_line) != 3:
entropy_server.output(
"%s: %s !!!" % (_("invalid line"), strip_line),
importance=1, level="warning")
invalid_lines.append(strip_line)
else:
new_actions.append(strip_line)
elif strip_line.startswith("slotmove"):
split_line = strip_line.split()
if len(split_line) != 4:
entropy_server.output(
"%s: %s !!!" % (
purple(_("invalid line")), strip_line),
importance=1, level="warning")
invalid_lines.append(strip_line)
else:
new_actions.append(strip_line)
else:
entropy_server.output(
"%s: %s !!!" % (
purple(_("invalid line")), strip_line),
importance=1, level="warning")
invalid_lines.append(strip_line)
if invalid_lines:
resp = entropy_server.ask_question(
_("Invalid syntax, what to do ?"),
responses=(_("Repeat"), _("Abort")))
if resp == _("Abort"):
os.remove(tmp_path)
return 1
else:
# repeat, edit same file
continue
# show submitted info
for action in new_actions:
entropy_server.output(action, level="generic")
entropy_server.output("", level="generic")
# ask confirmation
while True:
try:
rc_question = entropy_server.ask_question(
"[%s] %s" % (
purple(self._repository_id),
teal(_("Do you agree?"))
),
responses = (_("Yes"), _("Repeat"), _("No"),)
)
except KeyboardInterrupt:
# do not allow, we're in a critical region
continue
break
if rc_question == _("Yes"):
break
elif rc_question == _("No"):
return 1
# otherwise repeat everything again
# keep tmp_path
if tmp_path is not None:
try:
os.remove(tmp_path)
except (OSError) as err:
if err.errno != errno.ENOENT:
raise
# write new actions
branch = self._settings()['repositories']['branch']
actions_meta = []
cur_t = time.time()
# time is completely fake, no particular precision required
for action in new_actions:
cur_t += 1
actions_meta.append((action, branch, str(cur_t)))
repo.removeTreeUpdatesActions(self._repository_id)
try:
repo.insertTreeUpdatesActions(actions_meta, self._repository_id)
except Exception as err:
repo.rollback()
raise
repo.commit()
return 0
EitCommandDescriptor.register(
EitCommandDescriptor(
EitPkgmove,
EitPkgmove.NAME,
_('edit automatic package moves for repository'))
)