From patchwork Wed Apr 29 19:14:03 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Snow X-Patchwork-Id: 466240 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id E3236140307 for ; Thu, 30 Apr 2015 05:14:47 +1000 (AEST) Received: from localhost ([::1]:40620 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YnXRV-0002QF-On for incoming@patchwork.ozlabs.org; Wed, 29 Apr 2015 15:14:45 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37203) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YnXQw-0001Md-SY for qemu-devel@nongnu.org; Wed, 29 Apr 2015 15:14:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YnXQv-0003pd-Bk for qemu-devel@nongnu.org; Wed, 29 Apr 2015 15:14:10 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39225) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YnXQv-0003pU-5Y for qemu-devel@nongnu.org; Wed, 29 Apr 2015 15:14:09 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id CEACBA0E4A for ; Wed, 29 Apr 2015 19:14:08 +0000 (UTC) Received: from scv.usersys.redhat.com (dhcp-17-29.bos.redhat.com [10.18.17.29]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t3TJE50r011162; Wed, 29 Apr 2015 15:14:08 -0400 From: John Snow To: qemu-devel@nongnu.org Date: Wed, 29 Apr 2015 15:14:03 -0400 Message-Id: <1430334844-7015-4-git-send-email-jsnow@redhat.com> In-Reply-To: <1430334844-7015-1-git-send-email-jsnow@redhat.com> References: <1430334844-7015-1-git-send-email-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: John Snow , kchamart@redhat.com Subject: [Qemu-devel] [PATCH v4 3/4] scripts: qmp-shell: add transaction subshell X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add a special processing mode to craft transactions. By entering "transaction(" the shell will enter a special mode where each subsequent command will be saved as a transaction instead of executed as an individual command. The transaction can be submitted by entering ")" on a line by itself. Examples: Separate lines: (QEMU) transaction( TRANS> block-dirty-bitmap-add node=drive0 name=bitmap1 TRANS> block-dirty-bitmap-clear node=drive0 name=bitmap0 TRANS> ) With a transaction action included on the first line: (QEMU) transaction( block-dirty-bitmap-add node=drive0 name=bitmap2 TRANS> block-dirty-bitmap-add node=drive0 name=bitmap3 TRANS> ) As a one-liner, with just one transaction action: (QEMU) transaction( block-dirty-bitmap-add node=drive0 name=bitmap0 ) As a side-effect of this patch, blank lines are now parsed as no-ops, regardless of which shell mode you are in. Signed-off-by: John Snow Reviewed-by: Eric Blake --- scripts/qmp/qmp-shell | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell index 7f2c554..1df2ca7 100755 --- a/scripts/qmp/qmp-shell +++ b/scripts/qmp/qmp-shell @@ -73,6 +73,8 @@ class QMPShell(qmp.QEMUMonitorProtocol): self._greeting = None self._completer = None self._pp = pp + self._transmode = False + self._actions = list() def __get_address(self, arg): """ @@ -159,6 +161,36 @@ class QMPShell(qmp.QEMUMonitorProtocol): < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ] """ cmdargs = cmdline.split() + + # Transactional CLI entry/exit: + if cmdargs[0] == 'transaction(': + self._transmode = True + cmdargs.pop(0) + elif cmdargs[0] == ')' and self._transmode: + self._transmode = False + if len(cmdargs) > 1: + raise QMPShellError("Unexpected input after close of Transaction sub-shell") + qmpcmd = { 'execute': 'transaction', + 'arguments': { 'actions': self._actions } } + self._actions = list() + return qmpcmd + + # Nothing to process? + if not cmdargs: + return None + + # Parse and then cache this Transactional Action + if self._transmode: + finalize = False + action = { 'type': cmdargs[0], 'data': {} } + if cmdargs[-1] == ')': + cmdargs.pop(-1) + finalize = True + self.__cli_expr(cmdargs[1:], action['data']) + self._actions.append(action) + return self.__build_cmd(')') if finalize else None + + # Standard command: parse and return it to be executed. qmpcmd = { 'execute': cmdargs[0], 'arguments': {} } self.__cli_expr(cmdargs[1:], qmpcmd['arguments']) return qmpcmd @@ -171,6 +203,9 @@ class QMPShell(qmp.QEMUMonitorProtocol): print 'command format: ', print '[arg-name1=arg1] ... [arg-nameN=argN]' return True + # For transaction mode, we may have just cached the action: + if qmpcmd is None: + return True resp = self.cmd_obj(qmpcmd) if resp is None: print 'Disconnected' @@ -191,6 +226,11 @@ class QMPShell(qmp.QEMUMonitorProtocol): version = self._greeting['QMP']['version']['qemu'] print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro']) + def get_prompt(self): + if self._transmode: + return "TRANS> " + return "(QEMU) " + def read_exec_command(self, prompt): """ Read and execute a command. @@ -330,7 +370,7 @@ def main(): die('Could not connect to %s' % addr) qemu.show_banner() - while qemu.read_exec_command('(QEMU) '): + while qemu.read_exec_command(qemu.get_prompt()): pass qemu.close()