From 30bd6815efbaf5bae70885feac9a35e149e2f1ad Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 29 Apr 2015 15:14:03 -0400 Subject: scripts: qmp-shell: add transaction subshell 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 Tested-by: Kashyap Chamarthy Signed-off-by: Luiz Capitulino --- scripts/qmp/qmp-shell | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'scripts/qmp') diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell index 7f2c554b47..1df2ca7eef 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() -- cgit v1.2.1