* [Qemu-devel] [PATCH v2 1/4] scripts: qmp-shell: refactor helpers
2015-04-22 16:21 [Qemu-devel] [PATCH v2 0/4] scripts: qmp-shell: add transaction support John Snow
@ 2015-04-22 16:21 ` John Snow
2015-04-22 16:21 ` [Qemu-devel] [PATCH v2 2/4] scripts: qmp-shell: Expand support for QMP expressions John Snow
` (3 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: John Snow @ 2015-04-22 16:21 UTC (permalink / raw)
To: qemu-devel; +Cc: John Snow, lcapitulino, kchamart
Refactor the qmp-shell command line processing function
into two components. This will be used to allow sub-expressions,
which will assist us in adding transactional support to qmp-shell.
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
scripts/qmp/qmp-shell | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index e0e848b..a9632ec 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -88,16 +88,8 @@ class QMPShell(qmp.QEMUMonitorProtocol):
# clearing everything as it doesn't seem to matter
readline.set_completer_delims('')
- def __build_cmd(self, cmdline):
- """
- Build a QMP input object from a user provided command-line in the
- following format:
-
- < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
- """
- cmdargs = cmdline.split()
- qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
- for arg in cmdargs[1:]:
+ def __cli_expr(self, tokens, parent):
+ for arg in tokens:
opt = arg.split('=')
try:
if(len(opt) > 2):
@@ -113,7 +105,6 @@ class QMPShell(qmp.QEMUMonitorProtocol):
else:
value = opt[1]
optpath = opt[0].split('.')
- parent = qmpcmd['arguments']
curpath = []
for p in optpath[:-1]:
curpath.append(p)
@@ -128,6 +119,17 @@ class QMPShell(qmp.QEMUMonitorProtocol):
else:
raise QMPShellError('Cannot set "%s" multiple times' % opt[0])
parent[optpath[-1]] = value
+
+ def __build_cmd(self, cmdline):
+ """
+ Build a QMP input object from a user provided command-line in the
+ following format:
+
+ < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
+ """
+ cmdargs = cmdline.split()
+ qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
+ self.__cli_expr(cmdargs[1:], qmpcmd['arguments'])
return qmpcmd
def _execute_cmd(self, cmdline):
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v2 2/4] scripts: qmp-shell: Expand support for QMP expressions
2015-04-22 16:21 [Qemu-devel] [PATCH v2 0/4] scripts: qmp-shell: add transaction support John Snow
2015-04-22 16:21 ` [Qemu-devel] [PATCH v2 1/4] scripts: qmp-shell: refactor helpers John Snow
@ 2015-04-22 16:21 ` John Snow
2015-04-22 16:41 ` John Snow
2015-04-22 17:18 ` Eric Blake
2015-04-22 16:21 ` [Qemu-devel] [PATCH v2 3/4] scripts: qmp-shell: add transaction subshell John Snow
` (2 subsequent siblings)
4 siblings, 2 replies; 11+ messages in thread
From: John Snow @ 2015-04-22 16:21 UTC (permalink / raw)
To: qemu-devel; +Cc: John Snow, lcapitulino, kchamart
This includes support for [] expressions, single-quotes in
QMP expressions (which is not strictly a part of JSON), and
the ability to use "True" or "False" literals instead of
JSON's lowercased 'true' and 'false' literals.
qmp-shell currently allows you to describe values as
JSON expressions:
key={"key":{"key2":"val"}}
But it does not currently support arrays, which are needed
for serializing and deserializing transactions:
key=[{"type":"drive-backup","data":{...}}]
qmp-shell also only currently accepts doubly quoted strings
as-per JSON spec, but QMP allows single quotes.
Lastly, python allows you to utilize "True" or "False" as
boolean literals, but JSON expects "true" or "false". Expand
qmp-shell to allow the user to type either, converting to the
correct type.
As a consequence of the above, the key=val parsing is also improved
to give better error messages if a key=val token is not provided.
CAVEAT: The parser is still extremely rudimentary and does not
expect to find spaces in {} nor [] expressions. This patch does
not improve this functionality.
Signed-off-by: John Snow <jsnow@redhat.com>
---
scripts/qmp/qmp-shell | 44 ++++++++++++++++++++++++++++----------------
1 file changed, 28 insertions(+), 16 deletions(-)
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index a9632ec..4cdcb6c 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -88,23 +88,35 @@ class QMPShell(qmp.QEMUMonitorProtocol):
# clearing everything as it doesn't seem to matter
readline.set_completer_delims('')
+ def __parse_value(self, val):
+ try:
+ return int(val)
+ except ValueError:
+ pass
+
+ if val.lower() == 'true':
+ return True
+ if val.lower() == 'false':
+ return False
+ if val.startswith(('{', '[')):
+ try:
+ return json.loads(val)
+ except ValueError:
+ pass
+ try:
+ return ast.literal_eval(val)
+ except SyntaxError:
+ pass
+ return val
+
def __cli_expr(self, tokens, parent):
for arg in tokens:
- opt = arg.split('=')
- try:
- if(len(opt) > 2):
- opt[1] = '='.join(opt[1:])
- value = int(opt[1])
- except ValueError:
- if opt[1] == 'true':
- value = True
- elif opt[1] == 'false':
- value = False
- elif opt[1].startswith('{'):
- value = json.loads(opt[1])
- else:
- value = opt[1]
- optpath = opt[0].split('.')
+ (key, _, val) = arg.partition('=')
+ if not val:
+ raise QMPShellError("Expected a key=value pair, got '%s'" % arg)
+
+ value = __parse_value(val)
+ optpath = key.split('.')
curpath = []
for p in optpath[:-1]:
curpath.append(p)
@@ -117,7 +129,7 @@ class QMPShell(qmp.QEMUMonitorProtocol):
if type(parent[optpath[-1]]) is dict:
raise QMPShellError('Cannot use "%s" as both leaf and non-leaf key' % '.'.join(curpath))
else:
- raise QMPShellError('Cannot set "%s" multiple times' % opt[0])
+ raise QMPShellError('Cannot set "%s" multiple times' % key)
parent[optpath[-1]] = value
def __build_cmd(self, cmdline):
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v2 2/4] scripts: qmp-shell: Expand support for QMP expressions
2015-04-22 16:21 ` [Qemu-devel] [PATCH v2 2/4] scripts: qmp-shell: Expand support for QMP expressions John Snow
@ 2015-04-22 16:41 ` John Snow
2015-04-22 17:18 ` Eric Blake
1 sibling, 0 replies; 11+ messages in thread
From: John Snow @ 2015-04-22 16:41 UTC (permalink / raw)
To: qemu-devel; +Cc: kchamart, lcapitulino
On 04/22/2015 12:21 PM, John Snow wrote:
> This includes support for [] expressions, single-quotes in
> QMP expressions (which is not strictly a part of JSON), and
> the ability to use "True" or "False" literals instead of
> JSON's lowercased 'true' and 'false' literals.
>
> qmp-shell currently allows you to describe values as
> JSON expressions:
> key={"key":{"key2":"val"}}
>
> But it does not currently support arrays, which are needed
> for serializing and deserializing transactions:
> key=[{"type":"drive-backup","data":{...}}]
>
> qmp-shell also only currently accepts doubly quoted strings
> as-per JSON spec, but QMP allows single quotes.
>
> Lastly, python allows you to utilize "True" or "False" as
> boolean literals, but JSON expects "true" or "false". Expand
> qmp-shell to allow the user to type either, converting to the
> correct type.
>
> As a consequence of the above, the key=val parsing is also improved
> to give better error messages if a key=val token is not provided.
>
> CAVEAT: The parser is still extremely rudimentary and does not
> expect to find spaces in {} nor [] expressions. This patch does
> not improve this functionality.
>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
> scripts/qmp/qmp-shell | 44 ++++++++++++++++++++++++++++----------------
> 1 file changed, 28 insertions(+), 16 deletions(-)
>
Left a line dangling in my local tree by accident:
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index 4cdcb6c..e7b40eb 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -32,6 +32,7 @@
import qmp
import json
+import ast
import readline
import sys
import pprint
> diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
> index a9632ec..4cdcb6c 100755
> --- a/scripts/qmp/qmp-shell
> +++ b/scripts/qmp/qmp-shell
> @@ -88,23 +88,35 @@ class QMPShell(qmp.QEMUMonitorProtocol):
> # clearing everything as it doesn't seem to matter
> readline.set_completer_delims('')
>
> + def __parse_value(self, val):
> + try:
> + return int(val)
> + except ValueError:
> + pass
> +
> + if val.lower() == 'true':
> + return True
> + if val.lower() == 'false':
> + return False
> + if val.startswith(('{', '[')):
> + try:
> + return json.loads(val)
> + except ValueError:
> + pass
> + try:
> + return ast.literal_eval(val)
> + except SyntaxError:
> + pass
> + return val
> +
> def __cli_expr(self, tokens, parent):
> for arg in tokens:
> - opt = arg.split('=')
> - try:
> - if(len(opt) > 2):
> - opt[1] = '='.join(opt[1:])
> - value = int(opt[1])
> - except ValueError:
> - if opt[1] == 'true':
> - value = True
> - elif opt[1] == 'false':
> - value = False
> - elif opt[1].startswith('{'):
> - value = json.loads(opt[1])
> - else:
> - value = opt[1]
> - optpath = opt[0].split('.')
> + (key, _, val) = arg.partition('=')
> + if not val:
> + raise QMPShellError("Expected a key=value pair, got '%s'" % arg)
> +
> + value = __parse_value(val)
> + optpath = key.split('.')
> curpath = []
> for p in optpath[:-1]:
> curpath.append(p)
> @@ -117,7 +129,7 @@ class QMPShell(qmp.QEMUMonitorProtocol):
> if type(parent[optpath[-1]]) is dict:
> raise QMPShellError('Cannot use "%s" as both leaf and non-leaf key' % '.'.join(curpath))
> else:
> - raise QMPShellError('Cannot set "%s" multiple times' % opt[0])
> + raise QMPShellError('Cannot set "%s" multiple times' % key)
> parent[optpath[-1]] = value
>
> def __build_cmd(self, cmdline):
>
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v2 2/4] scripts: qmp-shell: Expand support for QMP expressions
2015-04-22 16:21 ` [Qemu-devel] [PATCH v2 2/4] scripts: qmp-shell: Expand support for QMP expressions John Snow
2015-04-22 16:41 ` John Snow
@ 2015-04-22 17:18 ` Eric Blake
2015-04-22 17:25 ` Eric Blake
2015-04-22 17:33 ` John Snow
1 sibling, 2 replies; 11+ messages in thread
From: Eric Blake @ 2015-04-22 17:18 UTC (permalink / raw)
To: John Snow, qemu-devel; +Cc: lcapitulino, kchamart
[-- Attachment #1: Type: text/plain, Size: 4028 bytes --]
On 04/22/2015 10:21 AM, John Snow wrote:
> This includes support for [] expressions, single-quotes in
> QMP expressions (which is not strictly a part of JSON), and
> the ability to use "True" or "False" literals instead of
> JSON's lowercased 'true' and 'false' literals.
>
> qmp-shell currently allows you to describe values as
> JSON expressions:
> key={"key":{"key2":"val"}}
>
> But it does not currently support arrays, which are needed
> for serializing and deserializing transactions:
> key=[{"type":"drive-backup","data":{...}}]
>
> qmp-shell also only currently accepts doubly quoted strings
> as-per JSON spec, but QMP allows single quotes.
>
> Lastly, python allows you to utilize "True" or "False" as
> boolean literals, but JSON expects "true" or "false". Expand
> qmp-shell to allow the user to type either, converting to the
> correct type.
Well, when easy to do. See below for more discussion...
>
> As a consequence of the above, the key=val parsing is also improved
> to give better error messages if a key=val token is not provided.
>
> CAVEAT: The parser is still extremely rudimentary and does not
> expect to find spaces in {} nor [] expressions. This patch does
> not improve this functionality.
If someone cares about this, they can fix it later. As I said in the v1
review, qmp-shell is mostly for debugging and testsuites, and we can
live with the caveats for now.
>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
> scripts/qmp/qmp-shell | 44 ++++++++++++++++++++++++++++----------------
> 1 file changed, 28 insertions(+), 16 deletions(-)
As far as I can tell, this makes qmp-shell strictly more useful, so I
have no qualms giving:
Reviewed-by: Eric Blake <eblake@redhat.com>
>
> diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
> index a9632ec..4cdcb6c 100755
> --- a/scripts/qmp/qmp-shell
> +++ b/scripts/qmp/qmp-shell
> @@ -88,23 +88,35 @@ class QMPShell(qmp.QEMUMonitorProtocol):
> # clearing everything as it doesn't seem to matter
> readline.set_completer_delims('')
>
> + def __parse_value(self, val):
> + try:
> + return int(val)
> + except ValueError:
> + pass
> +
> + if val.lower() == 'true':
> + return True
> + if val.lower() == 'false':
> + return False
...as promised earlier,
This allows param=tRuE (neither JSON nor Python), but that's a minor
price to pay to get both param=true (param=JSON style) and param=True
(param=Python style) to work. Meanwhile...
> + if val.startswith(('{', '[')):
> + try:
> + return json.loads(val)
This statement accepts param=JSON style, as in:
param={ "foo":true }
but it rejects (as invalid JSON):
param={ 'foo':true }
param={ "foo":True }
param={ 'foo':True }
> + except ValueError:
> + pass
> + try:
> + return ast.literal_eval(val)
And this statement accepts param=Python style, as in:
param={ "foo":True }
param={ 'foo':True }
but it rejects (as invalid Python):
param={ "foo":true }
param={ 'foo':true }
Of those four combinations, QMP accepts:
param={ "foo":true }
param={ 'foo':true }
while rejecting:
param={ "foo":True }
param={ 'foo':True }
So among the four combinations of single/double quoting vs upper/lower
casing of boolean literals, qmp-shell now accepts three variants, but we
have a case that QMP accepts but qmp-shell rejects (single quotes mixed
with lower-case true).
Not the end of the world (again, if someone wants all four cases to work
in qmp-shell and/or QMP proper, they can provide a patch later to
further enhance things). But maybe worth expanding that CAVEAT in the
commit message to acknowledge the issues.
At any rate, doesn't affect my R-b given above.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v2 2/4] scripts: qmp-shell: Expand support for QMP expressions
2015-04-22 17:18 ` Eric Blake
@ 2015-04-22 17:25 ` Eric Blake
2015-04-22 17:33 ` John Snow
1 sibling, 0 replies; 11+ messages in thread
From: Eric Blake @ 2015-04-22 17:25 UTC (permalink / raw)
To: John Snow, qemu-devel; +Cc: kchamart, lcapitulino
[-- Attachment #1: Type: text/plain, Size: 847 bytes --]
On 04/22/2015 11:18 AM, Eric Blake wrote:
> On 04/22/2015 10:21 AM, John Snow wrote:
>> This includes support for [] expressions, single-quotes in
>> QMP expressions (which is not strictly a part of JSON), and
>> the ability to use "True" or "False" literals instead of
>> JSON's lowercased 'true' and 'false' literals.
>>
>>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>> scripts/qmp/qmp-shell | 44 ++++++++++++++++++++++++++++----------------
>> 1 file changed, 28 insertions(+), 16 deletions(-)
>
> As far as I can tell, this makes qmp-shell strictly more useful, so I
> have no qualms giving:
>
> Reviewed-by: Eric Blake <eblake@redhat.com>
When combined with your one-line touchup, of course.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v2 2/4] scripts: qmp-shell: Expand support for QMP expressions
2015-04-22 17:18 ` Eric Blake
2015-04-22 17:25 ` Eric Blake
@ 2015-04-22 17:33 ` John Snow
1 sibling, 0 replies; 11+ messages in thread
From: John Snow @ 2015-04-22 17:33 UTC (permalink / raw)
To: Eric Blake, qemu-devel; +Cc: kchamart, lcapitulino
On 04/22/2015 01:18 PM, Eric Blake wrote:
> On 04/22/2015 10:21 AM, John Snow wrote:
>> This includes support for [] expressions, single-quotes in
>> QMP expressions (which is not strictly a part of JSON), and
>> the ability to use "True" or "False" literals instead of
>> JSON's lowercased 'true' and 'false' literals.
>>
>> qmp-shell currently allows you to describe values as
>> JSON expressions:
>> key={"key":{"key2":"val"}}
>>
>> But it does not currently support arrays, which are needed
>> for serializing and deserializing transactions:
>> key=[{"type":"drive-backup","data":{...}}]
>>
>> qmp-shell also only currently accepts doubly quoted strings
>> as-per JSON spec, but QMP allows single quotes.
>>
>> Lastly, python allows you to utilize "True" or "False" as
>> boolean literals, but JSON expects "true" or "false". Expand
>> qmp-shell to allow the user to type either, converting to the
>> correct type.
>
> Well, when easy to do. See below for more discussion...
>
>>
>> As a consequence of the above, the key=val parsing is also improved
>> to give better error messages if a key=val token is not provided.
>>
>> CAVEAT: The parser is still extremely rudimentary and does not
>> expect to find spaces in {} nor [] expressions. This patch does
>> not improve this functionality.
>
> If someone cares about this, they can fix it later. As I said in the v1
> review, qmp-shell is mostly for debugging and testsuites, and we can
> live with the caveats for now.
>
>>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>> scripts/qmp/qmp-shell | 44 ++++++++++++++++++++++++++++----------------
>> 1 file changed, 28 insertions(+), 16 deletions(-)
>
> As far as I can tell, this makes qmp-shell strictly more useful, so I
> have no qualms giving:
>
> Reviewed-by: Eric Blake <eblake@redhat.com>
>
>>
>> diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
>> index a9632ec..4cdcb6c 100755
>> --- a/scripts/qmp/qmp-shell
>> +++ b/scripts/qmp/qmp-shell
>> @@ -88,23 +88,35 @@ class QMPShell(qmp.QEMUMonitorProtocol):
>> # clearing everything as it doesn't seem to matter
>> readline.set_completer_delims('')
>>
>> + def __parse_value(self, val):
>> + try:
>> + return int(val)
>> + except ValueError:
>> + pass
>> +
>> + if val.lower() == 'true':
>> + return True
>> + if val.lower() == 'false':
>> + return False
>
> ...as promised earlier,
>
> This allows param=tRuE (neither JSON nor Python), but that's a minor
> price to pay to get both param=true (param=JSON style) and param=True
> (param=Python style) to work. Meanwhile...
>
>> + if val.startswith(('{', '[')):
>> + try:
>> + return json.loads(val)
>
> This statement accepts param=JSON style, as in:
> param={ "foo":true }
> but it rejects (as invalid JSON):
> param={ 'foo':true }
> param={ "foo":True }
> param={ 'foo':True }
>
>> + except ValueError:
>> + pass
>> + try:
>> + return ast.literal_eval(val)
>
> And this statement accepts param=Python style, as in:
> param={ "foo":True }
> param={ 'foo':True }
> but it rejects (as invalid Python):
> param={ "foo":true }
> param={ 'foo':true }
>
> Of those four combinations, QMP accepts:
> param={ "foo":true }
> param={ 'foo':true }
> while rejecting:
> param={ "foo":True }
> param={ 'foo':True }
>
> So among the four combinations of single/double quoting vs upper/lower
> casing of boolean literals, qmp-shell now accepts three variants, but we
> have a case that QMP accepts but qmp-shell rejects (single quotes mixed
> with lower-case true).
>
> Not the end of the world (again, if someone wants all four cases to work
> in qmp-shell and/or QMP proper, they can provide a patch later to
> further enhance things). But maybe worth expanding that CAVEAT in the
> commit message to acknowledge the issues.
>
> At any rate, doesn't affect my R-b given above.
>
Yes, unfortunately the object literals still must comply with some sort
of standard, neither of which is truly QMP: They must either be Python
or JSON.
key=val pairs can/will accept true/TRUE/tRuE etc as well, which I think
is probably acceptable since that falls within the realm of "qmp-shell
syntax" which doesn't necessarily have to maintain similarities to
JSON/QMP/etc. I could probably go back and adjust it to just lowercase
the first letter, but this is probably only ever going to be a typo
(which we can unambiguously resolve) and the generated QMP (if -v is
present) will of course appear correctly formatted.
GIQO: Garbage in, QMP out? :)
I will author an additional patch as an add-on a bit later that
documents all the quirks to help improve the usability of this little tool.
Probably I'll also update the QMP banner to display a quick help message.
Thank you,
--John
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v2 3/4] scripts: qmp-shell: add transaction subshell
2015-04-22 16:21 [Qemu-devel] [PATCH v2 0/4] scripts: qmp-shell: add transaction support John Snow
2015-04-22 16:21 ` [Qemu-devel] [PATCH v2 1/4] scripts: qmp-shell: refactor helpers John Snow
2015-04-22 16:21 ` [Qemu-devel] [PATCH v2 2/4] scripts: qmp-shell: Expand support for QMP expressions John Snow
@ 2015-04-22 16:21 ` John Snow
2015-04-22 16:21 ` [Qemu-devel] [PATCH v2 4/4] scripts: qmp-shell: Add verbose flag John Snow
2015-04-22 19:27 ` [Qemu-devel] [PATCH v2 0/4] scripts: qmp-shell: add transaction support John Snow
4 siblings, 0 replies; 11+ messages in thread
From: John Snow @ 2015-04-22 16:21 UTC (permalink / raw)
To: qemu-devel; +Cc: John Snow, lcapitulino, kchamart
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 <jsnow@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
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 4cdcb6c..3fffe15 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -59,6 +59,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):
"""
@@ -140,6 +142,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 cmdargs:
+ 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
@@ -152,6 +184,9 @@ class QMPShell(qmp.QEMUMonitorProtocol):
print 'command format: <command-name> ',
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'
@@ -172,6 +207,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.
@@ -311,7 +351,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()
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v2 4/4] scripts: qmp-shell: Add verbose flag
2015-04-22 16:21 [Qemu-devel] [PATCH v2 0/4] scripts: qmp-shell: add transaction support John Snow
` (2 preceding siblings ...)
2015-04-22 16:21 ` [Qemu-devel] [PATCH v2 3/4] scripts: qmp-shell: add transaction subshell John Snow
@ 2015-04-22 16:21 ` John Snow
2015-04-22 19:27 ` [Qemu-devel] [PATCH v2 0/4] scripts: qmp-shell: add transaction support John Snow
4 siblings, 0 replies; 11+ messages in thread
From: John Snow @ 2015-04-22 16:21 UTC (permalink / raw)
To: qemu-devel; +Cc: John Snow, lcapitulino, kchamart
Add a verbose flag that shows the QMP command that was
constructed, to allow for later copy/pasting, reference,
debugging, etc.
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
scripts/qmp/qmp-shell | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index 3fffe15..213f515 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -176,6 +176,12 @@ class QMPShell(qmp.QEMUMonitorProtocol):
self.__cli_expr(cmdargs[1:], qmpcmd['arguments'])
return qmpcmd
+ def _print(self, qmp):
+ if self._pp is not None:
+ self._pp.pprint(qmp)
+ else:
+ print qmp
+
def _execute_cmd(self, cmdline):
try:
qmpcmd = self.__build_cmd(cmdline)
@@ -187,15 +193,13 @@ class QMPShell(qmp.QEMUMonitorProtocol):
# For transaction mode, we may have just cached the action:
if qmpcmd is None:
return True
+ if self._verbose:
+ self._print(qmpcmd)
resp = self.cmd_obj(qmpcmd)
if resp is None:
print 'Disconnected'
return False
-
- if self._pp is not None:
- self._pp.pprint(resp)
- else:
- print resp
+ self._print(resp)
return True
def connect(self):
@@ -231,6 +235,9 @@ class QMPShell(qmp.QEMUMonitorProtocol):
else:
return self._execute_cmd(cmdline)
+ def set_verbosity(self, verbose):
+ self._verbose = verbose
+
class HMPShell(QMPShell):
def __init__(self, address):
QMPShell.__init__(self, address)
@@ -316,6 +323,7 @@ def main():
qemu = None
hmp = False
pp = None
+ verbose = False
try:
for arg in sys.argv[1:]:
@@ -327,6 +335,8 @@ def main():
if pp is not None:
fail_cmdline(arg)
pp = pprint.PrettyPrinter(indent=4)
+ elif arg == "-v":
+ verbose = True
else:
if qemu is not None:
fail_cmdline(arg)
@@ -351,6 +361,7 @@ def main():
die('Could not connect to %s' % addr)
qemu.show_banner()
+ qemu.set_verbosity(verbose)
while qemu.read_exec_command(qemu.get_prompt()):
pass
qemu.close()
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v2 0/4] scripts: qmp-shell: add transaction support
2015-04-22 16:21 [Qemu-devel] [PATCH v2 0/4] scripts: qmp-shell: add transaction support John Snow
` (3 preceding siblings ...)
2015-04-22 16:21 ` [Qemu-devel] [PATCH v2 4/4] scripts: qmp-shell: Add verbose flag John Snow
@ 2015-04-22 19:27 ` John Snow
2015-04-23 13:11 ` Luiz Capitulino
4 siblings, 1 reply; 11+ messages in thread
From: John Snow @ 2015-04-22 19:27 UTC (permalink / raw)
To: qemu-devel; +Cc: kchamart, lcapitulino
On 04/22/2015 12:21 PM, John Snow wrote:
> The qmp-shell is a little rudimentary, but it can be hacked
> to give us some transactional support without too much difficulty.
>
> (1) Prep.
> (2) Add support for serializing json arrays
> (3) Allow users to use 'single quotes' instead of "double quotes"
> (4) Add a special transaction( ... ) syntax that lets users
> build up transactional commands using the existing qmp shell
> syntax to define each action.
> (5) Add a verbose flag to display generated QMP commands.
>
> The parsing is not as robust as one would like, but this suffices
> without adding a proper parser.
>
> Design considerations:
>
> (1) Try not to disrupt the existing design of the qmp-shell. The existing
> API is not disturbed.
>
> (2) Pick a "magic token" such that it could not be confused for legitimate
> QMP/JSON syntax. Parentheses are used for this purpose.
>
> ===
> v2:
> ===
>
> - Squash patches 2 & 3:
> - Remove wholesale replacement of single quotes, in favor of try blocks
> that attempt to parse as pure JSON, then as Python.
> - Factored out the value parser block to accomplish the above.
> - Allow both true/True and false/False for values.
> - Fix typo in patch 3 cover letter. (was patch 4.)
>
> John Snow (4):
> scripts: qmp-shell: refactor helpers
> scripts: qmp-shell: Expand support for QMP expressions
> scripts: qmp-shell: add transaction subshell
> scripts: qmp-shell: Add verbose flag
>
> scripts/qmp/qmp-shell | 125 ++++++++++++++++++++++++++++++++++++++------------
> 1 file changed, 95 insertions(+), 30 deletions(-)
>
Version "2+" with the hotfix added, with R-B's added:
https://github.com/jnsnow/qemu/commits/qmp-shell-plus
To whomever would pull this into their tree: Let me know if you prefer I
send a "v3" instead.
Thanks,
--John
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v2 0/4] scripts: qmp-shell: add transaction support
2015-04-22 19:27 ` [Qemu-devel] [PATCH v2 0/4] scripts: qmp-shell: add transaction support John Snow
@ 2015-04-23 13:11 ` Luiz Capitulino
0 siblings, 0 replies; 11+ messages in thread
From: Luiz Capitulino @ 2015-04-23 13:11 UTC (permalink / raw)
To: John Snow; +Cc: qemu-devel, kchamart
On Wed, 22 Apr 2015 15:27:17 -0400
John Snow <jsnow@redhat.com> wrote:
>
>
> On 04/22/2015 12:21 PM, John Snow wrote:
> > The qmp-shell is a little rudimentary, but it can be hacked
> > to give us some transactional support without too much difficulty.
> >
> > (1) Prep.
> > (2) Add support for serializing json arrays
> > (3) Allow users to use 'single quotes' instead of "double quotes"
> > (4) Add a special transaction( ... ) syntax that lets users
> > build up transactional commands using the existing qmp shell
> > syntax to define each action.
> > (5) Add a verbose flag to display generated QMP commands.
> >
> > The parsing is not as robust as one would like, but this suffices
> > without adding a proper parser.
> >
> > Design considerations:
> >
> > (1) Try not to disrupt the existing design of the qmp-shell. The existing
> > API is not disturbed.
> >
> > (2) Pick a "magic token" such that it could not be confused for legitimate
> > QMP/JSON syntax. Parentheses are used for this purpose.
> >
> > ===
> > v2:
> > ===
> >
> > - Squash patches 2 & 3:
> > - Remove wholesale replacement of single quotes, in favor of try blocks
> > that attempt to parse as pure JSON, then as Python.
> > - Factored out the value parser block to accomplish the above.
> > - Allow both true/True and false/False for values.
> > - Fix typo in patch 3 cover letter. (was patch 4.)
> >
> > John Snow (4):
> > scripts: qmp-shell: refactor helpers
> > scripts: qmp-shell: Expand support for QMP expressions
> > scripts: qmp-shell: add transaction subshell
> > scripts: qmp-shell: Add verbose flag
> >
> > scripts/qmp/qmp-shell | 125 ++++++++++++++++++++++++++++++++++++++------------
> > 1 file changed, 95 insertions(+), 30 deletions(-)
> >
>
> Version "2+" with the hotfix added, with R-B's added:
> https://github.com/jnsnow/qemu/commits/qmp-shell-plus
>
> To whomever would pull this into their tree: Let me know if you prefer I
> send a "v3" instead.
Please, re-send.
^ permalink raw reply [flat|nested] 11+ messages in thread