All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] Non-flat command line option argument syntax
@ 2017-02-02 19:42 Markus Armbruster
  2017-02-02 20:06 ` Eric Blake
                   ` (13 more replies)
  0 siblings, 14 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-02 19:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Kevin Wolf, Peter Krempa, Eric Blake, Daniel P. Berrange

= Introduction =

If you're familiar with prior discussion of non-flat arguments for
-object and -blockdev, you can probably skip ahead to "= Structured
option argument syntax =".

Structured option arguments use KEY=VALUE,... syntax.  Goes back many
years (at least to commit 7c9d8e0, Nov 2005).  Since 2009, the proper
way to do this is QemuOpts.

QemuOpts can be used in two ways.  You can either declare accepted keys
and their types, or accept arbitrary keys with string values.  The types
supported with declared keys are char *, bool, uint64_t.  Since none of
them is structured, an option argument is basically a flat dictionary.

QMP was created a few months after QemuOpts, and later on rebased onto
QAPI.  Its simple types are char * (JSON string), bool (JSON false,
true), {uint,int}{8,16,32,64}_t and double (JSON number).  Structured
types are dictionary (JSON object) and list (JSON array).  A QMP command
takes a dictionary as argument.  It need not be flat.

Fine print: the implementation currently can't read uint64_t values
above INT64_MAX from the wire, but that's fixable.

We expose a few things both as QMP command and as command line option:
netdev_add and -netdev, device_add and -device, chardev-add and
-chardev, ...

When the QMP command's argument dictionary happens to be flat,
translating it to QemuOpts is easy enough, if you're willing to map all
integers to uint64_t, and don't need floating-point.

However, many argument dictionaries aren't flat, and numeric types other
than uint64_t exist for a reason.  We need command line option arguments
that are just as expressive as QMP command arguments.  Moreover, having
to translate the argument type from QAPI to QemuOpts is dumb.

We actually have a way to use a QAPI type for an option argument without
translating it: the options visitor.  But it supports basically just the
intersection of QemuOpts and QMP.  Too limited.

We've hacked around the "flatness" of QemuOpts in various ways over the
years.  We abuse implementation details to express flat lists as
repeated keys (e.g. -semihosting-config, -spice, options visitor).  We
bolted on value syntax for lists of integers in places (options visitor,
string visitor).  We bolted on value syntax for arbitrary nesting in
another place (-drive file=json:...).  We bolted on key syntax for
arbitrary nesting in yet another place (block layer's dotted key
convention).  Most recently, Dan even created a fully functional bridge
between QemuOpts and QMP types based on the dotted key convention
(patches [1], not committed).

In my opinion, we need to stop hacking around QemuOpts design
limitations, and start replacing it.

Naturally, any replacement needs to remain sufficiently backward
compatible.  This memo is about the replacement's option argument
syntax.


= Brief recap of dotted key convention =

We'll discuss use of dotted key convention later, so let me explain it
briefly for the readers who don't know it already.

The dotted key convention interprets the KEY part as a sequence of names
separated by dots.  If a name looks like an integer *handwave*, it's an
array index, else it's an object member name.  The first name must be an
object member name, because the option argument is an object, not an
array.  Restriction: can't express member names that look like an
integer.

Example: port=5901 sets the option argument member "port" to the value
5901.

Example: foo.0.bar=bla updates the option argument member "foo", whose
value is an array.  The array's 0-th element is an object with a member
"bar".  That member's value is set to "bla".

The various KEYs need to be consistent in their use of array vs. object.
For instance, foo.0.bar=bla,foo.eek.bar=blubb isn't, because it uses the
value of member "foo" both as array and as object.


= Structured option argument syntax =

== JSON ==

The obvious way to provide the expressiveness of JSON on the command
line is JSON.  Easy enough[2].  However, besides not being compatible,
it's rather heavy on syntax, at least for simple cases.  Compare:

    -machine q35,accel=kvm
    -machine '{ "type": "q35", "accel": "kvm"}'

It compares a bit more favourably in cases that use our non-flat hacks.
Here's a flat list as KEY=VALUE,... with repeated keys, and as JSON:

    -semihosting-config enable,arg=eins,arg=zwei,arg=drei
    -semihosting-config '{ "enable": true, "arg": [ "eins", "zwei", "drei" ] }'

Arbitrary nesting with dotted key convention:

    -drive driver=qcow2,file.driver=gluster,
           file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
           file.server.0.type=tcp,
           file.server.0.host=1.2.3.4,
           file.server.0.port=24007,
           file.server.1.type=unix,
           file.server.1.socket=/var/run/glusterd.socket
    -drive '{ "driver": "qcow2",
              "file": {
                  "driver": "gluster", "volume": "testvol",
                  "path": "/path/a.qcow2", "debug": 9,
                  "server": [ { "type": "tcp",
                                "host": "1.2.3.4", "port": "24007"},
                              { "type": "unix",
                                "socket": "/var/run/glusterd.socket" } ] } }'

Lines broken and indented for legibility; you need to join them for
actual use.  Once you do, both variants are basically illegible.  This
is simply something that belongs into a config file rather than the
command line.  In a config file, JSON would be a better choice.

There's also the -drive file=json:... syntax.  It's a bad fit for
QemuOpts, because QemuOpts and JSON fight for the comma.  I'd show you
if I could get it to work.

We obviously can't replace QemuOpts with JSON.  But accepting JSON in
addition to QemuOpts is a debatable feature: it lets management
applications reuse the code to build QMP arguments for option arguments.

Since structured option arguments are always dictionaries, a JSON option
argument always starts with '{'.  If no QemuOpts argument can ever start
with '{', accepting either QemuOpts or a JSON object is unambiguous.
For a more detailed discussion of the following argument, see [3].

A QemuOpts argument normally starts with KEY.  We need to outlaw KEYs
starting with '{'.  QAPI outlaws such names, see docs/qapi-code-gen.txt.
QOM doesn't, but no such keys exist as far as I know.

QemuOpts permit abbreviating KEY=VALUE to just VALUE for one specific
KEY (the "implied" key).  We need to limit this to KEYs whose VALUE
can't start with '{'.  Most implied keys can't have such values.
Troublemakers include qemu-img's use of implied "file" keys.  You'd have
to say "file={my-tastelessly-named-file}" instead of just
"{my-tastelessly-named-file}".

== Extensions of the traditional syntax ==

Even if we accept JSON in addition to the traditional KEY=VALUE,...
syntax, we might want to make the traditional syntax more expressive
anyway.  Do we?

Kevin brought up an argument for yes: without it, going from the simple,
flat case to the nested case involves a complete syntax change from
KEY=VALUE,... to JSON.

=== Dotted keys ===

One sufficiently powerful syntax extension already exists: the dotted
key convention.  It's syntactically unambiguous only when none of the
KEYs involved contains '.'  To adopt it across the board, we'd have to
outlaw '.' in KEYs.  QAPI outlaws '.' already, but we have a bunch of
QOM properties names with '.'.  We'd have to rename at least the ones
that need to be accessible in -object.

Dotted keys can't express member names that look like integers.  We'd
have to outlaw them at least for the objects that are accessible on the
command line.  Once again, QAPI outlaws such names already.  QOM is
anarchy when it comes to names, however.

The way dotted keys do arrays is inconsistent with how QOM's automatic
arrayification (commit 3396590) do them: foo.0 vs. foo[0].  Backward
compatibility makes changing the dotted key convention awkward.  Perhaps
we can still change QOM.

=== Structured values ===

The dotted key convention messes with KEY syntax to permit structured
values.  Works, but the more conventional way to support structured
values is a syntax for structured values.  

An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
... ] for arrays.  Looks like this:

    -drive 'driver=quorum,
            child=[{ driver=file, filename=disk1.img },
                   { driver=host_device, filename=/dev/sdb },
                   { driver=nbd, host=localhost } ]'

Again, lines broken and indented for legibility; you need to join them
for actual use.

There's a syntactic catch, though: a value of the form [ ... ] can
either be an array or a string.  Which one it is depends on the type of
the key.  To parse this syntax, you need to know the types, unlike JSON
or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
'[', which feels impractical.

But wait, there's another syntactic catch: in traditional QemuOpts, a
value ends at the next unescaped ',' or '\0'.  Inside an object, it now
also ends at the next unescaped '}', and inside an array, at the next
unescaped ']'.  Or perhaps at the next space (the example above assumes
it does).  That means we either have to provide a way to escape '}', ']'
and space, or find another way to delimit string values, say require '"'
around strings whenever the string contains "funny" characters.

So, if escaped ',' wasn't ugly and confusing enough for you...

=== Comparison ===

In my opinion, dotted keys are weird and ugly, but at least they don't
add to the quoting mess.  Structured values look better, except when
they do add to the quoting mess.

I'm having a hard time deciding which one I like less :)

Opinions?  Other ideas?




[1] [PATCH v14 00/21] QAPI/QOM work for non-scalar object properties
(actually v15)
Message-Id: <1475246744-29302-1-git-send-email-berrange@redhat.com>
http://lists.gnu.org/archive/html/qemu-devel/2016-09/msg08238.html

[2] [RFC PATCH] block: Crude initial implementation of -blockdev
Message-Id: <1485968933-9162-1-git-send-email-armbru@redhat.com>
http://lists.gnu.org/archive/html/qemu-devel/2017-02/msg00182.html

[3] Message-ID: <87h989ncse.fsf@dusky.pond.sub.org>
http://lists.gnu.org/archive/html/qemu-devel/2016-10/msg04046.html

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
@ 2017-02-02 20:06 ` Eric Blake
  2017-02-02 20:23 ` Eric Blake
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 55+ messages in thread
From: Eric Blake @ 2017-02-02 20:06 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel
  Cc: qemu-block, Kevin Wolf, Peter Krempa, Daniel P. Berrange

[-- Attachment #1: Type: text/plain, Size: 1108 bytes --]

On 02/02/2017 01:42 PM, Markus Armbruster wrote:

quick comment before I reply to the overall message...


> Arbitrary nesting with dotted key convention:
> 
>     -drive driver=qcow2,file.driver=gluster,
>            file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
>            file.server.0.type=tcp,
>            file.server.0.host=1.2.3.4,
>            file.server.0.port=24007,
>            file.server.1.type=unix,
>            file.server.1.socket=/var/run/glusterd.socket

> 
> Lines broken and indented for legibility; you need to join them for
> actual use.  Once you do, both variants are basically illegible. 

It should be relatively simple to tweak QemuOpts to support:

-drive 'driver=qcow2,
        file.driver=gluster,
        file....'

where all whitespace after comma is ignored, with a nice effect of much
more legibility in long command lines.  I might just submit a patch for
that, regardless of what else we do to get rid of QemuOpts.

-- 
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] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
  2017-02-02 20:06 ` Eric Blake
@ 2017-02-02 20:23 ` Eric Blake
  2017-02-03  7:57   ` Markus Armbruster
  2017-02-02 20:27 ` Dr. David Alan Gilbert
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 55+ messages in thread
From: Eric Blake @ 2017-02-02 20:23 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel
  Cc: qemu-block, Kevin Wolf, Peter Krempa, Daniel P. Berrange

[-- Attachment #1: Type: text/plain, Size: 3349 bytes --]

On 02/02/2017 01:42 PM, Markus Armbruster wrote:

> 
> === Structured values ===
> 
> The dotted key convention messes with KEY syntax to permit structured
> values.  Works, but the more conventional way to support structured
> values is a syntax for structured values.  
> 
> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
> ... ] for arrays.  Looks like this:
> 
>     -drive 'driver=quorum,
>             child=[{ driver=file, filename=disk1.img },
>                    { driver=host_device, filename=/dev/sdb },
>                    { driver=nbd, host=localhost } ]'
> 
> Again, lines broken and indented for legibility; you need to join them
> for actual use.
> 
> There's a syntactic catch, though: a value of the form [ ... ] can
> either be an array or a string.  Which one it is depends on the type of
> the key.  To parse this syntax, you need to know the types, unlike JSON
> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
> '[', which feels impractical.

Another syntactic catch: from the shell,

-drive driver=quorum,child=[...]

is insufficiently quoted, and MIGHT glob to a completely different
argument (or even multiple arguments) depending on the (oddly-named)
contents of the current directory.  Any use of [] HAS to consistently
recommend use with shell quotes.  Using straight JSON already has to use
shell quotes (generally '' for the overall argument, and "" for key
names and string values within the JSON, although our parser as an
extension supports '' for key names and string values which pairs with
"" for the overall argument and allows the use of $var shell interpolation).

> 
> === Comparison ===
> 
> In my opinion, dotted keys are weird and ugly, but at least they don't
> add to the quoting mess.  Structured values look better, except when
> they do add to the quoting mess.
> 
> I'm having a hard time deciding which one I like less :)

Both are a bit awkward.  I think dotted keys require more typing but
less shell quoting than structured values.  And with either approach, it
would STILL be nice if we taught QemuOpts to strip whitespace after
delimiting commas - the only requirement is that no key value can start
with space, which QAPI enforces, and QOM is unlikely to break, although
the benefits of stripping whitespace are only apparent when you remember
to use shell quoting over the entire argument (which partially defeats
the purpose of trying to come up with a syntax that needs less shell
quoting).

> 
> Opinions?  Other ideas?

I don't think command line length is a problem; most command lines are
generated. I'm torn on whether a simplified structured values is nicer
than full-blown JSON; your argument about having the same JSON work on
both the command line and through QMP resulting in less work for
management apps is interesting.  And reusing an existing syntax instead
of inventing yet another one always has the benefit of less code to
maintain.  So even though it's harder to type by hand, I'm somewhat
leaning towards full JSON (where a leading '{' says to parse using JSON
until the closing '}'), rather than any other structured value
representation.

-- 
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] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
  2017-02-02 20:06 ` Eric Blake
  2017-02-02 20:23 ` Eric Blake
@ 2017-02-02 20:27 ` Dr. David Alan Gilbert
  2017-02-03  7:50   ` Markus Armbruster
  2017-02-03 10:03 ` Daniel P. Berrange
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 55+ messages in thread
From: Dr. David Alan Gilbert @ 2017-02-02 20:27 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, Kevin Wolf, Peter Krempa, qemu-block

* Markus Armbruster (armbru@redhat.com) wrote:
> = Introduction =
> 

<snip>

> = Structured option argument syntax =
> 
> == JSON ==
> 
> The obvious way to provide the expressiveness of JSON on the command
> line is JSON.  Easy enough[2].  However, besides not being compatible,
> it's rather heavy on syntax, at least for simple cases.  Compare:
> 
>     -machine q35,accel=kvm
>     -machine '{ "type": "q35", "accel": "kvm"}'
> 
> It compares a bit more favourably in cases that use our non-flat hacks.
> Here's a flat list as KEY=VALUE,... with repeated keys, and as JSON:
> 
>     -semihosting-config enable,arg=eins,arg=zwei,arg=drei
>     -semihosting-config '{ "enable": true, "arg": [ "eins", "zwei", "drei" ] }'
> 
> Arbitrary nesting with dotted key convention:
> 
>     -drive driver=qcow2,file.driver=gluster,
>            file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
>            file.server.0.type=tcp,
>            file.server.0.host=1.2.3.4,
>            file.server.0.port=24007,
>            file.server.1.type=unix,
>            file.server.1.socket=/var/run/glusterd.socket
>     -drive '{ "driver": "qcow2",
>               "file": {
>                   "driver": "gluster", "volume": "testvol",
>                   "path": "/path/a.qcow2", "debug": 9,
>                   "server": [ { "type": "tcp",
>                                 "host": "1.2.3.4", "port": "24007"},
>                               { "type": "unix",
>                                 "socket": "/var/run/glusterd.socket" } ] } }'

So while I generally hate JSON, the -drive dotted key syntax makes
me mad when it gets like this;  have a look
at the block replication and quorum setups especially, that can end up
with (from docs/COLO-FT.txt):

  -drive if=virtio,id=primary-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
         children.0.file.filename=1.raw,\
         children.0.driver=raw -S

   that's just way too many .'s to ever properly understand.
(I'm sure it used to be more complex).

> Lines broken and indented for legibility; you need to join them for
> actual use.

Why? What's a \n between friends for JSON?

> Once you do, both variants are basically illegible.  This
> is simply something that belongs into a config file rather than the
> command line.  In a config file, JSON would be a better choice.
> 
> There's also the -drive file=json:... syntax.  It's a bad fit for
> QemuOpts, because QemuOpts and JSON fight for the comma.  I'd show you
> if I could get it to work.
> 
> We obviously can't replace QemuOpts with JSON.  But accepting JSON in
> addition to QemuOpts is a debatable feature: it lets management
> applications reuse the code to build QMP arguments for option arguments.
> 
> Since structured option arguments are always dictionaries, a JSON option
> argument always starts with '{'.  If no QemuOpts argument can ever start
> with '{', accepting either QemuOpts or a JSON object is unambiguous.
> For a more detailed discussion of the following argument, see [3].
> 
> A QemuOpts argument normally starts with KEY.  We need to outlaw KEYs
> starting with '{'.  QAPI outlaws such names, see docs/qapi-code-gen.txt.
> QOM doesn't, but no such keys exist as far as I know.
> 
> QemuOpts permit abbreviating KEY=VALUE to just VALUE for one specific
> KEY (the "implied" key).  We need to limit this to KEYs whose VALUE
> can't start with '{'.  Most implied keys can't have such values.
> Troublemakers include qemu-img's use of implied "file" keys.  You'd have
> to say "file={my-tastelessly-named-file}" instead of just
> "{my-tastelessly-named-file}".

What worries me a bit is building shell scripts which include ['s and {'s
tends to be painful.

<snip>

> === Structured values ===
> 
> The dotted key convention messes with KEY syntax to permit structured
> values.  Works, but the more conventional way to support structured
> values is a syntax for structured values.  
> 
> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
> ... ] for arrays.  Looks like this:
> 
>     -drive 'driver=quorum,
>             child=[{ driver=file, filename=disk1.img },
>                    { driver=host_device, filename=/dev/sdb },
>                    { driver=nbd, host=localhost } ]'
> 
> Again, lines broken and indented for legibility; you need to join them
> for actual use.
> 
> There's a syntactic catch, though: a value of the form [ ... ] can
> either be an array or a string.  Which one it is depends on the type of
> the key.  To parse this syntax, you need to know the types, unlike JSON
> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
> '[', which feels impractical.

I don't understand why [ could imply a string.

> But wait, there's another syntactic catch: in traditional QemuOpts, a
> value ends at the next unescaped ',' or '\0'.  Inside an object, it now
> also ends at the next unescaped '}', and inside an array, at the next
> unescaped ']'.  Or perhaps at the next space (the example above assumes
> it does).  That means we either have to provide a way to escape '}', ']'
> and space, or find another way to delimit string values, say require '"'
> around strings whenever the string contains "funny" characters.

How about a tighter rule that if you've got a structured value - i.e. you're
inside either of [ or {, then you must " all strings (except keys that we keep clean).

> So, if escaped ',' wasn't ugly and confusing enough for you...
> 
> === Comparison ===
> 
> In my opinion, dotted keys are weird and ugly, but at least they don't
> add to the quoting mess.  Structured values look better, except when
> they do add to the quoting mess.
> 
> I'm having a hard time deciding which one I like less :)
> 
> Opinions?  Other ideas?

Dave

> 
> 
> 
> 
> [1] [PATCH v14 00/21] QAPI/QOM work for non-scalar object properties
> (actually v15)
> Message-Id: <1475246744-29302-1-git-send-email-berrange@redhat.com>
> http://lists.gnu.org/archive/html/qemu-devel/2016-09/msg08238.html
> 
> [2] [RFC PATCH] block: Crude initial implementation of -blockdev
> Message-Id: <1485968933-9162-1-git-send-email-armbru@redhat.com>
> http://lists.gnu.org/archive/html/qemu-devel/2017-02/msg00182.html
> 
> [3] Message-ID: <87h989ncse.fsf@dusky.pond.sub.org>
> http://lists.gnu.org/archive/html/qemu-devel/2016-10/msg04046.html
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 20:27 ` Dr. David Alan Gilbert
@ 2017-02-03  7:50   ` Markus Armbruster
  2017-02-03 16:57     ` Dr. David Alan Gilbert
  2017-02-03 20:02     ` [Qemu-devel] [Qemu-block] " Max Reitz
  0 siblings, 2 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-03  7:50 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

"Dr. David Alan Gilbert" <dgilbert@redhat.com> writes:

> * Markus Armbruster (armbru@redhat.com) wrote:
>> = Introduction =
>> 
>
> <snip>
>
>> = Structured option argument syntax =
>> 
>> == JSON ==
>> 
>> The obvious way to provide the expressiveness of JSON on the command
>> line is JSON.  Easy enough[2].  However, besides not being compatible,
>> it's rather heavy on syntax, at least for simple cases.  Compare:
>> 
>>     -machine q35,accel=kvm
>>     -machine '{ "type": "q35", "accel": "kvm"}'
>> 
>> It compares a bit more favourably in cases that use our non-flat hacks.
>> Here's a flat list as KEY=VALUE,... with repeated keys, and as JSON:
>> 
>>     -semihosting-config enable,arg=eins,arg=zwei,arg=drei
>>     -semihosting-config '{ "enable": true, "arg": [ "eins", "zwei", "drei" ] }'
>> 
>> Arbitrary nesting with dotted key convention:
>> 
>>     -drive driver=qcow2,file.driver=gluster,
>>            file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
>>            file.server.0.type=tcp,
>>            file.server.0.host=1.2.3.4,
>>            file.server.0.port=24007,
>>            file.server.1.type=unix,
>>            file.server.1.socket=/var/run/glusterd.socket
>>     -drive '{ "driver": "qcow2",
>>               "file": {
>>                   "driver": "gluster", "volume": "testvol",
>>                   "path": "/path/a.qcow2", "debug": 9,
>>                   "server": [ { "type": "tcp",
>>                                 "host": "1.2.3.4", "port": "24007"},
>>                               { "type": "unix",
>>                                 "socket": "/var/run/glusterd.socket" } ] } }'
>
> So while I generally hate JSON, the -drive dotted key syntax makes
> me mad when it gets like this;  have a look
> at the block replication and quorum setups especially, that can end up
> with (from docs/COLO-FT.txt):
>
>   -drive if=virtio,id=primary-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
>          children.0.file.filename=1.raw,\
>          children.0.driver=raw -S
>
>    that's just way too many .'s to ever properly understand.
> (I'm sure it used to be more complex).

Here's an idea to cut down on the dottery that drives you mad (and me
too): if KEY starts with '.', combine it with a prefix of the previous
one so that the result has the same number of name components.

Your example becomes

    -drive if=virtio,id=primary-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
           children.0.file.filename=1.raw,.driver=raw -S

My example

     -drive driver=qcow2,file.driver=gluster,
            file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
            file.server.0.type=tcp,
            file.server.0.host=1.2.3.4,
            file.server.0.port=24007,
            file.server.1.type=unix,
            file.server.1.socket=/var/run/glusterd.socket

becomes

     -drive driver=qcow2,
            file.driver=gluster,
                .volume=testvol,
                .path=/path/a.qcow2,
                .debug=9,
            file.server.0.type=tcp,
                         .host=1.2.3.4,
                         .port=24007,
            file.server.1.type=unix,
                         .socket=/var/run/glusterd.socket

Mind, I'm not at all sure this is a *good* idea.  I suspect it's more
magic than it's worth.

>> Lines broken and indented for legibility; you need to join them for
>> actual use.
>
> Why? What's a \n between friends for JSON?

You're right, the JSON works as is.  Only the KEY=VALUE example doesn't.

>> Once you do, both variants are basically illegible.  This
>> is simply something that belongs into a config file rather than the
>> command line.  In a config file, JSON would be a better choice.
>> 
>> There's also the -drive file=json:... syntax.  It's a bad fit for
>> QemuOpts, because QemuOpts and JSON fight for the comma.  I'd show you
>> if I could get it to work.
>> 
>> We obviously can't replace QemuOpts with JSON.  But accepting JSON in
>> addition to QemuOpts is a debatable feature: it lets management
>> applications reuse the code to build QMP arguments for option arguments.
>> 
>> Since structured option arguments are always dictionaries, a JSON option
>> argument always starts with '{'.  If no QemuOpts argument can ever start
>> with '{', accepting either QemuOpts or a JSON object is unambiguous.
>> For a more detailed discussion of the following argument, see [3].
>> 
>> A QemuOpts argument normally starts with KEY.  We need to outlaw KEYs
>> starting with '{'.  QAPI outlaws such names, see docs/qapi-code-gen.txt.
>> QOM doesn't, but no such keys exist as far as I know.
>> 
>> QemuOpts permit abbreviating KEY=VALUE to just VALUE for one specific
>> KEY (the "implied" key).  We need to limit this to KEYs whose VALUE
>> can't start with '{'.  Most implied keys can't have such values.
>> Troublemakers include qemu-img's use of implied "file" keys.  You'd have
>> to say "file={my-tastelessly-named-file}" instead of just
>> "{my-tastelessly-named-file}".
>
> What worries me a bit is building shell scripts which include ['s and {'s
> tends to be painful.

No more than it already is if your builder copes with arbitrary
filenames and such.  But point well taken.

> <snip>
>
>> === Structured values ===
>> 
>> The dotted key convention messes with KEY syntax to permit structured
>> values.  Works, but the more conventional way to support structured
>> values is a syntax for structured values.  
>> 
>> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
>> ... ] for arrays.  Looks like this:
>> 
>>     -drive 'driver=quorum,
>>             child=[{ driver=file, filename=disk1.img },
>>                    { driver=host_device, filename=/dev/sdb },
>>                    { driver=nbd, host=localhost } ]'
>> 
>> Again, lines broken and indented for legibility; you need to join them
>> for actual use.
>> 
>> There's a syntactic catch, though: a value of the form [ ... ] can
>> either be an array or a string.  Which one it is depends on the type of
>> the key.  To parse this syntax, you need to know the types, unlike JSON
>> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
>> '[', which feels impractical.
>
> I don't understand why [ could imply a string.

Consider

    -drive 'driver=quorum,
            child=[{ driver=file, filename={"foolish":"name"} },
                   { driver=host_device, filename=/dev/sdb },
                   { driver=nbd, host=[::1] } ]'

Three KEY=VALUE have their VALUE start with '[' or '{':

* child=[{ driver=file, ...

  This is an array, not a string, because child is an array.

* host=[::1]

  This is a string, not an array containing the string "::1", because
  host is a string.

* filename={"foolish":"name"}

  This is a string, not an object, because filename is a string.

Clearer now?

>> But wait, there's another syntactic catch: in traditional QemuOpts, a
>> value ends at the next unescaped ',' or '\0'.  Inside an object, it now
>> also ends at the next unescaped '}', and inside an array, at the next
>> unescaped ']'.  Or perhaps at the next space (the example above assumes
>> it does).  That means we either have to provide a way to escape '}', ']'
>> and space, or find another way to delimit string values, say require '"'
>> around strings whenever the string contains "funny" characters.
>
> How about a tighter rule that if you've got a structured value -
> i.e. you're inside either of [ or {, then you must " all strings
> (except keys that we keep clean).

Matter of taste.

Regardless, we need a way to escape '"'.  Doubling it would be
consistent with the existing escape of ','.

>> So, if escaped ',' wasn't ugly and confusing enough for you...
>> 
>> === Comparison ===
>> 
>> In my opinion, dotted keys are weird and ugly, but at least they don't
>> add to the quoting mess.  Structured values look better, except when
>> they do add to the quoting mess.
>> 
>> I'm having a hard time deciding which one I like less :)
>> 
>> Opinions?  Other ideas?
>
> Dave
>
>> 
>> 
>> 
>> 
>> [1] [PATCH v14 00/21] QAPI/QOM work for non-scalar object properties
>> (actually v15)
>> Message-Id: <1475246744-29302-1-git-send-email-berrange@redhat.com>
>> http://lists.gnu.org/archive/html/qemu-devel/2016-09/msg08238.html
>> 
>> [2] [RFC PATCH] block: Crude initial implementation of -blockdev
>> Message-Id: <1485968933-9162-1-git-send-email-armbru@redhat.com>
>> http://lists.gnu.org/archive/html/qemu-devel/2017-02/msg00182.html
>> 
>> [3] Message-ID: <87h989ncse.fsf@dusky.pond.sub.org>
>> http://lists.gnu.org/archive/html/qemu-devel/2016-10/msg04046.html
>> 
> --
> Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 20:23 ` Eric Blake
@ 2017-02-03  7:57   ` Markus Armbruster
  0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-03  7:57 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Kevin Wolf, Peter Krempa, qemu-block

Eric Blake <eblake@redhat.com> writes:

> On 02/02/2017 01:42 PM, Markus Armbruster wrote:
>
>> 
>> === Structured values ===
>> 
>> The dotted key convention messes with KEY syntax to permit structured
>> values.  Works, but the more conventional way to support structured
>> values is a syntax for structured values.  
>> 
>> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
>> ... ] for arrays.  Looks like this:
>> 
>>     -drive 'driver=quorum,
>>             child=[{ driver=file, filename=disk1.img },
>>                    { driver=host_device, filename=/dev/sdb },
>>                    { driver=nbd, host=localhost } ]'
>> 
>> Again, lines broken and indented for legibility; you need to join them
>> for actual use.
>> 
>> There's a syntactic catch, though: a value of the form [ ... ] can
>> either be an array or a string.  Which one it is depends on the type of
>> the key.  To parse this syntax, you need to know the types, unlike JSON
>> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
>> '[', which feels impractical.
>
> Another syntactic catch: from the shell,
>
> -drive driver=quorum,child=[...]
>
> is insufficiently quoted, and MIGHT glob to a completely different
> argument (or even multiple arguments) depending on the (oddly-named)
> contents of the current directory.  Any use of [] HAS to consistently
> recommend use with shell quotes.  Using straight JSON already has to use
> shell quotes (generally '' for the overall argument, and "" for key
> names and string values within the JSON, although our parser as an
> extension supports '' for key names and string values which pairs with
> "" for the overall argument and allows the use of $var shell interpolation).

I forgot to mention interactions with shell meta-characters and
quoting.  Glad you brought it up.

>> === Comparison ===
>> 
>> In my opinion, dotted keys are weird and ugly, but at least they don't
>> add to the quoting mess.  Structured values look better, except when
>> they do add to the quoting mess.
>> 
>> I'm having a hard time deciding which one I like less :)
>
> Both are a bit awkward.  I think dotted keys require more typing but
> less shell quoting than structured values.  And with either approach, it
> would STILL be nice if we taught QemuOpts to strip whitespace after
> delimiting commas - the only requirement is that no key value can start
> with space, which QAPI enforces, and QOM is unlikely to break, although
> the benefits of stripping whitespace are only apparent when you remember
> to use shell quoting over the entire argument (which partially defeats
> the purpose of trying to come up with a syntax that needs less shell
> quoting).

Syntax that requires shell quoting even in simple cases is not nice.

Syntax that requires it in complicated cases could be tolerable.  If
you're the kind of person to type option arguments exceeding 200
characters into an interactive shell, you should be the kind of person
to know when to quote.  Programs generating shell input should probably
quote everything except the specific parts they *want* the shell to
expand.

>> Opinions?  Other ideas?
>
> I don't think command line length is a problem; most command lines are
> generated. I'm torn on whether a simplified structured values is nicer
> than full-blown JSON; your argument about having the same JSON work on
> both the command line and through QMP resulting in less work for
> management apps is interesting.  And reusing an existing syntax instead
> of inventing yet another one always has the benefit of less code to
> maintain.  So even though it's harder to type by hand, I'm somewhat
> leaning towards full JSON (where a leading '{' says to parse using JSON
> until the closing '}'), rather than any other structured value
> representation.

Thanks!

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
                   ` (2 preceding siblings ...)
  2017-02-02 20:27 ` Dr. David Alan Gilbert
@ 2017-02-03 10:03 ` Daniel P. Berrange
  2017-02-03 11:13   ` Markus Armbruster
  2017-02-03 12:37 ` Peter Krempa
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 55+ messages in thread
From: Daniel P. Berrange @ 2017-02-03 10:03 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: qemu-devel, qemu-block, Kevin Wolf, Peter Krempa, Eric Blake

On Thu, Feb 02, 2017 at 08:42:33PM +0100, Markus Armbruster wrote:
> === Dotted keys ===
> 
> One sufficiently powerful syntax extension already exists: the dotted
> key convention.  It's syntactically unambiguous only when none of the
> KEYs involved contains '.'  To adopt it across the board, we'd have to
> outlaw '.' in KEYs.  QAPI outlaws '.' already, but we have a bunch of
> QOM properties names with '.'.  We'd have to rename at least the ones
> that need to be accessible in -object.

We don't neccessarily need to rename - there's a couple of alternatives

 - Allow registration of property name aliases, so there's two
   names to access the same property. The old one with the '.'
   in it for back compat, and a new one without the '.'.

 - Magically remap '.' to '_'. eg if user specifies foo_bar and
   there's no foo_bar present, then also look for foo.bar

> Dotted keys can't express member names that look like integers.  We'd
> have to outlaw them at least for the objects that are accessible on the
> command line.  Once again, QAPI outlaws such names already.  QOM is
> anarchy when it comes to names, however.
> 
> The way dotted keys do arrays is inconsistent with how QOM's automatic
> arrayification (commit 3396590) do them: foo.0 vs. foo[0].  Backward
> compatibility makes changing the dotted key convention awkward.  Perhaps
> we can still change QOM.

It is a shame - foo[0] is clearly better as it avoids need to outlaw
member names that are pure integers.

IIRC, we outlaw members names that begin with a "_", so if we must
support member names that are integers, we could allow them to be
given unambigously by using  foo._0  to dinstiguish from foo.0
array access.
 
> === Structured values ===
> 
> The dotted key convention messes with KEY syntax to permit structured
> values.  Works, but the more conventional way to support structured
> values is a syntax for structured values.  
> 
> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
> ... ] for arrays.  Looks like this:
> 
>     -drive 'driver=quorum,
>             child=[{ driver=file, filename=disk1.img },
>                    { driver=host_device, filename=/dev/sdb },
>                    { driver=nbd, host=localhost } ]'
> 
> Again, lines broken and indented for legibility; you need to join them
> for actual use.
> 
> There's a syntactic catch, though: a value of the form [ ... ] can
> either be an array or a string.  Which one it is depends on the type of
> the key.  To parse this syntax, you need to know the types, unlike JSON
> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
> '[', which feels impractical.
> 
> But wait, there's another syntactic catch: in traditional QemuOpts, a
> value ends at the next unescaped ',' or '\0'.  Inside an object, it now
> also ends at the next unescaped '}', and inside an array, at the next
> unescaped ']'.  Or perhaps at the next space (the example above assumes
> it does).  That means we either have to provide a way to escape '}', ']'
> and space, or find another way to delimit string values, say require '"'
> around strings whenever the string contains "funny" characters.
> 
> So, if escaped ',' wasn't ugly and confusing enough for you...

I'm not a fan of this because it essentially introduces yet another
syntax, different from everything that exists today.

> === Comparison ===
> 
> In my opinion, dotted keys are weird and ugly, but at least they don't
> add to the quoting mess.  Structured values look better, except when
> they do add to the quoting mess.
> 
> I'm having a hard time deciding which one I like less :)
> 
> Opinions?  Other ideas?

I think the JSON approach is fine, *iff*, QEMU is being managed by
a machine (ie libvirt). If QEMU is being managed by a human, then
typing & quoting json in the CLI is pretty horrible - when I write
json I pretty much always get the syntax wrong several times, with
the trailing comma rules being particularly tedious. IMHO this is
why humans tend to still use the HMP (or the HMP-lookalike QMP-shell
to talk to QMP), rather ever using QMP directly.

The block layer allows both dotted keys and JSON already IIUC.

As such I'm inclined to say we should support dotted syntax as the
primary human facing syntax and JSON as the machine targetted
syntax. Essentially just do what the block layer already does
and avoid inventing something new. It might not be perfectly
to our taste if we had a green-field, but given historical
baggage, I think its basically fine.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://entangle-photo.org       -o-    http://search.cpan.org/~danberr/ :|

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-03 10:03 ` Daniel P. Berrange
@ 2017-02-03 11:13   ` Markus Armbruster
  0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-03 11:13 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

"Daniel P. Berrange" <berrange@redhat.com> writes:

> On Thu, Feb 02, 2017 at 08:42:33PM +0100, Markus Armbruster wrote:
>> === Dotted keys ===
>> 
>> One sufficiently powerful syntax extension already exists: the dotted
>> key convention.  It's syntactically unambiguous only when none of the
>> KEYs involved contains '.'  To adopt it across the board, we'd have to
>> outlaw '.' in KEYs.  QAPI outlaws '.' already, but we have a bunch of
>> QOM properties names with '.'.  We'd have to rename at least the ones
>> that need to be accessible in -object.
>
> We don't neccessarily need to rename - there's a couple of alternatives
>
>  - Allow registration of property name aliases, so there's two
>    names to access the same property. The old one with the '.'
>    in it for back compat, and a new one without the '.'.

Might have other uses, too.

>  - Magically remap '.' to '_'. eg if user specifies foo_bar and
>    there's no foo_bar present, then also look for foo.bar

I'm wary of such magic, but yes, it's an option.

Rename is the simplest fix when it's possible.

>> Dotted keys can't express member names that look like integers.  We'd
>> have to outlaw them at least for the objects that are accessible on the
>> command line.  Once again, QAPI outlaws such names already.  QOM is
>> anarchy when it comes to names, however.
>> 
>> The way dotted keys do arrays is inconsistent with how QOM's automatic
>> arrayification (commit 3396590) do them: foo.0 vs. foo[0].  Backward
>> compatibility makes changing the dotted key convention awkward.  Perhaps
>> we can still change QOM.
>
> It is a shame - foo[0] is clearly better as it avoids need to outlaw
> member names that are pure integers.

Yes, but you have to quote foo[0] for the shell, unlike foo.0.

> IIRC, we outlaw members names that begin with a "_", so if we must
> support member names that are integers, we could allow them to be
> given unambigously by using  foo._0  to dinstiguish from foo.0
> array access.

QAPI permits leading '_' only for __RFQDN_ downstream extension
prefixes.

Note that even without dotted key convention, you can define QOM names
hostile to command line use: ',' needs be escaped by doubling, shell
meta-characters need to be escaped for the shell, and anything with '='
is impossible to use as KEY.

I stand by my opinion that our failure to define and outlaw anti-social
names consistently is a self-inflicted wound.

>> === Structured values ===
>> 
>> The dotted key convention messes with KEY syntax to permit structured
>> values.  Works, but the more conventional way to support structured
>> values is a syntax for structured values.  
>> 
>> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
>> ... ] for arrays.  Looks like this:
>> 
>>     -drive 'driver=quorum,
>>             child=[{ driver=file, filename=disk1.img },
>>                    { driver=host_device, filename=/dev/sdb },
>>                    { driver=nbd, host=localhost } ]'
>> 
>> Again, lines broken and indented for legibility; you need to join them
>> for actual use.
>> 
>> There's a syntactic catch, though: a value of the form [ ... ] can
>> either be an array or a string.  Which one it is depends on the type of
>> the key.  To parse this syntax, you need to know the types, unlike JSON
>> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
>> '[', which feels impractical.
>> 
>> But wait, there's another syntactic catch: in traditional QemuOpts, a
>> value ends at the next unescaped ',' or '\0'.  Inside an object, it now
>> also ends at the next unescaped '}', and inside an array, at the next
>> unescaped ']'.  Or perhaps at the next space (the example above assumes
>> it does).  That means we either have to provide a way to escape '}', ']'
>> and space, or find another way to delimit string values, say require '"'
>> around strings whenever the string contains "funny" characters.
>> 
>> So, if escaped ',' wasn't ugly and confusing enough for you...
>
> I'm not a fan of this because it essentially introduces yet another
> syntax, different from everything that exists today.
>
>> === Comparison ===
>> 
>> In my opinion, dotted keys are weird and ugly, but at least they don't
>> add to the quoting mess.  Structured values look better, except when
>> they do add to the quoting mess.
>> 
>> I'm having a hard time deciding which one I like less :)
>> 
>> Opinions?  Other ideas?
>
> I think the JSON approach is fine, *iff*, QEMU is being managed by
> a machine (ie libvirt). If QEMU is being managed by a human, then
> typing & quoting json in the CLI is pretty horrible - when I write
> json I pretty much always get the syntax wrong several times, with
> the trailing comma rules being particularly tedious. IMHO this is
> why humans tend to still use the HMP (or the HMP-lookalike QMP-shell
> to talk to QMP), rather ever using QMP directly.

Getting humans to use QMP for interactive work is a non-goal.

> The block layer allows both dotted keys and JSON already IIUC.
>
> As such I'm inclined to say we should support dotted syntax as the
> primary human facing syntax and JSON as the machine targetted
> syntax. Essentially just do what the block layer already does
> and avoid inventing something new. It might not be perfectly
> to our taste if we had a green-field, but given historical
> baggage, I think its basically fine.

Thanks!

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
                   ` (3 preceding siblings ...)
  2017-02-03 10:03 ` Daniel P. Berrange
@ 2017-02-03 12:37 ` Peter Krempa
  2017-02-03 13:53   ` Markus Armbruster
  2017-02-03 17:25 ` Richard W.M. Jones
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 55+ messages in thread
From: Peter Krempa @ 2017-02-03 12:37 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: qemu-devel, qemu-block, Kevin Wolf, Eric Blake, Daniel P. Berrange

[-- Attachment #1: Type: text/plain, Size: 2272 bytes --]

On Thu, Feb 02, 2017 at 20:42:33 +0100, Markus Armbruster wrote:

[...]

> === Comparison ===
> 
> In my opinion, dotted keys are weird and ugly, but at least they don't
> add to the quoting mess.  Structured values look better, except when
> they do add to the quoting mess.

From libvirt's point of view anything that can be easily generated from
the JSON representation into command line arguments is acceptable.
Neither uglyness, nor escaping worry us that much. Libvirt users usually
don't come into contact with the command line and if they do it's messy
anyways.

> I'm having a hard time deciding which one I like less :)

I don't like plain JSON. On the other hand I like the dotted syntax ...
mostly as I've already written the convertors for it a while ago :) [1]

Currently we already to that with anything '-object' related that we do
in libvirt (memory backing objects, master encryption key, etc) and for
a few certain network disk backing protocols:

I stole this example above:

We already generate this internally:
    '{ "file": {
       "driver": "gluster", "volume": "testvol",
       "path": "/path/a.qcow2", "debug": 9,
       "server": [ { "type": "tcp",
                     "host": "1.2.3.4", "port": "24007"},
                   { "type": "unix",
                     "socket": "/var/run/glusterd.socket" } ] } }'

And convert it to this:
>     -drive driver=qcow2,file.driver=gluster,
>            file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
>            file.server.0.type=tcp,
>            file.server.0.host=1.2.3.4,
>            file.server.0.port=24007,
>            file.server.1.type=unix,
>            file.server.1.socket=/var/run/glusterd.socket

There are unfortunately two implementations of the array generator:
For -object we use the repeated key method, and for gluster we use the
numbered method. It might be due to the fact that I tried to do bitmap
to array conversion, where the bitmap is represented by a list of
ranges. It was necessary for memory hotplug

Peter

[1] 331b2583ec2928b in libvirt introduces the first generator (2015/01)
    b7eef33df20dc19 adds the numbered array methot so that it can be
                    uset with gluster (2016/07)

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-03 12:37 ` Peter Krempa
@ 2017-02-03 13:53   ` Markus Armbruster
  0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-03 13:53 UTC (permalink / raw)
  To: Peter Krempa; +Cc: Kevin Wolf, qemu-devel, qemu-block

Peter Krempa <pkrempa@redhat.com> writes:

> On Thu, Feb 02, 2017 at 20:42:33 +0100, Markus Armbruster wrote:
>
> [...]
>
>> === Comparison ===
>> 
>> In my opinion, dotted keys are weird and ugly, but at least they don't
>> add to the quoting mess.  Structured values look better, except when
>> they do add to the quoting mess.
>
> From libvirt's point of view anything that can be easily generated from
> the JSON representation into command line arguments is acceptable.
> Neither uglyness, nor escaping worry us that much. Libvirt users usually
> don't come into contact with the command line and if they do it's messy
> anyways.

Generating JSON should be pretty much as simple as it gets then.

Even quoting for shell is easy: enclose in "'", taking care to quote "'"
in the JSON text.  Since "'" can only occur in JSON strings, you can
simply replace it by \u0027.  Of course you can also replace by '"'"',
trading legibility for not having to exploit "can only occur in
strings".

>> I'm having a hard time deciding which one I like less :)
>
> I don't like plain JSON. On the other hand I like the dotted syntax ...
> mostly as I've already written the convertors for it a while ago :) [1]

Heh!

I'd certainly go with JSON once that works, to minimize differences with
QMP, execute less code (= fewer bugs), and because I find it more
legible than dotted keys.

> Currently we already to that with anything '-object' related that we do
> in libvirt (memory backing objects, master encryption key, etc) and for
> a few certain network disk backing protocols:
>
> I stole this example above:
>
> We already generate this internally:
>     '{ "file": {
>        "driver": "gluster", "volume": "testvol",
>        "path": "/path/a.qcow2", "debug": 9,
>        "server": [ { "type": "tcp",
>                      "host": "1.2.3.4", "port": "24007"},
>                    { "type": "unix",
>                      "socket": "/var/run/glusterd.socket" } ] } }'
>
> And convert it to this:
>>     -drive driver=qcow2,file.driver=gluster,
>>            file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
>>            file.server.0.type=tcp,
>>            file.server.0.host=1.2.3.4,
>>            file.server.0.port=24007,
>>            file.server.1.type=unix,
>>            file.server.1.socket=/var/run/glusterd.socket
>
> There are unfortunately two implementations of the array generator:
> For -object we use the repeated key method, and for gluster we use the
> numbered method. It might be due to the fact that I tried to do bitmap
> to array conversion, where the bitmap is represented by a list of
> ranges. It was necessary for memory hotplug

Two array generators isn't so bad considering we have three and a half
ways to do arrays/lists with QemuOpts.

> [1] 331b2583ec2928b in libvirt introduces the first generator (2015/01)
>     b7eef33df20dc19 adds the numbered array methot so that it can be
>                     uset with gluster (2016/07)

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-03  7:50   ` Markus Armbruster
@ 2017-02-03 16:57     ` Dr. David Alan Gilbert
  2017-02-04  9:44       ` Markus Armbruster
  2017-02-03 20:02     ` [Qemu-devel] [Qemu-block] " Max Reitz
  1 sibling, 1 reply; 55+ messages in thread
From: Dr. David Alan Gilbert @ 2017-02-03 16:57 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

* Markus Armbruster (armbru@redhat.com) wrote:
> "Dr. David Alan Gilbert" <dgilbert@redhat.com> writes:
> 
> > * Markus Armbruster (armbru@redhat.com) wrote:
> >> = Introduction =
> >> 
> >
> > <snip>
> >
> >> = Structured option argument syntax =
> >> 
> >> == JSON ==
> >> 
> >> The obvious way to provide the expressiveness of JSON on the command
> >> line is JSON.  Easy enough[2].  However, besides not being compatible,
> >> it's rather heavy on syntax, at least for simple cases.  Compare:
> >> 
> >>     -machine q35,accel=kvm
> >>     -machine '{ "type": "q35", "accel": "kvm"}'
> >> 
> >> It compares a bit more favourably in cases that use our non-flat hacks.
> >> Here's a flat list as KEY=VALUE,... with repeated keys, and as JSON:
> >> 
> >>     -semihosting-config enable,arg=eins,arg=zwei,arg=drei
> >>     -semihosting-config '{ "enable": true, "arg": [ "eins", "zwei", "drei" ] }'
> >> 
> >> Arbitrary nesting with dotted key convention:
> >> 
> >>     -drive driver=qcow2,file.driver=gluster,
> >>            file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
> >>            file.server.0.type=tcp,
> >>            file.server.0.host=1.2.3.4,
> >>            file.server.0.port=24007,
> >>            file.server.1.type=unix,
> >>            file.server.1.socket=/var/run/glusterd.socket
> >>     -drive '{ "driver": "qcow2",
> >>               "file": {
> >>                   "driver": "gluster", "volume": "testvol",
> >>                   "path": "/path/a.qcow2", "debug": 9,
> >>                   "server": [ { "type": "tcp",
> >>                                 "host": "1.2.3.4", "port": "24007"},
> >>                               { "type": "unix",
> >>                                 "socket": "/var/run/glusterd.socket" } ] } }'
> >
> > So while I generally hate JSON, the -drive dotted key syntax makes
> > me mad when it gets like this;  have a look
> > at the block replication and quorum setups especially, that can end up
> > with (from docs/COLO-FT.txt):
> >
> >   -drive if=virtio,id=primary-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
> >          children.0.file.filename=1.raw,\
> >          children.0.driver=raw -S
> >
> >    that's just way too many .'s to ever properly understand.
> > (I'm sure it used to be more complex).
> 
> Here's an idea to cut down on the dottery that drives you mad (and me
> too): if KEY starts with '.', combine it with a prefix of the previous
> one so that the result has the same number of name components.
> 
> Your example becomes
> 
>     -drive if=virtio,id=primary-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
>            children.0.file.filename=1.raw,.driver=raw -S
> 
> My example
> 
>      -drive driver=qcow2,file.driver=gluster,
>             file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
>             file.server.0.type=tcp,
>             file.server.0.host=1.2.3.4,
>             file.server.0.port=24007,
>             file.server.1.type=unix,
>             file.server.1.socket=/var/run/glusterd.socket
> 
> becomes
> 
>      -drive driver=qcow2,
>             file.driver=gluster,
>                 .volume=testvol,
>                 .path=/path/a.qcow2,
>                 .debug=9,
>             file.server.0.type=tcp,
>                          .host=1.2.3.4,
>                          .port=24007,
>             file.server.1.type=unix,
>                          .socket=/var/run/glusterd.socket
> 
> Mind, I'm not at all sure this is a *good* idea.  I suspect it's more
> magic than it's worth.

That is actually quite a nice compaction; it still feels pretty easy to read,
and doesn't use any more magic characters.

> >> Lines broken and indented for legibility; you need to join them for
> >> actual use.
> >
> > Why? What's a \n between friends for JSON?
> 
> You're right, the JSON works as is.  Only the KEY=VALUE example doesn't.
> 
> >> Once you do, both variants are basically illegible.  This
> >> is simply something that belongs into a config file rather than the
> >> command line.  In a config file, JSON would be a better choice.
> >> 
> >> There's also the -drive file=json:... syntax.  It's a bad fit for
> >> QemuOpts, because QemuOpts and JSON fight for the comma.  I'd show you
> >> if I could get it to work.
> >> 
> >> We obviously can't replace QemuOpts with JSON.  But accepting JSON in
> >> addition to QemuOpts is a debatable feature: it lets management
> >> applications reuse the code to build QMP arguments for option arguments.
> >> 
> >> Since structured option arguments are always dictionaries, a JSON option
> >> argument always starts with '{'.  If no QemuOpts argument can ever start
> >> with '{', accepting either QemuOpts or a JSON object is unambiguous.
> >> For a more detailed discussion of the following argument, see [3].
> >> 
> >> A QemuOpts argument normally starts with KEY.  We need to outlaw KEYs
> >> starting with '{'.  QAPI outlaws such names, see docs/qapi-code-gen.txt.
> >> QOM doesn't, but no such keys exist as far as I know.
> >> 
> >> QemuOpts permit abbreviating KEY=VALUE to just VALUE for one specific
> >> KEY (the "implied" key).  We need to limit this to KEYs whose VALUE
> >> can't start with '{'.  Most implied keys can't have such values.
> >> Troublemakers include qemu-img's use of implied "file" keys.  You'd have
> >> to say "file={my-tastelessly-named-file}" instead of just
> >> "{my-tastelessly-named-file}".
> >
> > What worries me a bit is building shell scripts which include ['s and {'s
> > tends to be painful.
> 
> No more than it already is if your builder copes with arbitrary
> filenames and such.  But point well taken.
> 
> > <snip>
> >
> >> === Structured values ===
> >> 
> >> The dotted key convention messes with KEY syntax to permit structured
> >> values.  Works, but the more conventional way to support structured
> >> values is a syntax for structured values.  
> >> 
> >> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
> >> ... ] for arrays.  Looks like this:
> >> 
> >>     -drive 'driver=quorum,
> >>             child=[{ driver=file, filename=disk1.img },
> >>                    { driver=host_device, filename=/dev/sdb },
> >>                    { driver=nbd, host=localhost } ]'
> >> 
> >> Again, lines broken and indented for legibility; you need to join them
> >> for actual use.
> >> 
> >> There's a syntactic catch, though: a value of the form [ ... ] can
> >> either be an array or a string.  Which one it is depends on the type of
> >> the key.  To parse this syntax, you need to know the types, unlike JSON
> >> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
> >> '[', which feels impractical.
> >
> > I don't understand why [ could imply a string.
> 
> Consider
> 
>     -drive 'driver=quorum,
>             child=[{ driver=file, filename={"foolish":"name"} },
>                    { driver=host_device, filename=/dev/sdb },
>                    { driver=nbd, host=[::1] } ]'
> 
> Three KEY=VALUE have their VALUE start with '[' or '{':
> 
> * child=[{ driver=file, ...
> 
>   This is an array, not a string, because child is an array.
> 
> * host=[::1]
> 
>   This is a string, not an array containing the string "::1", because
>   host is a string.

Why is that accepted as valid input? Can't that just spit a
'I wanted a string not an array' ?

> * filename={"foolish":"name"}
> 
>   This is a string, not an object, because filename is a string.
> 
> Clearer now?
> 
> >> But wait, there's another syntactic catch: in traditional QemuOpts, a
> >> value ends at the next unescaped ',' or '\0'.  Inside an object, it now
> >> also ends at the next unescaped '}', and inside an array, at the next
> >> unescaped ']'.  Or perhaps at the next space (the example above assumes
> >> it does).  That means we either have to provide a way to escape '}', ']'
> >> and space, or find another way to delimit string values, say require '"'
> >> around strings whenever the string contains "funny" characters.
> >
> > How about a tighter rule that if you've got a structured value -
> > i.e. you're inside either of [ or {, then you must " all strings
> > (except keys that we keep clean).
> 
> Matter of taste.
> 
> Regardless, we need a way to escape '"'.  Doubling it would be
> consistent with the existing escape of ','.

Doubling for escape feels hideous, especially for ".

Dave

> >> So, if escaped ',' wasn't ugly and confusing enough for you...
> >> 
> >> === Comparison ===
> >> 
> >> In my opinion, dotted keys are weird and ugly, but at least they don't
> >> add to the quoting mess.  Structured values look better, except when
> >> they do add to the quoting mess.
> >> 
> >> I'm having a hard time deciding which one I like less :)
> >> 
> >> Opinions?  Other ideas?
> >
> > Dave
> >
> >> 
> >> 
> >> 
> >> 
> >> [1] [PATCH v14 00/21] QAPI/QOM work for non-scalar object properties
> >> (actually v15)
> >> Message-Id: <1475246744-29302-1-git-send-email-berrange@redhat.com>
> >> http://lists.gnu.org/archive/html/qemu-devel/2016-09/msg08238.html
> >> 
> >> [2] [RFC PATCH] block: Crude initial implementation of -blockdev
> >> Message-Id: <1485968933-9162-1-git-send-email-armbru@redhat.com>
> >> http://lists.gnu.org/archive/html/qemu-devel/2017-02/msg00182.html
> >> 
> >> [3] Message-ID: <87h989ncse.fsf@dusky.pond.sub.org>
> >> http://lists.gnu.org/archive/html/qemu-devel/2016-10/msg04046.html
> >> 
> > --
> > Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
                   ` (4 preceding siblings ...)
  2017-02-03 12:37 ` Peter Krempa
@ 2017-02-03 17:25 ` Richard W.M. Jones
  2017-02-04  9:51   ` Markus Armbruster
  2017-02-03 20:28 ` Max Reitz
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 55+ messages in thread
From: Richard W.M. Jones @ 2017-02-03 17:25 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, Kevin Wolf, Peter Krempa, qemu-block

On Thu, Feb 02, 2017 at 08:42:33PM +0100, Markus Armbruster wrote:
> There's also the -drive file=json:... syntax.  It's a bad fit for
> QemuOpts, because QemuOpts and JSON fight for the comma.  I'd show you
> if I could get it to work.

I think this refers to the json: syntax for qemu URIs?

Anyway we're using this in virt-v2v
(https://github.com/libguestfs/libguestfs/blob/master/v2v/input_libvirt_xen_ssh.ml)

It's very useful, please try not to break it!

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine.  Supports Linux and Windows.
http://people.redhat.com/~rjones/virt-df/

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [Qemu-block] Non-flat command line option argument syntax
  2017-02-03  7:50   ` Markus Armbruster
  2017-02-03 16:57     ` Dr. David Alan Gilbert
@ 2017-02-03 20:02     ` Max Reitz
  2017-02-04  9:45       ` Markus Armbruster
  1 sibling, 1 reply; 55+ messages in thread
From: Max Reitz @ 2017-02-03 20:02 UTC (permalink / raw)
  To: Markus Armbruster, Dr. David Alan Gilbert
  Cc: Kevin Wolf, qemu-devel, qemu-block

[-- Attachment #1: Type: text/plain, Size: 4070 bytes --]

On 03.02.2017 08:50, Markus Armbruster wrote:
> "Dr. David Alan Gilbert" <dgilbert@redhat.com> writes:
> 
>> * Markus Armbruster (armbru@redhat.com) wrote:
>>> = Introduction =
>>>
>>
>> <snip>
>>
>>> = Structured option argument syntax =
>>>
>>> == JSON ==
>>>
>>> The obvious way to provide the expressiveness of JSON on the command
>>> line is JSON.  Easy enough[2].  However, besides not being compatible,
>>> it's rather heavy on syntax, at least for simple cases.  Compare:
>>>
>>>     -machine q35,accel=kvm
>>>     -machine '{ "type": "q35", "accel": "kvm"}'
>>>
>>> It compares a bit more favourably in cases that use our non-flat hacks.
>>> Here's a flat list as KEY=VALUE,... with repeated keys, and as JSON:
>>>
>>>     -semihosting-config enable,arg=eins,arg=zwei,arg=drei
>>>     -semihosting-config '{ "enable": true, "arg": [ "eins", "zwei", "drei" ] }'
>>>
>>> Arbitrary nesting with dotted key convention:
>>>
>>>     -drive driver=qcow2,file.driver=gluster,
>>>            file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
>>>            file.server.0.type=tcp,
>>>            file.server.0.host=1.2.3.4,
>>>            file.server.0.port=24007,
>>>            file.server.1.type=unix,
>>>            file.server.1.socket=/var/run/glusterd.socket
>>>     -drive '{ "driver": "qcow2",
>>>               "file": {
>>>                   "driver": "gluster", "volume": "testvol",
>>>                   "path": "/path/a.qcow2", "debug": 9,
>>>                   "server": [ { "type": "tcp",
>>>                                 "host": "1.2.3.4", "port": "24007"},
>>>                               { "type": "unix",
>>>                                 "socket": "/var/run/glusterd.socket" } ] } }'
>>
>> So while I generally hate JSON, the -drive dotted key syntax makes
>> me mad when it gets like this;  have a look
>> at the block replication and quorum setups especially, that can end up
>> with (from docs/COLO-FT.txt):
>>
>>   -drive if=virtio,id=primary-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
>>          children.0.file.filename=1.raw,\
>>          children.0.driver=raw -S
>>
>>    that's just way too many .'s to ever properly understand.
>> (I'm sure it used to be more complex).
> 
> Here's an idea to cut down on the dottery that drives you mad (and me
> too): if KEY starts with '.', combine it with a prefix of the previous
> one so that the result has the same number of name components.
> 
> Your example becomes
> 
>     -drive if=virtio,id=primary-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
>            children.0.file.filename=1.raw,.driver=raw -S

No, the last option would be children.0.file.driver=raw when expanded
(which is wrong, it should be children.0.driver).

> 
> My example
> 
>      -drive driver=qcow2,file.driver=gluster,
>             file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
>             file.server.0.type=tcp,
>             file.server.0.host=1.2.3.4,
>             file.server.0.port=24007,
>             file.server.1.type=unix,
>             file.server.1.socket=/var/run/glusterd.socket
> 
> becomes
> 
>      -drive driver=qcow2,
>             file.driver=gluster,
>                 .volume=testvol,
>                 .path=/path/a.qcow2,
>                 .debug=9,
>             file.server.0.type=tcp,
>                          .host=1.2.3.4,
>                          .port=24007,
>             file.server.1.type=unix,
>                          .socket=/var/run/glusterd.socket
> 
> Mind, I'm not at all sure this is a *good* idea.  I suspect it's more
> magic than it's worth.

As someone who likes dot syntax very much, I don't like it. If you
structure it like this, it's OK, but then you can just write the full
prefix (which gets the point across just as well because I can quickly
tell from a glance that it's the same prefix).

OTOH, when joined into a single line it doesn't change much in terms of
legibility, in my opinion.

Max


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [Qemu-block] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
                   ` (5 preceding siblings ...)
  2017-02-03 17:25 ` Richard W.M. Jones
@ 2017-02-03 20:28 ` Max Reitz
  2017-02-04  9:56   ` Markus Armbruster
  2017-02-04 12:21 ` [Qemu-devel] " Fam Zheng
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 55+ messages in thread
From: Max Reitz @ 2017-02-03 20:28 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: Kevin Wolf, Daniel P. Berrange, qemu-block

[-- Attachment #1: Type: text/plain, Size: 3224 bytes --]

I like both JSON and dot syntax. But I like them differently in
different places.

I love JSON when it's in some file where I can turn out syntax
highlighting and let my $EDITOR match brackets and braces.

I hate JSON when it's on the command line. You have to escape, you get
strings in strings, and at least for QMP you sometimes even get strings
in strings in strings (yes, I like my "echo | qemu -qmp stdio" with
human-monitor-command). Apart from that, usually I don't format anything
nicely on the command line anyway, so JSON and dot syntax are equally
illegible then.

JSON is great for reading, when formatted correctly. If it's not
formatted nicely and you don't have a good editor with highlighting,
it's pretty bad.
It's good for writing in an editor. It's not so nice for writing in a shell.

OTOH, it's hard to read dot syntax when formatted correctly and it's
just as bad as JSON when it isn't. But even if you have an editor at
hand, you can't make it better.
It's very easy to write dot syntax, however. Just write down what you
want. Oh, forgot a parameter for that dict three arrays ago? Just write
it down now. Doesn't matter where you put it. How many braces do I need
to close now? Oh, right, I don't need to close any. Nice!

So dot syntax is pretty much a write-only syntax. But it's very good at
that.

On the command line I absolutely adore the dot syntax. It doesn't force
you to quote, you can put everything anywhere and you don't need to
count braces. I love it.

However, nobody can read what you wrote. Usually doesn't matter. But for
docs, that's bad. For scripts, it depends, but again, it usually is bad.
For configuration files, there is pretty much no excuse. So in general,
I'm very skeptic about dot syntax in files, to say the least.


So I think it would be good to allow full-JSON configuration. Put it in
a file, great.

But at the same time, I do not think that JSON is good for the command
line. Dot syntax works fine and in my opinion it often doesn't actually
matter whether it's legible or not.


I don't like structured values very much because to me they are just
"JSON light". Well, you don't have to quote keys and values (so no
"string in string" mess), but other than that you still have to quote
everything and you still have to count braces.

Max


PS: I personally actually think that structured representations such as
JSON may in some situations be less legible than the dot syntax if you
do not have syntax highlighting and it's not formatted nicely; and
that's because you have to count braces not just when writing but also
when reading. Imagine the following:

a.b.c.d.e.f=42,a.b.c.g=23

{"a":{"b":{"c":{"d":{"e":{"f":42}}},"g":23}}}

I can read the first one much better than the second one. Of course,
that's different with nice formatting and a good editor, but the above
is how I would write it on the command line.

I know it's a fabricated example and you'd just need to switch "g" and
"d", but "}}}}}}" actually makes me a bit dizzy, so that may be even
worse. Anyway, I just wanted to make the point that I think that compact
JSON and dot syntax are both pretty much illegible.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-03 16:57     ` Dr. David Alan Gilbert
@ 2017-02-04  9:44       ` Markus Armbruster
  2017-02-06 10:20         ` Dr. David Alan Gilbert
  0 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2017-02-04  9:44 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

"Dr. David Alan Gilbert" <dgilbert@redhat.com> writes:

> * Markus Armbruster (armbru@redhat.com) wrote:
>> "Dr. David Alan Gilbert" <dgilbert@redhat.com> writes:
>> 
>> > * Markus Armbruster (armbru@redhat.com) wrote:
[...]
>> >> === Structured values ===
>> >> 
>> >> The dotted key convention messes with KEY syntax to permit structured
>> >> values.  Works, but the more conventional way to support structured
>> >> values is a syntax for structured values.  
>> >> 
>> >> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
>> >> ... ] for arrays.  Looks like this:
>> >> 
>> >>     -drive 'driver=quorum,
>> >>             child=[{ driver=file, filename=disk1.img },
>> >>                    { driver=host_device, filename=/dev/sdb },
>> >>                    { driver=nbd, host=localhost } ]'
>> >> 
>> >> Again, lines broken and indented for legibility; you need to join them
>> >> for actual use.
>> >> 
>> >> There's a syntactic catch, though: a value of the form [ ... ] can
>> >> either be an array or a string.  Which one it is depends on the type of
>> >> the key.  To parse this syntax, you need to know the types, unlike JSON
>> >> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
>> >> '[', which feels impractical.
>> >
>> > I don't understand why [ could imply a string.
>> 
>> Consider
>> 
>>     -drive 'driver=quorum,
>>             child=[{ driver=file, filename={"foolish":"name"} },
>>                    { driver=host_device, filename=/dev/sdb },
>>                    { driver=nbd, host=[::1] } ]'
>> 
>> Three KEY=VALUE have their VALUE start with '[' or '{':
>> 
>> * child=[{ driver=file, ...
>> 
>>   This is an array, not a string, because child is an array.
>> 
>> * host=[::1]
>> 
>>   This is a string, not an array containing the string "::1", because
>>   host is a string.
>
> Why is that accepted as valid input? Can't that just spit a
> 'I wanted a string not an array' ?

Because "[::1]" is a perfectly valid string.

It's also a valid array.  Unless the parser knows what type to expect
here, it cannot decide how to parse it.  That's why I wrote "to parse
this syntax, you need to know the types".

>> * filename={"foolish":"name"}
>> 
>>   This is a string, not an object, because filename is a string.
>> 
>> Clearer now?
>> 
>> >> But wait, there's another syntactic catch: in traditional QemuOpts, a
>> >> value ends at the next unescaped ',' or '\0'.  Inside an object, it now
>> >> also ends at the next unescaped '}', and inside an array, at the next
>> >> unescaped ']'.  Or perhaps at the next space (the example above assumes
>> >> it does).  That means we either have to provide a way to escape '}', ']'
>> >> and space, or find another way to delimit string values, say require '"'
>> >> around strings whenever the string contains "funny" characters.
>> >
>> > How about a tighter rule that if you've got a structured value -
>> > i.e. you're inside either of [ or {, then you must " all strings
>> > (except keys that we keep clean).
>> 
>> Matter of taste.
>> 
>> Regardless, we need a way to escape '"'.  Doubling it would be
>> consistent with the existing escape of ','.
>
> Doubling for escape feels hideous, especially for ".

No argument, but it beats counting backslashes.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [Qemu-block] Non-flat command line option argument syntax
  2017-02-03 20:02     ` [Qemu-devel] [Qemu-block] " Max Reitz
@ 2017-02-04  9:45       ` Markus Armbruster
  2017-02-04 10:03         ` [Qemu-devel] " Paolo Bonzini
  0 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2017-02-04  9:45 UTC (permalink / raw)
  To: Max Reitz; +Cc: Dr. David Alan Gilbert, Kevin Wolf, qemu-devel, qemu-block

Max Reitz <mreitz@redhat.com> writes:

> On 03.02.2017 08:50, Markus Armbruster wrote:
>> "Dr. David Alan Gilbert" <dgilbert@redhat.com> writes:
>> 
>>> * Markus Armbruster (armbru@redhat.com) wrote:
>>>> = Introduction =
>>>>
>>>
>>> <snip>
>>>
>>>> = Structured option argument syntax =
>>>>
>>>> == JSON ==
>>>>
>>>> The obvious way to provide the expressiveness of JSON on the command
>>>> line is JSON.  Easy enough[2].  However, besides not being compatible,
>>>> it's rather heavy on syntax, at least for simple cases.  Compare:
>>>>
>>>>     -machine q35,accel=kvm
>>>>     -machine '{ "type": "q35", "accel": "kvm"}'
>>>>
>>>> It compares a bit more favourably in cases that use our non-flat hacks.
>>>> Here's a flat list as KEY=VALUE,... with repeated keys, and as JSON:
>>>>
>>>>     -semihosting-config enable,arg=eins,arg=zwei,arg=drei
>>>>     -semihosting-config '{ "enable": true, "arg": [ "eins", "zwei", "drei" ] }'
>>>>
>>>> Arbitrary nesting with dotted key convention:
>>>>
>>>>     -drive driver=qcow2,file.driver=gluster,
>>>>            file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
>>>>            file.server.0.type=tcp,
>>>>            file.server.0.host=1.2.3.4,
>>>>            file.server.0.port=24007,
>>>>            file.server.1.type=unix,
>>>>            file.server.1.socket=/var/run/glusterd.socket
>>>>     -drive '{ "driver": "qcow2",
>>>>               "file": {
>>>>                   "driver": "gluster", "volume": "testvol",
>>>>                   "path": "/path/a.qcow2", "debug": 9,
>>>>                   "server": [ { "type": "tcp",
>>>>                                 "host": "1.2.3.4", "port": "24007"},
>>>>                               { "type": "unix",
>>>>                                 "socket": "/var/run/glusterd.socket" } ] } }'
>>>
>>> So while I generally hate JSON, the -drive dotted key syntax makes
>>> me mad when it gets like this;  have a look
>>> at the block replication and quorum setups especially, that can end up
>>> with (from docs/COLO-FT.txt):
>>>
>>>   -drive if=virtio,id=primary-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
>>>          children.0.file.filename=1.raw,\
>>>          children.0.driver=raw -S
>>>
>>>    that's just way too many .'s to ever properly understand.
>>> (I'm sure it used to be more complex).
>> 
>> Here's an idea to cut down on the dottery that drives you mad (and me
>> too): if KEY starts with '.', combine it with a prefix of the previous
>> one so that the result has the same number of name components.
>> 
>> Your example becomes
>> 
>>     -drive if=virtio,id=primary-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
>>            children.0.file.filename=1.raw,.driver=raw -S
>
> No, the last option would be children.0.file.driver=raw when expanded
> (which is wrong, it should be children.0.driver).

You're right.

>> My example
>> 
>>      -drive driver=qcow2,file.driver=gluster,
>>             file.volume=testvol,file.path=/path/a.qcow2,file.debug=9,
>>             file.server.0.type=tcp,
>>             file.server.0.host=1.2.3.4,
>>             file.server.0.port=24007,
>>             file.server.1.type=unix,
>>             file.server.1.socket=/var/run/glusterd.socket
>> 
>> becomes
>> 
>>      -drive driver=qcow2,
>>             file.driver=gluster,
>>                 .volume=testvol,
>>                 .path=/path/a.qcow2,
>>                 .debug=9,
>>             file.server.0.type=tcp,
>>                          .host=1.2.3.4,
>>                          .port=24007,
>>             file.server.1.type=unix,
>>                          .socket=/var/run/glusterd.socket
>> 
>> Mind, I'm not at all sure this is a *good* idea.  I suspect it's more
>> magic than it's worth.
>
> As someone who likes dot syntax very much, I don't like it. If you
> structure it like this, it's OK, but then you can just write the full
> prefix (which gets the point across just as well because I can quickly
> tell from a glance that it's the same prefix).
>
> OTOH, when joined into a single line it doesn't change much in terms of
> legibility, in my opinion.

Thanks!

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-03 17:25 ` Richard W.M. Jones
@ 2017-02-04  9:51   ` Markus Armbruster
  2017-02-05 20:46     ` [Qemu-devel] [Qemu-block] " Max Reitz
  0 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2017-02-04  9:51 UTC (permalink / raw)
  To: Richard W.M. Jones; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

"Richard W.M. Jones" <rjones@redhat.com> writes:

> On Thu, Feb 02, 2017 at 08:42:33PM +0100, Markus Armbruster wrote:
>> There's also the -drive file=json:... syntax.  It's a bad fit for
>> QemuOpts, because QemuOpts and JSON fight for the comma.  I'd show you
>> if I could get it to work.
>
> I think this refers to the json: syntax for qemu URIs?

The json: pseudo-protocol, i.e. "file names" starting with a "json:"
protocol prefix.  I think we mean the same.

> Anyway we're using this in virt-v2v
> (https://github.com/libguestfs/libguestfs/blob/master/v2v/input_libvirt_xen_ssh.ml)
>
> It's very useful, please try not to break it!

We're not going to take the json: pseudo-protocol away.  Perhaps we'll
deprecate it at some point, but even then it'll stay for a sufficiently
generous grace period.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [Qemu-block] Non-flat command line option argument syntax
  2017-02-03 20:28 ` Max Reitz
@ 2017-02-04  9:56   ` Markus Armbruster
  0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-04  9:56 UTC (permalink / raw)
  To: Max Reitz; +Cc: qemu-devel, Kevin Wolf, qemu-block

Max Reitz <mreitz@redhat.com> writes:

> I like both JSON and dot syntax. But I like them differently in
> different places.
>
> I love JSON when it's in some file where I can turn out syntax
> highlighting and let my $EDITOR match brackets and braces.
>
> I hate JSON when it's on the command line. You have to escape, you get
> strings in strings, and at least for QMP you sometimes even get strings
> in strings in strings (yes, I like my "echo | qemu -qmp stdio" with
> human-monitor-command). Apart from that, usually I don't format anything
> nicely on the command line anyway, so JSON and dot syntax are equally
> illegible then.
>
> JSON is great for reading, when formatted correctly. If it's not
> formatted nicely and you don't have a good editor with highlighting,
> it's pretty bad.
> It's good for writing in an editor. It's not so nice for writing in a shell.

Pro-tip: M-x shell blinks parenthesis.

But point taken.

> OTOH, it's hard to read dot syntax when formatted correctly and it's
> just as bad as JSON when it isn't. But even if you have an editor at
> hand, you can't make it better.
> It's very easy to write dot syntax, however. Just write down what you
> want. Oh, forgot a parameter for that dict three arrays ago? Just write
> it down now. Doesn't matter where you put it. How many braces do I need
> to close now? Oh, right, I don't need to close any. Nice!
>
> So dot syntax is pretty much a write-only syntax. But it's very good at
> that.

Tiresomely repetitive, though.

> On the command line I absolutely adore the dot syntax. It doesn't force
> you to quote, you can put everything anywhere and you don't need to
> count braces. I love it.
>
> However, nobody can read what you wrote. Usually doesn't matter. But for
> docs, that's bad. For scripts, it depends, but again, it usually is bad.
> For configuration files, there is pretty much no excuse. So in general,
> I'm very skeptic about dot syntax in files, to say the least.

Me too.

> So I think it would be good to allow full-JSON configuration. Put it in
> a file, great.
>
> But at the same time, I do not think that JSON is good for the command
> line. Dot syntax works fine and in my opinion it often doesn't actually
> matter whether it's legible or not.
>
>
> I don't like structured values very much because to me they are just
> "JSON light". Well, you don't have to quote keys and values (so no
> "string in string" mess), but other than that you still have to quote
> everything and you still have to count braces.
>
> Max
>
>
> PS: I personally actually think that structured representations such as
> JSON may in some situations be less legible than the dot syntax if you
> do not have syntax highlighting and it's not formatted nicely; and
> that's because you have to count braces not just when writing but also
> when reading. Imagine the following:
>
> a.b.c.d.e.f=42,a.b.c.g=23
>
> {"a":{"b":{"c":{"d":{"e":{"f":42}}},"g":23}}}
>
> I can read the first one much better than the second one. Of course,
> that's different with nice formatting and a good editor, but the above
> is how I would write it on the command line.
>
> I know it's a fabricated example and you'd just need to switch "g" and
> "d", but "}}}}}}" actually makes me a bit dizzy, so that may be even
> worse. Anyway, I just wanted to make the point that I think that compact
> JSON and dot syntax are both pretty much illegible.

Quoting myself: "both variants are basically illegible.  This is simply
something that belongs into a config file rather than the command line."

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-04  9:45       ` Markus Armbruster
@ 2017-02-04 10:03         ` Paolo Bonzini
  2017-02-04 11:52           ` Markus Armbruster
  0 siblings, 1 reply; 55+ messages in thread
From: Paolo Bonzini @ 2017-02-04 10:03 UTC (permalink / raw)
  To: Markus Armbruster, Max Reitz
  Cc: Kevin Wolf, Dr. David Alan Gilbert, qemu-block, qemu-devel



On 04/02/2017 01:45, Markus Armbruster wrote:
>>>      -drive driver=qcow2,
>>>             file.driver=gluster,
>>>                 .volume=testvol,
>>>                 .path=/path/a.qcow2,
>>>                 .debug=9,
>>>             file.server.0.type=tcp,
>>>                          .host=1.2.3.4,
>>>                          .port=24007,
>>>             file.server.1.type=unix,
>>>                          .socket=/var/run/glusterd.socket
>>>
>>> Mind, I'm not at all sure this is a *good* idea.  I suspect it's more
>>> magic than it's worth.
>> As someone who likes dot syntax very much, I don't like it. If you
>> structure it like this, it's OK, but then you can just write the full
>> prefix (which gets the point across just as well because I can quickly
>> tell from a glance that it's the same prefix).
>>
>> OTOH, when joined into a single line it doesn't change much in terms of
>> legibility, in my opinion.
> 
> Thanks!

Actually I think it does improve legibility.

It doesn't improve writability though, as anecdotally proved by Markus's
own mistake.

I am a fan of the dot syntax too.  It seems to be the most incremental
solution, and it's still as expressive as JSON.

_However_ we could also extend -readconfig to support JSON, i.e. instead of

	[drive "abc"]
		file = "foo"

it could support

	{ 'drive': { 'file: 'foo' }, 'id': 'abc' }

In other words [ would introduce key-value QemuOpts with dot syntax,
while { would introduce JSON.

Paolo

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-04 10:03         ` [Qemu-devel] " Paolo Bonzini
@ 2017-02-04 11:52           ` Markus Armbruster
  2017-02-04 12:43             ` Paolo Bonzini
  0 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2017-02-04 11:52 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Max Reitz, Kevin Wolf, Dr. David Alan Gilbert, qemu-block, qemu-devel

Paolo Bonzini <pbonzini@redhat.com> writes:

> On 04/02/2017 01:45, Markus Armbruster wrote:
>>>>      -drive driver=qcow2,
>>>>             file.driver=gluster,
>>>>                 .volume=testvol,
>>>>                 .path=/path/a.qcow2,
>>>>                 .debug=9,
>>>>             file.server.0.type=tcp,
>>>>                          .host=1.2.3.4,
>>>>                          .port=24007,
>>>>             file.server.1.type=unix,
>>>>                          .socket=/var/run/glusterd.socket
>>>>
>>>> Mind, I'm not at all sure this is a *good* idea.  I suspect it's more
>>>> magic than it's worth.
>>> As someone who likes dot syntax very much, I don't like it. If you
>>> structure it like this, it's OK, but then you can just write the full
>>> prefix (which gets the point across just as well because I can quickly
>>> tell from a glance that it's the same prefix).
>>>
>>> OTOH, when joined into a single line it doesn't change much in terms of
>>> legibility, in my opinion.
>> 
>> Thanks!
>
> Actually I think it does improve legibility.
>
> It doesn't improve writability though, as anecdotally proved by Markus's
> own mistake.
>
> I am a fan of the dot syntax too.  It seems to be the most incremental
> solution, and it's still as expressive as JSON.

Noted.

> _However_ we could also extend -readconfig to support JSON, i.e. instead of
>
> 	[drive "abc"]
> 		file = "foo"
>
> it could support
>
> 	{ 'drive': { 'file: 'foo' }, 'id': 'abc' }
>
> In other words [ would introduce key-value QemuOpts with dot syntax,
> while { would introduce JSON.

Yes, we should support config files in JSON syntax.  Not sure mixing INI
and JSON syntax in the same file is a good idea, though.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
                   ` (6 preceding siblings ...)
  2017-02-03 20:28 ` Max Reitz
@ 2017-02-04 12:21 ` Fam Zheng
  2017-02-04 12:44   ` Paolo Bonzini
                     ` (2 more replies)
  2017-02-06  6:57 ` Markus Armbruster
                   ` (5 subsequent siblings)
  13 siblings, 3 replies; 55+ messages in thread
From: Fam Zheng @ 2017-02-04 12:21 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, Kevin Wolf, Peter Krempa, qemu-block

On Thu, 02/02 20:42, Markus Armbruster wrote:
> === Comparison ===
> 
> In my opinion, dotted keys are weird and ugly, but at least they don't
> add to the quoting mess.  Structured values look better, except when
> they do add to the quoting mess.
> 
> I'm having a hard time deciding which one I like less :)
> 
> Opinions?  Other ideas?

Here's my poor attempt:

The dotted syntax, as the simpler of two, can cover everyday use very well.  If
we introduce an "@reference" extension to it which can help the expresiveness,
we can have a hybrid solution. It's not the cleanest interface and syntax, but
escaping, nesting and quoting can all be divide-and-conqured in their optimal way.
What I'm imagining is something like:

    -json "id=children0,text=[
                { 'driver': 'null-co://' },
                { 'driver': 'null-co://' },
                { 'driver': 'null-co://' }
            ]" \
    -dot \
      id=quorum0,driver=quorum,read-pattern=fifo,vote-threshold=1,children=@children0 \
    -drive if=virtio,id=primary-disk0,driver=qcow2,file=@quorum0

IOW "-json" and "-dot" define options that is intended to be referenced from
other dotted keys (quorum0 uses children0, and in turn primary-disk0 uses
quorum0).

Note: "-dot" here could be replaced with a -blockdev in this specific case but
I'm demostrating it just in case it is useful generically.

Fam

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-04 11:52           ` Markus Armbruster
@ 2017-02-04 12:43             ` Paolo Bonzini
  0 siblings, 0 replies; 55+ messages in thread
From: Paolo Bonzini @ 2017-02-04 12:43 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, qemu-devel, Dr. David Alan Gilbert, qemu-block, Max Reitz



On 04/02/2017 03:52, Markus Armbruster wrote:
> Paolo Bonzini <pbonzini@redhat.com> writes:
> 
>> On 04/02/2017 01:45, Markus Armbruster wrote:
>>>>>      -drive driver=qcow2,
>>>>>             file.driver=gluster,
>>>>>                 .volume=testvol,
>>>>>                 .path=/path/a.qcow2,
>>>>>                 .debug=9,
>>>>>             file.server.0.type=tcp,
>>>>>                          .host=1.2.3.4,
>>>>>                          .port=24007,
>>>>>             file.server.1.type=unix,
>>>>>                          .socket=/var/run/glusterd.socket
>>>>>
>>>>> Mind, I'm not at all sure this is a *good* idea.  I suspect it's more
>>>>> magic than it's worth.
>>>> As someone who likes dot syntax very much, I don't like it. If you
>>>> structure it like this, it's OK, but then you can just write the full
>>>> prefix (which gets the point across just as well because I can quickly
>>>> tell from a glance that it's the same prefix).
>>>>
>>>> OTOH, when joined into a single line it doesn't change much in terms of
>>>> legibility, in my opinion.
>>>
>>> Thanks!
>>
>> Actually I think it does improve legibility.
>>
>> It doesn't improve writability though, as anecdotally proved by Markus's
>> own mistake.
>>
>> I am a fan of the dot syntax too.  It seems to be the most incremental
>> solution, and it's still as expressive as JSON.
> 
> Noted.
> 
>> _However_ we could also extend -readconfig to support JSON, i.e. instead of
>>
>> 	[drive "abc"]
>> 		file = "foo"
>>
>> it could support
>>
>> 	{ 'drive': { 'file: 'foo' }, 'id': 'abc' }
>>
>> In other words [ would introduce key-value QemuOpts with dot syntax,
>> while { would introduce JSON.
> 
> Yes, we should support config files in JSON syntax.  Not sure mixing INI
> and JSON syntax in the same file is a good idea, though.

It's probably not, so we could have "-readconfig foo,syntax=json"
instead (yes, that's QemuOpts syntax---so meta).

Paolo

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-04 12:21 ` [Qemu-devel] " Fam Zheng
@ 2017-02-04 12:44   ` Paolo Bonzini
  2017-02-04 13:02     ` Fam Zheng
  2017-02-04 13:35   ` Markus Armbruster
  2017-02-06 11:08   ` Daniel P. Berrange
  2 siblings, 1 reply; 55+ messages in thread
From: Paolo Bonzini @ 2017-02-04 12:44 UTC (permalink / raw)
  To: Fam Zheng, Markus Armbruster; +Cc: Kevin Wolf, qemu-devel, qemu-block



On 04/02/2017 04:21, Fam Zheng wrote:
>     -json "id=children0,text=[
>                 { 'driver': 'null-co://' },
>                 { 'driver': 'null-co://' },

You meant ,, at the end of this lines.  Which throws a wrench in your
proposal somewhat. :(

Paolo

>                 { 'driver': 'null-co://' }
>             ]" \
>     -dot \
>       id=quorum0,driver=quorum,read-pattern=fifo,vote-threshold=1,children=@children0 \
>     -drive if=virtio,id=primary-disk0,driver=qcow2,file=@quorum0

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-04 12:44   ` Paolo Bonzini
@ 2017-02-04 13:02     ` Fam Zheng
  0 siblings, 0 replies; 55+ messages in thread
From: Fam Zheng @ 2017-02-04 13:02 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Markus Armbruster, Kevin Wolf, qemu-devel, qemu-block

On Sat, 02/04 04:44, Paolo Bonzini wrote:
> 
> 
> On 04/02/2017 04:21, Fam Zheng wrote:
> >     -json "id=children0,text=[
> >                 { 'driver': 'null-co://' },
> >                 { 'driver': 'null-co://' },
> 
> You meant ,, at the end of this lines.  Which throws a wrench in your
> proposal somewhat. :(

Ahh right.. We could just specially ditch the ,, escape here and start over with
a faithful JSON parser added to which a mere id syntax (i.e. the "ID=" prefix):

    -json "children0=[
                 { 'driver': 'null-co://' },
                 { 'driver': 'null-co://' },
                 { 'driver': 'null-co://' }
             ]" \


> 
> Paolo
> 
> >                 { 'driver': 'null-co://' }
> >             ]" \
> >     -dot \
> >       id=quorum0,driver=quorum,read-pattern=fifo,vote-threshold=1,children=@children0 \
> >     -drive if=virtio,id=primary-disk0,driver=qcow2,file=@quorum0
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-04 12:21 ` [Qemu-devel] " Fam Zheng
  2017-02-04 12:44   ` Paolo Bonzini
@ 2017-02-04 13:35   ` Markus Armbruster
  2017-02-04 14:10     ` Fam Zheng
  2017-02-06 11:08   ` Daniel P. Berrange
  2 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2017-02-04 13:35 UTC (permalink / raw)
  To: Fam Zheng; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

Fam Zheng <famz@redhat.com> writes:

> On Thu, 02/02 20:42, Markus Armbruster wrote:
>> === Comparison ===
>> 
>> In my opinion, dotted keys are weird and ugly, but at least they don't
>> add to the quoting mess.  Structured values look better, except when
>> they do add to the quoting mess.
>> 
>> I'm having a hard time deciding which one I like less :)
>> 
>> Opinions?  Other ideas?
>
> Here's my poor attempt:
>
> The dotted syntax, as the simpler of two, can cover everyday use very well.  If
> we introduce an "@reference" extension to it which can help the expresiveness,
> we can have a hybrid solution. It's not the cleanest interface and syntax, but
> escaping, nesting and quoting can all be divide-and-conqured in their optimal way.
> What I'm imagining is something like:
>
>     -json "id=children0,text=[
>                 { 'driver': 'null-co://' },
>                 { 'driver': 'null-co://' },
>                 { 'driver': 'null-co://' }
>             ]" \
>     -dot \
>       id=quorum0,driver=quorum,read-pattern=fifo,vote-threshold=1,children=@children0 \
>     -drive if=virtio,id=primary-disk0,driver=qcow2,file=@quorum0
>
> IOW "-json" and "-dot" define options that is intended to be referenced from
> other dotted keys (quorum0 uses children0, and in turn primary-disk0 uses
> quorum0).
>
> Note: "-dot" here could be replaced with a -blockdev in this specific case but
> I'm demostrating it just in case it is useful generically.
>
> Fam

KEY=@REF for references creates the same issue as KEY=[VALUE,...] for
arrays: you need to know the type of KEY to decide whether @REF is a
reference or a string, unless we outlaw strings starting with '@'.

Not a show-stopper, but it does preclude a design where a simple parser
feeds into a type-aware visitor, which is how the JSON -> QObject ->
QAPI pipeline works.

If you get creative in the VALUE part, you complicate the parser and/or
need to add quoting.

If you get creative in the KEY part, you need to restrict valid names.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-04 13:35   ` Markus Armbruster
@ 2017-02-04 14:10     ` Fam Zheng
  2017-02-06  6:24       ` Markus Armbruster
  0 siblings, 1 reply; 55+ messages in thread
From: Fam Zheng @ 2017-02-04 14:10 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

On Sat, 02/04 14:35, Markus Armbruster wrote:
> Fam Zheng <famz@redhat.com> writes:
> 
> > On Thu, 02/02 20:42, Markus Armbruster wrote:
> >> === Comparison ===
> >> 
> >> In my opinion, dotted keys are weird and ugly, but at least they don't
> >> add to the quoting mess.  Structured values look better, except when
> >> they do add to the quoting mess.
> >> 
> >> I'm having a hard time deciding which one I like less :)
> >> 
> >> Opinions?  Other ideas?
> >
> > Here's my poor attempt:
> >
> > The dotted syntax, as the simpler of two, can cover everyday use very well.  If
> > we introduce an "@reference" extension to it which can help the expresiveness,
> > we can have a hybrid solution. It's not the cleanest interface and syntax, but
> > escaping, nesting and quoting can all be divide-and-conqured in their optimal way.
> > What I'm imagining is something like:
> >
> >     -json "id=children0,text=[
> >                 { 'driver': 'null-co://' },
> >                 { 'driver': 'null-co://' },
> >                 { 'driver': 'null-co://' }
> >             ]" \
> >     -dot \
> >       id=quorum0,driver=quorum,read-pattern=fifo,vote-threshold=1,children=@children0 \
> >     -drive if=virtio,id=primary-disk0,driver=qcow2,file=@quorum0
> >
> > IOW "-json" and "-dot" define options that is intended to be referenced from
> > other dotted keys (quorum0 uses children0, and in turn primary-disk0 uses
> > quorum0).
> >
> > Note: "-dot" here could be replaced with a -blockdev in this specific case but
> > I'm demostrating it just in case it is useful generically.
> >
> > Fam
> 
> KEY=@REF for references creates the same issue as KEY=[VALUE,...] for
> arrays: you need to know the type of KEY to decide whether @REF is a
> reference or a string, unless we outlaw strings starting with '@'.
> 
> Not a show-stopper, but it does preclude a design where a simple parser
> feeds into a type-aware visitor, which is how the JSON -> QObject ->
> QAPI pipeline works.
> 
> If you get creative in the VALUE part, you complicate the parser and/or
> need to add quoting.
> 
> If you get creative in the KEY part, you need to restrict valid names.

How about KEY@=REF?

Fam

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [Qemu-block] Non-flat command line option argument syntax
  2017-02-04  9:51   ` Markus Armbruster
@ 2017-02-05 20:46     ` Max Reitz
  0 siblings, 0 replies; 55+ messages in thread
From: Max Reitz @ 2017-02-05 20:46 UTC (permalink / raw)
  To: Markus Armbruster, Richard W.M. Jones; +Cc: Kevin Wolf, qemu-devel, qemu-block

[-- Attachment #1: Type: text/plain, Size: 1220 bytes --]

On 04.02.2017 10:51, Markus Armbruster wrote:
> "Richard W.M. Jones" <rjones@redhat.com> writes:
> 
>> On Thu, Feb 02, 2017 at 08:42:33PM +0100, Markus Armbruster wrote:
>>> There's also the -drive file=json:... syntax.  It's a bad fit for
>>> QemuOpts, because QemuOpts and JSON fight for the comma.  I'd show you
>>> if I could get it to work.
>>
>> I think this refers to the json: syntax for qemu URIs?
> 
> The json: pseudo-protocol, i.e. "file names" starting with a "json:"
> protocol prefix.  I think we mean the same.
> 
>> Anyway we're using this in virt-v2v
>> (https://github.com/libguestfs/libguestfs/blob/master/v2v/input_libvirt_xen_ssh.ml)
>>
>> It's very useful, please try not to break it!
> 
> We're not going to take the json: pseudo-protocol away.  Perhaps we'll
> deprecate it at some point, but even then it'll stay for a sufficiently
> generous grace period.

It should be noted that there are no current plans to deprecate it. It
won't be superseded by command line changes, considering that it was
originally not introduced to make configuration on the command line more
beautiful but to allow e.g. backing file strings to contain more than
just a filename.

Max


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-04 14:10     ` Fam Zheng
@ 2017-02-06  6:24       ` Markus Armbruster
  0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-06  6:24 UTC (permalink / raw)
  To: Fam Zheng; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

Fam Zheng <famz@redhat.com> writes:

> On Sat, 02/04 14:35, Markus Armbruster wrote:
>> Fam Zheng <famz@redhat.com> writes:
>> 
>> > On Thu, 02/02 20:42, Markus Armbruster wrote:
>> >> === Comparison ===
>> >> 
>> >> In my opinion, dotted keys are weird and ugly, but at least they don't
>> >> add to the quoting mess.  Structured values look better, except when
>> >> they do add to the quoting mess.
>> >> 
>> >> I'm having a hard time deciding which one I like less :)
>> >> 
>> >> Opinions?  Other ideas?
>> >
>> > Here's my poor attempt:
>> >
>> > The dotted syntax, as the simpler of two, can cover everyday use very well.  If
>> > we introduce an "@reference" extension to it which can help the expresiveness,
>> > we can have a hybrid solution. It's not the cleanest interface and syntax, but
>> > escaping, nesting and quoting can all be divide-and-conqured in their optimal way.
>> > What I'm imagining is something like:
>> >
>> >     -json "id=children0,text=[
>> >                 { 'driver': 'null-co://' },
>> >                 { 'driver': 'null-co://' },
>> >                 { 'driver': 'null-co://' }
>> >             ]" \
>> >     -dot \
>> >       id=quorum0,driver=quorum,read-pattern=fifo,vote-threshold=1,children=@children0 \
>> >     -drive if=virtio,id=primary-disk0,driver=qcow2,file=@quorum0
>> >
>> > IOW "-json" and "-dot" define options that is intended to be referenced from
>> > other dotted keys (quorum0 uses children0, and in turn primary-disk0 uses
>> > quorum0).
>> >
>> > Note: "-dot" here could be replaced with a -blockdev in this specific case but
>> > I'm demostrating it just in case it is useful generically.
>> >
>> > Fam
>> 
>> KEY=@REF for references creates the same issue as KEY=[VALUE,...] for
>> arrays: you need to know the type of KEY to decide whether @REF is a
>> reference or a string, unless we outlaw strings starting with '@'.
>> 
>> Not a show-stopper, but it does preclude a design where a simple parser
>> feeds into a type-aware visitor, which is how the JSON -> QObject ->
>> QAPI pipeline works.
>> 
>> If you get creative in the VALUE part, you complicate the parser and/or
>> need to add quoting.
>> 
>> If you get creative in the KEY part, you need to restrict valid names.
>
> How about KEY@=REF?

Requires outlawing KEYs ending with '@'.  QAPI outlaws such names
already.  QOM doesn't, but I figure no such names exist so far.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
                   ` (7 preceding siblings ...)
  2017-02-04 12:21 ` [Qemu-devel] " Fam Zheng
@ 2017-02-06  6:57 ` Markus Armbruster
  2017-02-06 13:23 ` Kevin Wolf
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-06  6:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Kevin Wolf, Peter Krempa, Eric Blake, Daniel P. Berrange

Markus Armbruster <armbru@redhat.com> writes:

[...]
> === Structured values ===
>
> The dotted key convention messes with KEY syntax to permit structured
> values.  Works, but the more conventional way to support structured
> values is a syntax for structured values.  
>
> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
> ... ] for arrays.  Looks like this:
>
>     -drive 'driver=quorum,
>             child=[{ driver=file, filename=disk1.img },
>                    { driver=host_device, filename=/dev/sdb },
>                    { driver=nbd, host=localhost } ]'
>
> Again, lines broken and indented for legibility; you need to join them
> for actual use.
>
> There's a syntactic catch, though: a value of the form [ ... ] can
> either be an array or a string.  Which one it is depends on the type of
> the key.  To parse this syntax, you need to know the types, unlike JSON
> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
> '[', which feels impractical.

The parser having to know the types obviously precludes a design where a
simple parser feeds into a type-aware visitor, which is how the JSON ->
QObject -> QAPI pipeline works.

Perhaps less obviously, it even precludes a design where the parser is
derived from the QAPI schema to make it type-aware: the 'any' type
spoils that.

Consider -object/object-add and -device/device_add.  These take a few
statically known parameters such as "id".  Any additional parameters get
collected in a dictionary.  The schema represents it as value of type
'any'.  The code using this dictionary value matches its entries against
QOM properties.

To parse these additional parameters, knowing the (compile-time static)
schema isn't sufficient.  You also need to know the type of the QOM
property they'll get matched to at run-time.

This is a special case.  For the general case, you need to know how code
is going to use the value.  You generally can't know that until it's
done, so we'd have to parse lazily.  Thanks, but no thanks.

> But wait, there's another syntactic catch: in traditional QemuOpts, a
> value ends at the next unescaped ',' or '\0'.  Inside an object, it now
> also ends at the next unescaped '}', and inside an array, at the next
> unescaped ']'.  Or perhaps at the next space (the example above assumes
> it does).  That means we either have to provide a way to escape '}', ']'
> and space, or find another way to delimit string values, say require '"'
> around strings whenever the string contains "funny" characters.
>
> So, if escaped ',' wasn't ugly and confusing enough for you...
>
> === Comparison ===
>
> In my opinion, dotted keys are weird and ugly, but at least they don't
> add to the quoting mess.  Structured values look better, except when
> they do add to the quoting mess.
>
> I'm having a hard time deciding which one I like less :)
>
> Opinions?  Other ideas?
>
>
>
>
> [1] [PATCH v14 00/21] QAPI/QOM work for non-scalar object properties
> (actually v15)
> Message-Id: <1475246744-29302-1-git-send-email-berrange@redhat.com>
> http://lists.gnu.org/archive/html/qemu-devel/2016-09/msg08238.html
>
> [2] [RFC PATCH] block: Crude initial implementation of -blockdev
> Message-Id: <1485968933-9162-1-git-send-email-armbru@redhat.com>
> http://lists.gnu.org/archive/html/qemu-devel/2017-02/msg00182.html
>
> [3] Message-ID: <87h989ncse.fsf@dusky.pond.sub.org>
> http://lists.gnu.org/archive/html/qemu-devel/2016-10/msg04046.html

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-04  9:44       ` Markus Armbruster
@ 2017-02-06 10:20         ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 55+ messages in thread
From: Dr. David Alan Gilbert @ 2017-02-06 10:20 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

* Markus Armbruster (armbru@redhat.com) wrote:
> "Dr. David Alan Gilbert" <dgilbert@redhat.com> writes:
> 
> > * Markus Armbruster (armbru@redhat.com) wrote:
> >> "Dr. David Alan Gilbert" <dgilbert@redhat.com> writes:
> >> 
> >> > * Markus Armbruster (armbru@redhat.com) wrote:
> [...]
> >> >> === Structured values ===
> >> >> 
> >> >> The dotted key convention messes with KEY syntax to permit structured
> >> >> values.  Works, but the more conventional way to support structured
> >> >> values is a syntax for structured values.  
> >> >> 
> >> >> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
> >> >> ... ] for arrays.  Looks like this:
> >> >> 
> >> >>     -drive 'driver=quorum,
> >> >>             child=[{ driver=file, filename=disk1.img },
> >> >>                    { driver=host_device, filename=/dev/sdb },
> >> >>                    { driver=nbd, host=localhost } ]'
> >> >> 
> >> >> Again, lines broken and indented for legibility; you need to join them
> >> >> for actual use.
> >> >> 
> >> >> There's a syntactic catch, though: a value of the form [ ... ] can
> >> >> either be an array or a string.  Which one it is depends on the type of
> >> >> the key.  To parse this syntax, you need to know the types, unlike JSON
> >> >> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
> >> >> '[', which feels impractical.
> >> >
> >> > I don't understand why [ could imply a string.
> >> 
> >> Consider
> >> 
> >>     -drive 'driver=quorum,
> >>             child=[{ driver=file, filename={"foolish":"name"} },
> >>                    { driver=host_device, filename=/dev/sdb },
> >>                    { driver=nbd, host=[::1] } ]'
> >> 
> >> Three KEY=VALUE have their VALUE start with '[' or '{':
> >> 
> >> * child=[{ driver=file, ...
> >> 
> >>   This is an array, not a string, because child is an array.
> >> 
> >> * host=[::1]
> >> 
> >>   This is a string, not an array containing the string "::1", because
> >>   host is a string.
> >
> > Why is that accepted as valid input? Can't that just spit a
> > 'I wanted a string not an array' ?
> 
> Because "[::1]" is a perfectly valid string.
> 
> It's also a valid array.  Unless the parser knows what type to expect
> here, it cannot decide how to parse it.  That's why I wrote "to parse
> this syntax, you need to know the types".

I think that's fine; the parser would just parse something starting with
a [ as an array, always.  You just define that and then everyone knows
that you'd better " it if you've got a [ in your string.

Dave
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-04 12:21 ` [Qemu-devel] " Fam Zheng
  2017-02-04 12:44   ` Paolo Bonzini
  2017-02-04 13:35   ` Markus Armbruster
@ 2017-02-06 11:08   ` Daniel P. Berrange
  2 siblings, 0 replies; 55+ messages in thread
From: Daniel P. Berrange @ 2017-02-06 11:08 UTC (permalink / raw)
  To: Fam Zheng
  Cc: Markus Armbruster, Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

On Sat, Feb 04, 2017 at 08:21:50PM +0800, Fam Zheng wrote:
> On Thu, 02/02 20:42, Markus Armbruster wrote:
> > === Comparison ===
> > 
> > In my opinion, dotted keys are weird and ugly, but at least they don't
> > add to the quoting mess.  Structured values look better, except when
> > they do add to the quoting mess.
> > 
> > I'm having a hard time deciding which one I like less :)
> > 
> > Opinions?  Other ideas?
> 
> Here's my poor attempt:
> 
> The dotted syntax, as the simpler of two, can cover everyday use very well.  If
> we introduce an "@reference" extension to it which can help the expresiveness,
> we can have a hybrid solution. It's not the cleanest interface and syntax, but
> escaping, nesting and quoting can all be divide-and-conqured in their optimal way.
> What I'm imagining is something like:
> 
>     -json "id=children0,text=[
>                 { 'driver': 'null-co://' },
>                 { 'driver': 'null-co://' },
>                 { 'driver': 'null-co://' }
>             ]" \
>     -dot \
>       id=quorum0,driver=quorum,read-pattern=fifo,vote-threshold=1,children=@children0 \
>     -drive if=virtio,id=primary-disk0,driver=qcow2,file=@quorum0
> 
> IOW "-json" and "-dot" define options that is intended to be referenced from
> other dotted keys (quorum0 uses children0, and in turn primary-disk0 uses
> quorum0).
> 
> Note: "-dot" here could be replaced with a -blockdev in this specific case but
> I'm demostrating it just in case it is useful generically.

I'd be pretty wary of inventing this kind of magic. Having references
might sound neat, but I think this is pretty alien from POV of the code
generating such CLIs in libvirt. I think we'd sooner just use pure json
for everything than support such a feature in libvirt.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://entangle-photo.org       -o-    http://search.cpan.org/~danberr/ :|

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
                   ` (8 preceding siblings ...)
  2017-02-06  6:57 ` Markus Armbruster
@ 2017-02-06 13:23 ` Kevin Wolf
  2017-02-06 15:36   ` Markus Armbruster
  2017-02-24 16:04 ` Markus Armbruster
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 55+ messages in thread
From: Kevin Wolf @ 2017-02-06 13:23 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: qemu-devel, qemu-block, Peter Krempa, Eric Blake, Daniel P. Berrange

Am 02.02.2017 um 20:42 hat Markus Armbruster geschrieben:
> = Brief recap of dotted key convention =
> 
> We'll discuss use of dotted key convention later, so let me explain it
> briefly for the readers who don't know it already.
> 
> The dotted key convention interprets the KEY part as a sequence of names
> separated by dots.  If a name looks like an integer *handwave*, it's an
> array index, else it's an object member name.

I think that's not really what we have, but just what it looks like to
you from your perspective of someone who wants to write a parser that
generically parses these things into nested QObjects.

In reality, pretty much all users of the dotted syntax know from context
whether this is an array or an object. In the former case they call
something like qdict_array_entries()/split(), and in the latter case
qemu_opts_absorb_qdict(). Both of them are happy with numeric keys.

The one exception is qdict_crumple(), which already is a parser like
you're intending to write. The difference is that it's used only in very
few specific cases where we know that the assumption holds true.

In other words: To do things properly, you'd have to look at the schema.

> = Structured option argument syntax =
> 
> == JSON ==
> [...]
> There's also the -drive file=json:... syntax.  It's a bad fit for
> QemuOpts, because QemuOpts and JSON fight for the comma.  I'd show you
> if I could get it to work.

Just double all the commas in the JSON object. It's not really that hard
to come up with something working, but it makes it even uglier than
plain JSON on the command line.

Bonus: You get to guess which options are parsed by QemuOpts and which
aren't. qemu-img usually takes parameters directs from argv, so doubling
the comma there like you have to in -drive will result in an error.

> We obviously can't replace QemuOpts with JSON.  But accepting JSON in
> addition to QemuOpts is a debatable feature: it lets management
> applications reuse the code to build QMP arguments for option arguments.

Management applications already have working code for the existing
syntax, they might not want to switch just because (and probe whether
qemu is new enough to even support JSON for QemuOpts).

When I talked to Peter, his concern wasn't really about what the exact
syntax was, but just that the content is a 1:1 mapping of QMP arguments.

I take this as a sign that we should find something that works well
for human users, and management tools can easily cope with whatever we
choose.

> === Dotted keys ===
> 
> One sufficiently powerful syntax extension already exists: the dotted
> key convention.  It's syntactically unambiguous only when none of the
> KEYs involved contains '.'  To adopt it across the board, we'd have to
> outlaw '.' in KEYs.  QAPI outlaws '.' already, but we have a bunch of
> QOM properties names with '.'.  We'd have to rename at least the ones
> that need to be accessible in -object.
> 
> Dotted keys can't express member names that look like integers.  We'd
> have to outlaw them at least for the objects that are accessible on the
> command line.  Once again, QAPI outlaws such names already.  QOM is
> anarchy when it comes to names, however.
> 
> The way dotted keys do arrays is inconsistent with how QOM's automatic
> arrayification (commit 3396590) do them: foo.0 vs. foo[0].  Backward
> compatibility makes changing the dotted key convention awkward.  Perhaps
> we can still change QOM.

Dotted key syntax is a bit longwinded, but it's the simplest thinkable
extension of key=value and seems to be relatively easy to implement; the
necessary renaming should be possible to do.

This is not perfect for human users because of its repetitive nature,
but it could be the first step for 2.9.

> === Structured values ===
> 
> The dotted key convention messes with KEY syntax to permit structured
> values.  Works, but the more conventional way to support structured
> values is a syntax for structured values.  
> 
> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
> ... ] for arrays.  Looks like this:
> 
>     -drive 'driver=quorum,
>             child=[{ driver=file, filename=disk1.img },
>                    { driver=host_device, filename=/dev/sdb },
>                    { driver=nbd, host=localhost } ]'
> 
> Again, lines broken and indented for legibility; you need to join them
> for actual use.

This looks more like what you really want to use. However, being able to
write a={b=x,c=y} for a.b=x,a.c=y is really just syntactic sugar and
could be a second step after we got the basics working.

Note that treating it simply as syntactic sugar for the expanded dotted
form would also allow mixing (and I think that's a good thing):

    -drive 'driver=qcow2,
            backing.file.filename=backing.qcow2,
            file={driver=file, filename=overlay.qcow2, aio=native}'

Or even add to a previously defined thing, which should make Max happy
when he forgot a nested option at first:

    -drive 'driver=qcow2,
            file={driver=nbd,host=localhost},
            lazy-refcounts=on,
            file.port=1234'

> There's a syntactic catch, though: a value of the form [ ... ] can
> either be an array or a string.  Which one it is depends on the type of
> the key.  To parse this syntax, you need to know the types, unlike JSON
> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
> '[', which feels impractical.

We would have to look at the schema and only treat it as a nested object
or an array if the expected type has one there.

Your other mail says that even this doesn't work because of "any" types,
but I don't think this is a real problem: In that case, you simply use
the type that we always used, i.e. string. That's the fully backwards
compatible way.

Want to make use of the shiny new QemuOpts and get things parsed into
a nested object? Well, provide a real schema instead of "any" then.

> But wait, there's another syntactic catch: in traditional QemuOpts, a
> value ends at the next unescaped ',' or '\0'.  Inside an object, it now
> also ends at the next unescaped '}', and inside an array, at the next
> unescaped ']'.  Or perhaps at the next space (the example above assumes
> it does).  That means we either have to provide a way to escape '}', ']'
> and space, or find another way to delimit string values, say require '"'
> around strings whenever the string contains "funny" characters.
> 
> So, if escaped ',' wasn't ugly and confusing enough for you...

This is actually the part that troubles me the most about adding such a
syntax with new special characters. Otherwise it's pretty close to
optimal, in my opinion.

Kevin

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-06 13:23 ` Kevin Wolf
@ 2017-02-06 15:36   ` Markus Armbruster
  2017-02-06 16:33     ` Daniel P. Berrange
                       ` (2 more replies)
  0 siblings, 3 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-06 15:36 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Peter Krempa, qemu-devel, qemu-block

Kevin Wolf <kwolf@redhat.com> writes:

> Am 02.02.2017 um 20:42 hat Markus Armbruster geschrieben:
>> = Brief recap of dotted key convention =
>> 
>> We'll discuss use of dotted key convention later, so let me explain it
>> briefly for the readers who don't know it already.
>> 
>> The dotted key convention interprets the KEY part as a sequence of names
>> separated by dots.  If a name looks like an integer *handwave*, it's an
>> array index, else it's an object member name.
>
> I think that's not really what we have, but just what it looks like to
> you from your perspective of someone who wants to write a parser that
> generically parses these things into nested QObjects.
>
> In reality, pretty much all users of the dotted syntax know from context
> whether this is an array or an object. In the former case they call
> something like qdict_array_entries()/split(), and in the latter case
> qemu_opts_absorb_qdict(). Both of them are happy with numeric keys.
>
> The one exception is qdict_crumple(), which already is a parser like
> you're intending to write. The difference is that it's used only in very
> few specific cases where we know that the assumption holds true.
>
> In other words: To do things properly, you'd have to look at the schema.

See discussion of 'any' types below.

>> = Structured option argument syntax =
>> 
>> == JSON ==
>> [...]
>> There's also the -drive file=json:... syntax.  It's a bad fit for
>> QemuOpts, because QemuOpts and JSON fight for the comma.  I'd show you
>> if I could get it to work.
>
> Just double all the commas in the JSON object. It's not really that hard
> to come up with something working, but it makes it even uglier than
> plain JSON on the command line.

I tried, I failed, I suck :)

> Bonus: You get to guess which options are parsed by QemuOpts and which
> aren't. qemu-img usually takes parameters directs from argv, so doubling
> the comma there like you have to in -drive will result in an error.
>
>> We obviously can't replace QemuOpts with JSON.  But accepting JSON in
>> addition to QemuOpts is a debatable feature: it lets management
>> applications reuse the code to build QMP arguments for option arguments.
>
> Management applications already have working code for the existing
> syntax, they might not want to switch just because (and probe whether
> qemu is new enough to even support JSON for QemuOpts).

If it was my code, and that code converted from an internal
representation of JSON either to JSON or QemuOpts as libvirt does, I'd
gladly ditch the second conversion.  Less code, fewer bugs.

Note that "less code, fewer bugs" applies both to the management
application and QEMU: parsing KEY=VALUE,... in dotted key convention to
QAPI object is additional code that is tricky in places, e.g. where it
auto-converts string values.

> When I talked to Peter, his concern wasn't really about what the exact
> syntax was, but just that the content is a 1:1 mapping of QMP arguments.
>
> I take this as a sign that we should find something that works well
> for human users, and management tools can easily cope with whatever we
> choose.
>
>> === Dotted keys ===
>> 
>> One sufficiently powerful syntax extension already exists: the dotted
>> key convention.  It's syntactically unambiguous only when none of the
>> KEYs involved contains '.'  To adopt it across the board, we'd have to
>> outlaw '.' in KEYs.  QAPI outlaws '.' already, but we have a bunch of
>> QOM properties names with '.'.  We'd have to rename at least the ones
>> that need to be accessible in -object.
>> 
>> Dotted keys can't express member names that look like integers.  We'd
>> have to outlaw them at least for the objects that are accessible on the
>> command line.  Once again, QAPI outlaws such names already.  QOM is
>> anarchy when it comes to names, however.
>> 
>> The way dotted keys do arrays is inconsistent with how QOM's automatic
>> arrayification (commit 3396590) do them: foo.0 vs. foo[0].  Backward
>> compatibility makes changing the dotted key convention awkward.  Perhaps
>> we can still change QOM.
>
> Dotted key syntax is a bit longwinded, but it's the simplest thinkable
> extension of key=value and seems to be relatively easy to implement; the
> necessary renaming should be possible to do.
>
> This is not perfect for human users because of its repetitive nature,
> but it could be the first step for 2.9.
>
>> === Structured values ===
>> 
>> The dotted key convention messes with KEY syntax to permit structured
>> values.  Works, but the more conventional way to support structured
>> values is a syntax for structured values.  
>> 
>> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
>> ... ] for arrays.  Looks like this:
>> 
>>     -drive 'driver=quorum,
>>             child=[{ driver=file, filename=disk1.img },
>>                    { driver=host_device, filename=/dev/sdb },
>>                    { driver=nbd, host=localhost } ]'
>> 
>> Again, lines broken and indented for legibility; you need to join them
>> for actual use.
>
> This looks more like what you really want to use. However, being able to
> write a={b=x,c=y} for a.b=x,a.c=y is really just syntactic sugar and
> could be a second step after we got the basics working.
>
> Note that treating it simply as syntactic sugar for the expanded dotted
> form would also allow mixing (and I think that's a good thing):
>
>     -drive 'driver=qcow2,
>             backing.file.filename=backing.qcow2,
>             file={driver=file, filename=overlay.qcow2, aio=native}'
>
> Or even add to a previously defined thing, which should make Max happy
> when he forgot a nested option at first:
>
>     -drive 'driver=qcow2,
>             file={driver=nbd,host=localhost},
>             lazy-refcounts=on,
>             file.port=1234'
>
>> There's a syntactic catch, though: a value of the form [ ... ] can
>> either be an array or a string.  Which one it is depends on the type of
>> the key.  To parse this syntax, you need to know the types, unlike JSON
>> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
>> '[', which feels impractical.
>
> We would have to look at the schema and only treat it as a nested object
> or an array if the expected type has one there.
>
> Your other mail says that even this doesn't work because of "any" types,
> but I don't think this is a real problem: In that case, you simply use
> the type that we always used, i.e. string. That's the fully backwards
> compatible way.
>
> Want to make use of the shiny new QemuOpts and get things parsed into
> a nested object? Well, provide a real schema instead of "any" then.

Sadly, this is somewhere between impractical and impossible.

The QAPI schema is fixed at compile-time.  It needs to be, because its
purpose is to let us generate code we can compile and link into QEMU.

We use 'any' basically for things that aren't fixed at compile-time.

Example: qdev properties and device_add

Even though traditional qdev properties are fixed at compile time, they
are not known until run-time.  That's because they're defined in the
device models, and the registry of device models is only built at
run-time.

I believe this would've been fixable with some effort: make the devices
define suitable pieces of schema, and collect them somehow at
compile-time.  "Would've been", because progress!  See next example.

Example: QOM properties and object-add, qom-set, qom-get

QOM properties are created at run-time.  They cannot be fixed at
compile-time *by design*.  I always hated that part of the design, but I
was assured we absolutely need that much rope^Wflexibility.

So, all we know about the "props" argument of object-add is that it's a
JSON object.  The tightest imaginable QAPI schema would be an 'object'
type, except that doesn't exist, so we settle for 'any'.

-object unwraps "props" to get a flat QemuOpts, but let's ignore that
and pretend we'd want to parse -object qom-type=T,id=ID,props=...

If we made "props" an 'object' in the schema, we'd know we need to parse
the right hand side of props={foo=[bar]} as object, not as string.  We'd
still not know (and cannot know at compile-time) whether to parse [bar]
as array or as string.

But it gets worse.  Consider

    props={foo=[bar,baz=]}

If foo turns out to an array of string, we need to parse this like JSON

    { "foo": [ "bar", "baz=" ] }

But if it's of string type, we need to parse it like JSON

    { "foo": "[bar", "baz": ... }

This isn't just a "can't decide between integer and string" problem,
which Dan solved by auto-converting strings in the input visitor,
i.e. by delaying some parsing of terminals.  It's a "can't even figure
out the tree structure" problem.

I'm afraid there's no way to make this syntax work without requiring
some kind of quotes for at least "funny" strings.  Which makes me go
"okay, what's the advantage over plain JSON again?"

>> But wait, there's another syntactic catch: in traditional QemuOpts, a
>> value ends at the next unescaped ',' or '\0'.  Inside an object, it now
>> also ends at the next unescaped '}', and inside an array, at the next
>> unescaped ']'.  Or perhaps at the next space (the example above assumes
>> it does).  That means we either have to provide a way to escape '}', ']'
>> and space, or find another way to delimit string values, say require '"'
>> around strings whenever the string contains "funny" characters.
>> 
>> So, if escaped ',' wasn't ugly and confusing enough for you...
>
> This is actually the part that troubles me the most about adding such a
> syntax with new special characters. Otherwise it's pretty close to
> optimal, in my opinion.
>
> Kevin

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-06 15:36   ` Markus Armbruster
@ 2017-02-06 16:33     ` Daniel P. Berrange
  2017-02-06 17:24       ` Markus Armbruster
  2017-02-06 17:38     ` Paolo Bonzini
  2017-02-07  9:26     ` Kevin Wolf
  2 siblings, 1 reply; 55+ messages in thread
From: Daniel P. Berrange @ 2017-02-06 16:33 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

On Mon, Feb 06, 2017 at 04:36:50PM +0100, Markus Armbruster wrote:
> Kevin Wolf <kwolf@redhat.com> writes:
> > Want to make use of the shiny new QemuOpts and get things parsed into
> > a nested object? Well, provide a real schema instead of "any" then.
> 
> Sadly, this is somewhere between impractical and impossible.
> 
> The QAPI schema is fixed at compile-time.  It needs to be, because its
> purpose is to let us generate code we can compile and link into QEMU.
> 
> We use 'any' basically for things that aren't fixed at compile-time.
> 
> Example: qdev properties and device_add
> 
> Even though traditional qdev properties are fixed at compile time, they
> are not known until run-time.  That's because they're defined in the
> device models, and the registry of device models is only built at
> run-time.
> 
> I believe this would've been fixable with some effort: make the devices
> define suitable pieces of schema, and collect them somehow at
> compile-time.  "Would've been", because progress!  See next example.
> 
> Example: QOM properties and object-add, qom-set, qom-get
> 
> QOM properties are created at run-time.  They cannot be fixed at
> compile-time *by design*.  I always hated that part of the design, but I
> was assured we absolutely need that much rope^Wflexibility.
> 
> So, all we know about the "props" argument of object-add is that it's a
> JSON object.  The tightest imaginable QAPI schema would be an 'object'
> type, except that doesn't exist, so we settle for 'any'.

The CLI parser is executing at runtime though, so I would think
it should need to care if the schema its using to parse the CLI
args was defined at build time or execution time. It merely needs
the schema to be present at the time it parses the data.

So is there a way we dynamically report the info we need by improving
visitor support for QOM somehow.


> This isn't just a "can't decide between integer and string" problem,
> which Dan solved by auto-converting strings in the input visitor,
> i.e. by delaying some parsing of terminals.  It's a "can't even figure
> out the tree structure" problem.

Yep, my gross hack was because I was explicitly trying to avoid making
any changes to QemuOpts. I wanted to tokenize the string without knowing
anything about the schema, then convert to QDict, and then visit it to
create the object. Only the 3rd step had any kind of access to QOM type
information.

It feels like the gross hacks in this area could have been avoided if
I had been willing to sacrifice the layering to make schema info
available to the QemuOpts parser somehow. Then it could have dynamically
queried the QOM props to determine their expected types and parses the
opts accordingly.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://entangle-photo.org       -o-    http://search.cpan.org/~danberr/ :|

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-06 16:33     ` Daniel P. Berrange
@ 2017-02-06 17:24       ` Markus Armbruster
  2017-02-06 17:50         ` Daniel P. Berrange
  0 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2017-02-06 17:24 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

"Daniel P. Berrange" <berrange@redhat.com> writes:

> On Mon, Feb 06, 2017 at 04:36:50PM +0100, Markus Armbruster wrote:
>> Kevin Wolf <kwolf@redhat.com> writes:
>> > Want to make use of the shiny new QemuOpts and get things parsed into
>> > a nested object? Well, provide a real schema instead of "any" then.
>> 
>> Sadly, this is somewhere between impractical and impossible.
>> 
>> The QAPI schema is fixed at compile-time.  It needs to be, because its
>> purpose is to let us generate code we can compile and link into QEMU.
>> 
>> We use 'any' basically for things that aren't fixed at compile-time.
>> 
>> Example: qdev properties and device_add
>> 
>> Even though traditional qdev properties are fixed at compile time, they
>> are not known until run-time.  That's because they're defined in the
>> device models, and the registry of device models is only built at
>> run-time.
>> 
>> I believe this would've been fixable with some effort: make the devices
>> define suitable pieces of schema, and collect them somehow at
>> compile-time.  "Would've been", because progress!  See next example.
>> 
>> Example: QOM properties and object-add, qom-set, qom-get
>> 
>> QOM properties are created at run-time.  They cannot be fixed at
>> compile-time *by design*.  I always hated that part of the design, but I
>> was assured we absolutely need that much rope^Wflexibility.
>> 
>> So, all we know about the "props" argument of object-add is that it's a
>> JSON object.  The tightest imaginable QAPI schema would be an 'object'
>> type, except that doesn't exist, so we settle for 'any'.
>
> The CLI parser is executing at runtime though, so I would think
> it should need to care if the schema its using to parse the CLI
> args was defined at build time or execution time. It merely needs
> the schema to be present at the time it parses the data.

Whatever "the schema" is, it can't be the QAPI schema, and it can't be
used by generating code (which is how the visitors use the QAPI schema).

Let's assume for the moment that QOM is the only source of schema stuff
that becomes known only at run-time.  Then "the schema" is an
amalgamation of the QAPI schema and QOM reflection.  I say "reflection",
not "schema", because there is no QOM schema, only ways to examine (the
current structure of) QOM objects.

> So is there a way we dynamically report the info we need by improving
> visitor support for QOM somehow.

To parse the argument of -object, we need to create a QOM object of the
type given by qom-type, so we can examine it to find its properties and
their types.

Consider

    -object foo=[eins,qom-type=zwei,bar={x=y,qom-type=drei,baz=}]

What's the value of qom-type?  Remember, -object has "props" unwrapped
so that everything stays flat.

If foo is an array, qom-type is missing.

If foo is a string, then qom-type is zwei.  Except when bar is a string,
because then it gets overridden to drei.

This way is madness.

Want still more?  Okay.  What if setting a property adds, deletes or
modifies other properties?  Or some other stimulus beyond our control
does?  Obviously not possible while we create a new object (which nobody
else can find just yet), but my point is that in the fully general case,
QOM reflection comes with TOCTTOU traps.

>> This isn't just a "can't decide between integer and string" problem,
>> which Dan solved by auto-converting strings in the input visitor,
>> i.e. by delaying some parsing of terminals.  It's a "can't even figure
>> out the tree structure" problem.
>
> Yep, my gross hack was because I was explicitly trying to avoid making
> any changes to QemuOpts. I wanted to tokenize the string without knowing
> anything about the schema, then convert to QDict, and then visit it to
> create the object. Only the 3rd step had any kind of access to QOM type
> information.

Exactly.

> It feels like the gross hacks in this area could have been avoided if
> I had been willing to sacrifice the layering to make schema info
> available to the QemuOpts parser somehow.

We briefly discussed an alternative design that can use the *QAPI*
schema to direct the parse: an input visitor that parses
KEY=VALUE,... straight into a QAPI object.

>                                           Then it could have dynamically
> queried the QOM props to determine their expected types and parses the
> opts accordingly.

Won't do, I'm afraid.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-06 15:36   ` Markus Armbruster
  2017-02-06 16:33     ` Daniel P. Berrange
@ 2017-02-06 17:38     ` Paolo Bonzini
  2017-02-06 18:12       ` Markus Armbruster
  2017-02-07  9:26     ` Kevin Wolf
  2 siblings, 1 reply; 55+ messages in thread
From: Paolo Bonzini @ 2017-02-06 17:38 UTC (permalink / raw)
  To: Markus Armbruster, Kevin Wolf; +Cc: qemu-devel, qemu-block



On 06/02/2017 16:36, Markus Armbruster wrote:
> Example: QOM properties and object-add, qom-set, qom-get
> 
> QOM properties are created at run-time.  They cannot be fixed at
> compile-time *by design*.  I always hated that part of the design, but I
> was assured we absolutely need that much rope^Wflexibility.

QOM now supports class properties.  We can convert the wide majority of
them, including qdev's "static" properties, to class properties.

Paolo

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-06 17:24       ` Markus Armbruster
@ 2017-02-06 17:50         ` Daniel P. Berrange
  2017-02-06 18:56           ` Markus Armbruster
  0 siblings, 1 reply; 55+ messages in thread
From: Daniel P. Berrange @ 2017-02-06 17:50 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

On Mon, Feb 06, 2017 at 06:24:42PM +0100, Markus Armbruster wrote:
> "Daniel P. Berrange" <berrange@redhat.com> writes:
> 
> > On Mon, Feb 06, 2017 at 04:36:50PM +0100, Markus Armbruster wrote:
> >> Kevin Wolf <kwolf@redhat.com> writes:
> >> > Want to make use of the shiny new QemuOpts and get things parsed into
> >> > a nested object? Well, provide a real schema instead of "any" then.
> >> 
> >> Sadly, this is somewhere between impractical and impossible.
> >> 
> >> The QAPI schema is fixed at compile-time.  It needs to be, because its
> >> purpose is to let us generate code we can compile and link into QEMU.
> >> 
> >> We use 'any' basically for things that aren't fixed at compile-time.
> >> 
> >> Example: qdev properties and device_add
> >> 
> >> Even though traditional qdev properties are fixed at compile time, they
> >> are not known until run-time.  That's because they're defined in the
> >> device models, and the registry of device models is only built at
> >> run-time.
> >> 
> >> I believe this would've been fixable with some effort: make the devices
> >> define suitable pieces of schema, and collect them somehow at
> >> compile-time.  "Would've been", because progress!  See next example.
> >> 
> >> Example: QOM properties and object-add, qom-set, qom-get
> >> 
> >> QOM properties are created at run-time.  They cannot be fixed at
> >> compile-time *by design*.  I always hated that part of the design, but I
> >> was assured we absolutely need that much rope^Wflexibility.
> >> 
> >> So, all we know about the "props" argument of object-add is that it's a
> >> JSON object.  The tightest imaginable QAPI schema would be an 'object'
> >> type, except that doesn't exist, so we settle for 'any'.
> >
> > The CLI parser is executing at runtime though, so I would think
> > it should need to care if the schema its using to parse the CLI
> > args was defined at build time or execution time. It merely needs
> > the schema to be present at the time it parses the data.
> 
> Whatever "the schema" is, it can't be the QAPI schema, and it can't be
> used by generating code (which is how the visitors use the QAPI schema).
> 
> Let's assume for the moment that QOM is the only source of schema stuff
> that becomes known only at run-time.  Then "the schema" is an
> amalgamation of the QAPI schema and QOM reflection.  I say "reflection",
> not "schema", because there is no QOM schema, only ways to examine (the
> current structure of) QOM objects.
> 
> > So is there a way we dynamically report the info we need by improving
> > visitor support for QOM somehow.
> 
> To parse the argument of -object, we need to create a QOM object of the
> type given by qom-type, so we can examine it to find its properties and
> their types.
> 
> Consider
> 
>     -object foo=[eins,qom-type=zwei,bar={x=y,qom-type=drei,baz=}]
> 
> What's the value of qom-type?  Remember, -object has "props" unwrapped
> so that everything stays flat.
> 
> If foo is an array, qom-type is missing.
> 
> If foo is a string, then qom-type is zwei.  Except when bar is a string,
> because then it gets overridden to drei.

That's a strange syntax you've used for illustration there - a half
way between json and nested-dotted syntax. For pure json syntax it
would be a clear if qom-type was missing at the top level. for nested
dotted syntax, it again seems clear to me - split on ',' and find the
unqualified qom-type key (or the leading default arg)


Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://entangle-photo.org       -o-    http://search.cpan.org/~danberr/ :|

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-06 17:38     ` Paolo Bonzini
@ 2017-02-06 18:12       ` Markus Armbruster
  2017-02-06 21:52         ` Paolo Bonzini
  0 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2017-02-06 18:12 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Kevin Wolf, qemu-devel, qemu-block

Paolo Bonzini <pbonzini@redhat.com> writes:

> On 06/02/2017 16:36, Markus Armbruster wrote:
>> Example: QOM properties and object-add, qom-set, qom-get
>> 
>> QOM properties are created at run-time.  They cannot be fixed at
>> compile-time *by design*.  I always hated that part of the design, but I
>> was assured we absolutely need that much rope^Wflexibility.
>
> QOM now supports class properties.  We can convert the wide majority of
> them, including qdev's "static" properties, to class properties.

Won't help object-add as long as dynamic properties remain.  I'd welcome
such a conversion anyway.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-06 17:50         ` Daniel P. Berrange
@ 2017-02-06 18:56           ` Markus Armbruster
  0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-06 18:56 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

Note: a bit more context restored.

"Daniel P. Berrange" <berrange@redhat.com> writes:

> On Mon, Feb 06, 2017 at 06:24:42PM +0100, Markus Armbruster wrote:
>> "Daniel P. Berrange" <berrange@redhat.com> writes:
>> 
>> > On Mon, Feb 06, 2017 at 04:36:50PM +0100, Markus Armbruster wrote:
>> >> Kevin Wolf <kwolf@redhat.com> writes:
>> >> 
>> >> > Am 02.02.2017 um 20:42 hat Markus Armbruster geschrieben:
[...]
>> >> >> === Structured values ===
>> >> >> 
>> >> >> The dotted key convention messes with KEY syntax to permit structured
>> >> >> values.  Works, but the more conventional way to support structured
>> >> >> values is a syntax for structured values.  
>> >> >> 
>> >> >> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
>> >> >> ... ] for arrays.  Looks like this:
>> >> >> 
>> >> >>     -drive 'driver=quorum,
>> >> >>             child=[{ driver=file, filename=disk1.img },
>> >> >>                    { driver=host_device, filename=/dev/sdb },
>> >> >>                    { driver=nbd, host=localhost } ]'
>> >> >> 
>> >> >> Again, lines broken and indented for legibility; you need to join them
>> >> >> for actual use.
>> >> >
>> >> > This looks more like what you really want to use. However, being able to
>> >> > write a={b=x,c=y} for a.b=x,a.c=y is really just syntactic sugar and
>> >> > could be a second step after we got the basics working.
>> >> >
>> >> > Note that treating it simply as syntactic sugar for the expanded dotted
>> >> > form would also allow mixing (and I think that's a good thing):
>> >> >
>> >> >     -drive 'driver=qcow2,
>> >> >             backing.file.filename=backing.qcow2,
>> >> >             file={driver=file, filename=overlay.qcow2, aio=native}'
>> >> >
>> >> > Or even add to a previously defined thing, which should make Max happy
>> >> > when he forgot a nested option at first:
>> >> >
>> >> >     -drive 'driver=qcow2,
>> >> >             file={driver=nbd,host=localhost},
>> >> >             lazy-refcounts=on,
>> >> >             file.port=1234'
>> >> >
>> >> >> There's a syntactic catch, though: a value of the form [ ... ] can
>> >> >> either be an array or a string.  Which one it is depends on the type of
>> >> >> the key.  To parse this syntax, you need to know the types, unlike JSON
>> >> >> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
>> >> >> '[', which feels impractical.
>> >> >
>> >> > We would have to look at the schema and only treat it as a nested object
>> >> > or an array if the expected type has one there.
>> >> >
>> >> > Your other mail says that even this doesn't work because of "any" types,
>> >> > but I don't think this is a real problem: In that case, you simply use
>> >> > the type that we always used, i.e. string. That's the fully backwards
>> >> > compatible way.
>> >> >
>> >> > Want to make use of the shiny new QemuOpts and get things parsed into
>> >> > a nested object? Well, provide a real schema instead of "any" then.
>> >> 
>> >> Sadly, this is somewhere between impractical and impossible.
>> >> 
>> >> The QAPI schema is fixed at compile-time.  It needs to be, because its
>> >> purpose is to let us generate code we can compile and link into QEMU.
>> >> 
>> >> We use 'any' basically for things that aren't fixed at compile-time.
>> >> 
>> >> Example: qdev properties and device_add
>> >> 
>> >> Even though traditional qdev properties are fixed at compile time, they
>> >> are not known until run-time.  That's because they're defined in the
>> >> device models, and the registry of device models is only built at
>> >> run-time.
>> >> 
>> >> I believe this would've been fixable with some effort: make the devices
>> >> define suitable pieces of schema, and collect them somehow at
>> >> compile-time.  "Would've been", because progress!  See next example.
>> >> 
>> >> Example: QOM properties and object-add, qom-set, qom-get
>> >> 
>> >> QOM properties are created at run-time.  They cannot be fixed at
>> >> compile-time *by design*.  I always hated that part of the design, but I
>> >> was assured we absolutely need that much rope^Wflexibility.
>> >> 
>> >> So, all we know about the "props" argument of object-add is that it's a
>> >> JSON object.  The tightest imaginable QAPI schema would be an 'object'
>> >> type, except that doesn't exist, so we settle for 'any'.
>> >
>> > The CLI parser is executing at runtime though, so I would think
>> > it should need to care if the schema its using to parse the CLI
>> > args was defined at build time or execution time. It merely needs
>> > the schema to be present at the time it parses the data.
>> 
>> Whatever "the schema" is, it can't be the QAPI schema, and it can't be
>> used by generating code (which is how the visitors use the QAPI schema).
>> 
>> Let's assume for the moment that QOM is the only source of schema stuff
>> that becomes known only at run-time.  Then "the schema" is an
>> amalgamation of the QAPI schema and QOM reflection.  I say "reflection",
>> not "schema", because there is no QOM schema, only ways to examine (the
>> current structure of) QOM objects.
>> 
>> > So is there a way we dynamically report the info we need by improving
>> > visitor support for QOM somehow.
>> 
>> To parse the argument of -object, we need to create a QOM object of the
>> type given by qom-type, so we can examine it to find its properties and
>> their types.
>> 
>> Consider
>> 
>>     -object foo=[eins,qom-type=zwei,bar={x=y,qom-type=drei,baz=}]
>> 
>> What's the value of qom-type?  Remember, -object has "props" unwrapped
>> so that everything stays flat.
>> 
>> If foo is an array, qom-type is missing.
>> 
>> If foo is a string, then qom-type is zwei.  Except when bar is a string,
>> because then it gets overridden to drei.
>
> That's a strange syntax you've used for illustration there - a half
> way between json and nested-dotted syntax.

We're discussing section "=== Structured values ===" of my memo.  I
described the string vs. object/array ambiguity, Kevin suggested using
the QAPI schema as a solution, and I explained why it doesn't suffice.
You suggested we can have the necessary type information at run-time,
and I explained why that doesn't suffice, either, even if we assume QOM
is the only troublemaker here.

>                                            For pure json syntax it
> would be a clear if qom-type was missing at the top level.

That's section "== JSON ==".  No argument.

>                                                            for nested
> dotted syntax, it again seems clear to me - split on ',' and find the
> unqualified qom-type key (or the leading default arg)

That's section "=== Dotted keys ===".  No argument.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-06 18:12       ` Markus Armbruster
@ 2017-02-06 21:52         ` Paolo Bonzini
  2017-02-07  7:02           ` Markus Armbruster
  0 siblings, 1 reply; 55+ messages in thread
From: Paolo Bonzini @ 2017-02-06 21:52 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Kevin Wolf, qemu-devel, qemu-block



On 06/02/2017 19:12, Markus Armbruster wrote:
>> QOM now supports class properties.  We can convert the wide majority of
>> them, including qdev's "static" properties, to class properties.
> 
> Won't help object-add as long as dynamic properties remain.

Well, only as long as dynamic properties remain necessary for classes
that the user can create.  The main user of dynamic properties is
children properties.

Paolo

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-06 21:52         ` Paolo Bonzini
@ 2017-02-07  7:02           ` Markus Armbruster
  0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-07  7:02 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Kevin Wolf, qemu-devel, qemu-block

Paolo Bonzini <pbonzini@redhat.com> writes:

> On 06/02/2017 19:12, Markus Armbruster wrote:
>>> QOM now supports class properties.  We can convert the wide majority of
>>> them, including qdev's "static" properties, to class properties.
>> 
>> Won't help object-add as long as dynamic properties remain.
>
> Well, only as long as dynamic properties remain necessary for classes
> that the user can create.

Correct.

>                            The main user of dynamic properties is
> children properties.

Converting dynamic properties into static ones is a good idea, because
it simplifies reasoning about properties.  I'm afraid it'll be a rather
tedious job, and only at its end we'll be able to see what dynamic
properties remain.

Making -object blind to dynamic properties is a restriction unless these
properties are of no use there.  We can't know that now.  If we get
there and know, we'll have to protect that state somehow.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-06 15:36   ` Markus Armbruster
  2017-02-06 16:33     ` Daniel P. Berrange
  2017-02-06 17:38     ` Paolo Bonzini
@ 2017-02-07  9:26     ` Kevin Wolf
  2 siblings, 0 replies; 55+ messages in thread
From: Kevin Wolf @ 2017-02-07  9:26 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Peter Krempa, qemu-devel, qemu-block

Am 06.02.2017 um 16:36 hat Markus Armbruster geschrieben:
> >> === Structured values ===
> >> 
> >> The dotted key convention messes with KEY syntax to permit structured
> >> values.  Works, but the more conventional way to support structured
> >> values is a syntax for structured values.  
> >> 
> >> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
> >> ... ] for arrays.  Looks like this:
> >> 
> >>     -drive 'driver=quorum,
> >>             child=[{ driver=file, filename=disk1.img },
> >>                    { driver=host_device, filename=/dev/sdb },
> >>                    { driver=nbd, host=localhost } ]'
> >> 
> >> Again, lines broken and indented for legibility; you need to join them
> >> for actual use.
> >
> > This looks more like what you really want to use. However, being able to
> > write a={b=x,c=y} for a.b=x,a.c=y is really just syntactic sugar and
> > could be a second step after we got the basics working.
> >
> > Note that treating it simply as syntactic sugar for the expanded dotted
> > form would also allow mixing (and I think that's a good thing):
> >
> >     -drive 'driver=qcow2,
> >             backing.file.filename=backing.qcow2,
> >             file={driver=file, filename=overlay.qcow2, aio=native}'
> >
> > Or even add to a previously defined thing, which should make Max happy
> > when he forgot a nested option at first:
> >
> >     -drive 'driver=qcow2,
> >             file={driver=nbd,host=localhost},
> >             lazy-refcounts=on,
> >             file.port=1234'
> >
> >> There's a syntactic catch, though: a value of the form [ ... ] can
> >> either be an array or a string.  Which one it is depends on the type of
> >> the key.  To parse this syntax, you need to know the types, unlike JSON
> >> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
> >> '[', which feels impractical.
> >
> > We would have to look at the schema and only treat it as a nested object
> > or an array if the expected type has one there.
> >
> > Your other mail says that even this doesn't work because of "any" types,
> > but I don't think this is a real problem: In that case, you simply use
> > the type that we always used, i.e. string. That's the fully backwards
> > compatible way.
> >
> > Want to make use of the shiny new QemuOpts and get things parsed into
> > a nested object? Well, provide a real schema instead of "any" then.
> 
> Sadly, this is somewhere between impractical and impossible.
> 
> The QAPI schema is fixed at compile-time.  It needs to be, because its
> purpose is to let us generate code we can compile and link into QEMU.
> 
> We use 'any' basically for things that aren't fixed at compile-time.
> 
> Example: qdev properties and device_add
> 
> Even though traditional qdev properties are fixed at compile time, they
> are not known until run-time.  That's because they're defined in the
> device models, and the registry of device models is only built at
> run-time.
> 
> I believe this would've been fixable with some effort: make the devices
> define suitable pieces of schema, and collect them somehow at
> compile-time.  "Would've been", because progress!  See next example.

I think we might still be able to get there for -device. You won't be
able to set all QOM properties that could ever pop up during the life of
a device, but with -device I think you can't anyway, but just the good
old qdev properties.

Having a schema and generating all of the QOM boilerplate automatically
from it would probably be nice anyway.

> Example: QOM properties and object-add, qom-set, qom-get
> 
> QOM properties are created at run-time.  They cannot be fixed at
> compile-time *by design*.  I always hated that part of the design, but I
> was assured we absolutely need that much rope^Wflexibility.
> 
> So, all we know about the "props" argument of object-add is that it's a
> JSON object.  The tightest imaginable QAPI schema would be an 'object'
> type, except that doesn't exist, so we settle for 'any'.
> 
> -object unwraps "props" to get a flat QemuOpts, but let's ignore that
> and pretend we'd want to parse -object qom-type=T,id=ID,props=...
> 
> If we made "props" an 'object' in the schema, we'd know we need to parse
> the right hand side of props={foo=[bar]} as object, not as string.  We'd
> still not know (and cannot know at compile-time) whether to parse [bar]
> as array or as string.
> 
> But it gets worse.  Consider
> 
>     props={foo=[bar,baz=]}
> 
> If foo turns out to an array of string, we need to parse this like JSON
> 
>     { "foo": [ "bar", "baz=" ] }
> 
> But if it's of string type, we need to parse it like JSON
> 
>     { "foo": "[bar", "baz": ... }
> 
> This isn't just a "can't decide between integer and string" problem,
> which Dan solved by auto-converting strings in the input visitor,
> i.e. by delaying some parsing of terminals.  It's a "can't even figure
> out the tree structure" problem.
> 
> I'm afraid there's no way to make this syntax work without requiring
> some kind of quotes for at least "funny" strings.  Which makes me go
> "okay, what's the advantage over plain JSON again?"

Then don't make it work. As I said above:

> > Want to make use of the shiny new QemuOpts and get things parsed into
> > a nested object? Well, provide a real schema instead of "any" then.

So if you can't provide a real schema for a specific (sub)option, the
syntactic sugar simply doesn't work for this option and you get to use
longwinded explicit dotted keys. Not really a disaster either.

Now I see that this brings in some inconsistency, because the short
syntax would work for things like -blockdev (which is probably the
heaviest user of nesting) or -netdev, it might be possible to make it
work for -device, but it won't work for -object.

So there's a tradeoff between convenience and consistency here. You
could argue that having a more convenient way to specify things for
almost all options is nice and we definitely want it; or you could argue
that for consistency's sake the one remaining option means that we
shouldn't provide the convenient way anywhere.

Kevin

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
                   ` (9 preceding siblings ...)
  2017-02-06 13:23 ` Kevin Wolf
@ 2017-02-24 16:04 ` Markus Armbruster
  2017-02-24 16:39   ` Daniel P. Berrange
  2017-02-27 10:27 ` Markus Armbruster
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2017-02-24 16:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Kevin Wolf, Peter Krempa, Eric Blake, Daniel P. Berrange

Markus Armbruster <armbru@redhat.com> writes:

[...]
> === Dotted keys ===
>
> One sufficiently powerful syntax extension already exists: the dotted
> key convention.  It's syntactically unambiguous only when none of the
> KEYs involved contains '.'  To adopt it across the board, we'd have to
> outlaw '.' in KEYs.  QAPI outlaws '.' already,

*Except* in __RFQDN_ prefixes.

Say example.com needs to add a downstream extension to block driver
"raw".  Following QAPI rules, they add to to struct BlockdevOptionsRaw a
new optional member:

    '*__com.example_medium-rare': 'bool'

On the command line, this looks like

    -blockdev node-name=foo,driver=raw,__com.example_medium-rare=on,file.driver=file,file.filename=foo.img

Dotted keys parse this as a reference to member __com's member
example_medium-rare.

Possible solutions:

(a) Outlaw domain names with '_'.  If KEY starts with "__", everything
    up to the third '_' is an __RFQDN_ prefix.

(b) Outlaw '_' in the name part that follows __RFQDN_.  If KEY starts
    with "__", everything up to the last '_' is an __RFQDN_ prefix.

(c) Your bright idea.

I think (b) should do.  QAPI prefers '-' over '_' for new member names
anyway.

>                                                but we have a bunch of
> QOM properties names with '.'.  We'd have to rename at least the ones
> that need to be accessible in -object.
>
> Dotted keys can't express member names that look like integers.  We'd
> have to outlaw them at least for the objects that are accessible on the
> command line.  Once again, QAPI outlaws such names already.  QOM is
> anarchy when it comes to names, however.
>
> The way dotted keys do arrays is inconsistent with how QOM's automatic
> arrayification (commit 3396590) do them: foo.0 vs. foo[0].  Backward
> compatibility makes changing the dotted key convention awkward.  Perhaps
> we can still change QOM.

[...]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-24 16:04 ` Markus Armbruster
@ 2017-02-24 16:39   ` Daniel P. Berrange
  2017-02-24 17:17     ` Eric Blake
  0 siblings, 1 reply; 55+ messages in thread
From: Daniel P. Berrange @ 2017-02-24 16:39 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: qemu-devel, qemu-block, Kevin Wolf, Peter Krempa, Eric Blake

On Fri, Feb 24, 2017 at 05:04:34PM +0100, Markus Armbruster wrote:
> Markus Armbruster <armbru@redhat.com> writes:
> 
> [...]
> > === Dotted keys ===
> >
> > One sufficiently powerful syntax extension already exists: the dotted
> > key convention.  It's syntactically unambiguous only when none of the
> > KEYs involved contains '.'  To adopt it across the board, we'd have to
> > outlaw '.' in KEYs.  QAPI outlaws '.' already,
> 
> *Except* in __RFQDN_ prefixes.
> 
> Say example.com needs to add a downstream extension to block driver
> "raw".  Following QAPI rules, they add to to struct BlockdevOptionsRaw a
> new optional member:
> 
>     '*__com.example_medium-rare': 'bool'
> 
> On the command line, this looks like
> 
>     -blockdev node-name=foo,driver=raw,__com.example_medium-rare=on,file.driver=file,file.filename=foo.img
> 
> Dotted keys parse this as a reference to member __com's member
> example_medium-rare.
> 
> Possible solutions:
> 
> (a) Outlaw domain names with '_'.  If KEY starts with "__", everything
>     up to the third '_' is an __RFQDN_ prefix.
> 
> (b) Outlaw '_' in the name part that follows __RFQDN_.  If KEY starts
>     with "__", everything up to the last '_' is an __RFQDN_ prefix.
> 
> (c) Your bright idea.

Define a new downstream vendor naming convention. IMHO it is reasonable
to argue that the downstream vendor extensions are outside the scope of
backwards compatibility guarantees we normally apply for our CLI args.

Thus, simply say that vendors must replace all '.' with _ in their
namespace prefix. eg They should use '__com_example_medium.rare=on'
which would mean a property '__com_example_medium' which is a struct
containing a property rare with value on


Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://entangle-photo.org       -o-    http://search.cpan.org/~danberr/ :|

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-24 16:39   ` Daniel P. Berrange
@ 2017-02-24 17:17     ` Eric Blake
  2017-02-24 19:15       ` Markus Armbruster
  0 siblings, 1 reply; 55+ messages in thread
From: Eric Blake @ 2017-02-24 17:17 UTC (permalink / raw)
  To: Daniel P. Berrange, Markus Armbruster
  Cc: qemu-devel, qemu-block, Kevin Wolf, Peter Krempa

[-- Attachment #1: Type: text/plain, Size: 2896 bytes --]

On 02/24/2017 10:39 AM, Daniel P. Berrange wrote:
> On Fri, Feb 24, 2017 at 05:04:34PM +0100, Markus Armbruster wrote:
>> Markus Armbruster <armbru@redhat.com> writes:
>>
>> [...]
>>> === Dotted keys ===
>>>
>>> One sufficiently powerful syntax extension already exists: the dotted
>>> key convention.  It's syntactically unambiguous only when none of the
>>> KEYs involved contains '.'  To adopt it across the board, we'd have to
>>> outlaw '.' in KEYs.  QAPI outlaws '.' already,
>>
>> *Except* in __RFQDN_ prefixes.
>>

>> Possible solutions:
>>
>> (a) Outlaw domain names with '_'.  If KEY starts with "__", everything
>>     up to the third '_' is an __RFQDN_ prefix.

While there ARE valid DNS names with _ (such as
_http._sctp.www.example.com mentioned on
https://en.wikipedia.org/wiki/Hostname), we are at least told by RFC 952
that _ is not valid in hostnames.  Note that '-' is permitted, and that
transliterates to '_', so from the flattened name used in C code it's
harder to tell what is meant, but from the QMP side, I think we are
guaranteed that no RFQDN will confuse us with any extra _.

>>
>> (b) Outlaw '_' in the name part that follows __RFQDN_.  If KEY starts
>>     with "__", everything up to the last '_' is an __RFQDN_ prefix.

Reasonable enough, since we ask new interfaces to use '-' rather than
'_'. But does break existing vendors (a quick grep of RHEL 7.3
downstream finds at least:

qapi-schema.json:{ 'command': '__com.redhat_qxl_screendump', 'data': {
'id' : 'str',

So we'd have to get downstream buy-in to this plan, and downstreams may
have to hack around our new restrictions for a while.

>>
>> (c) Your bright idea.
> 
> Define a new downstream vendor naming convention. IMHO it is reasonable
> to argue that the downstream vendor extensions are outside the scope of
> backwards compatibility guarantees we normally apply for our CLI args.
> 
> Thus, simply say that vendors must replace all '.' with _ in their
> namespace prefix. eg They should use '__com_example_medium.rare=on'
> which would mean a property '__com_example_medium' which is a struct
> containing a property rare with value on

Same argument as (b) - we'd have to get downstream buy-in (and in this
case, it affects even more cases: ALL downstream extensions have to be
changed, rather than just the ones using _ after the __RFQDN_ portion).
But has the slightly nice appeal of avoiding the '.' vs. '_'
transliteration confusion that catches us only on downstream extensions
(it's hard to special-case '.' as being permitted in QAPI, but only for
downstream, because we can easily forget to test it).

If we are happy with the change forced on downstream vendors, I'm okay
with (c); if not, I think (a) is safe.

-- 
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] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-24 17:17     ` Eric Blake
@ 2017-02-24 19:15       ` Markus Armbruster
  0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-24 19:15 UTC (permalink / raw)
  To: Eric Blake
  Cc: Daniel P. Berrange, Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

Eric Blake <eblake@redhat.com> writes:

> On 02/24/2017 10:39 AM, Daniel P. Berrange wrote:
>> On Fri, Feb 24, 2017 at 05:04:34PM +0100, Markus Armbruster wrote:
>>> Markus Armbruster <armbru@redhat.com> writes:
>>>
>>> [...]
>>>> === Dotted keys ===
>>>>
>>>> One sufficiently powerful syntax extension already exists: the dotted
>>>> key convention.  It's syntactically unambiguous only when none of the
>>>> KEYs involved contains '.'  To adopt it across the board, we'd have to
>>>> outlaw '.' in KEYs.  QAPI outlaws '.' already,
>>>
>>> *Except* in __RFQDN_ prefixes.
>>>
>
>>> Possible solutions:
>>>
>>> (a) Outlaw domain names with '_'.  If KEY starts with "__", everything
>>>     up to the third '_' is an __RFQDN_ prefix.
>
> While there ARE valid DNS names with _ (such as
> _http._sctp.www.example.com mentioned on
> https://en.wikipedia.org/wiki/Hostname), we are at least told by RFC 952
> that _ is not valid in hostnames.  Note that '-' is permitted, and that
> transliterates to '_', so from the flattened name used in C code it's
> harder to tell what is meant, but from the QMP side, I think we are
> guaranteed that no RFQDN will confuse us with any extra _.

DNS registrars may fail to enforce the hostname rules.  But we can
specify that only __RFQDN_ prefixes derived from conforming hostnames
are allowed.  If someone breaks dotted keys by insisting on deriving his
from a non-conforming hostname, they get to keep the pieces.

We better clarify qapi-code-gen.txt, though.

>>>
>>> (b) Outlaw '_' in the name part that follows __RFQDN_.  If KEY starts
>>>     with "__", everything up to the last '_' is an __RFQDN_ prefix.
>
> Reasonable enough, since we ask new interfaces to use '-' rather than
> '_'. But does break existing vendors (a quick grep of RHEL 7.3
> downstream finds at least:
>
> qapi-schema.json:{ 'command': '__com.redhat_qxl_screendump', 'data': {
> 'id' : 'str',
>
> So we'd have to get downstream buy-in to this plan, and downstreams may
> have to hack around our new restrictions for a while.
>
>>>
>>> (c) Your bright idea.
>> 
>> Define a new downstream vendor naming convention. IMHO it is reasonable
>> to argue that the downstream vendor extensions are outside the scope of
>> backwards compatibility guarantees we normally apply for our CLI args.
>> 
>> Thus, simply say that vendors must replace all '.' with _ in their
>> namespace prefix. eg They should use '__com_example_medium.rare=on'
>> which would mean a property '__com_example_medium' which is a struct
>> containing a property rare with value on

Certainly simpler, and arguably what we should've done back when we
created the convention for QMP.  But changing it now would be a pain.

> Same argument as (b) - we'd have to get downstream buy-in (and in this
> case, it affects even more cases: ALL downstream extensions have to be
> changed, rather than just the ones using _ after the __RFQDN_ portion).
> But has the slightly nice appeal of avoiding the '.' vs. '_'
> transliteration confusion that catches us only on downstream extensions
> (it's hard to special-case '.' as being permitted in QAPI, but only for
> downstream, because we can easily forget to test it).
>
> If we are happy with the change forced on downstream vendors, I'm okay
> with (c); if not, I think (a) is safe.

Looks like (a) is the least painful.  I'll give it a try.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
                   ` (10 preceding siblings ...)
  2017-02-24 16:04 ` Markus Armbruster
@ 2017-02-27 10:27 ` Markus Armbruster
  2017-02-27 10:59   ` Kevin Wolf
  2017-02-27 19:43   ` Eric Blake
  2017-03-01  9:24 ` Markus Armbruster
  2017-03-21  8:40 ` Markus Armbruster
  13 siblings, 2 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-27 10:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Kevin Wolf, Peter Krempa, Eric Blake, Daniel P. Berrange

Markus Armbruster <armbru@redhat.com> writes:

[...]
> === Dotted keys ===
>
> One sufficiently powerful syntax extension already exists: the dotted
> key convention.  It's syntactically unambiguous only when none of the
> KEYs involved contains '.'  To adopt it across the board, we'd have to
> outlaw '.' in KEYs.  QAPI outlaws '.' already, but we have a bunch of
> QOM properties names with '.'.  We'd have to rename at least the ones
> that need to be accessible in -object.
>
> Dotted keys can't express member names that look like integers.  We'd
> have to outlaw them at least for the objects that are accessible on the
> command line.  Once again, QAPI outlaws such names already.  QOM is
> anarchy when it comes to names, however.
>
> The way dotted keys do arrays is inconsistent with how QOM's automatic
> arrayification (commit 3396590) do them: foo.0 vs. foo[0].  Backward
> compatibility makes changing the dotted key convention awkward.  Perhaps
> we can still change QOM.

Design flaw: there is no good way to denote an empty array or object
other than the root object.

Empty KEY=VALUE,... is valid and results in an empty root object.

Presence of a KEY that contains periods results in additional non-root
objects or arrays.  For instance, KEY a.b.c results in root object
member "a" that has member "b" that has (scalar) member "c".

These additional objects and arrays all have at least one member, by
construction.

Begs the question how to denote an empty object or array other than the
root.

A natural idea is to interpret "absent in KEY=VALUE,..." as empty.
After all, removing one key from it removes one member when there are
more, so why not when there aren't.

Sadly, it doesn't work: "absent in KEY=VALUE,..." already means
"optional object/array absent", which isn't the same as "empty
object/array present".

Without additional syntax, all we can do is choose what exactly to make
impossible:

* Absent key means absent, period.  No way to do empty array or object.
  This is what I implemented.

* Absent key means absent, except when the member is visited it means
  empty.  No way to do absent optional array or object.

* Likewise, but if the visit is preceeded by a test for presence with
  visit_optional(), it means absent again.  No way to do present
  optional empty array or object.  This requires keeping additional
  state.

Any bright ideas on how to avoid making things impossible?


[...]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-27 10:27 ` Markus Armbruster
@ 2017-02-27 10:59   ` Kevin Wolf
  2017-02-27 13:36     ` Markus Armbruster
  2017-02-27 19:43   ` Eric Blake
  1 sibling, 1 reply; 55+ messages in thread
From: Kevin Wolf @ 2017-02-27 10:59 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: qemu-devel, qemu-block, Peter Krempa, Eric Blake, Daniel P. Berrange

Am 27.02.2017 um 11:27 hat Markus Armbruster geschrieben:
> Markus Armbruster <armbru@redhat.com> writes:
> 
> [...]
> > === Dotted keys ===
> >
> > One sufficiently powerful syntax extension already exists: the dotted
> > key convention.  It's syntactically unambiguous only when none of the
> > KEYs involved contains '.'  To adopt it across the board, we'd have to
> > outlaw '.' in KEYs.  QAPI outlaws '.' already, but we have a bunch of
> > QOM properties names with '.'.  We'd have to rename at least the ones
> > that need to be accessible in -object.
> >
> > Dotted keys can't express member names that look like integers.  We'd
> > have to outlaw them at least for the objects that are accessible on the
> > command line.  Once again, QAPI outlaws such names already.  QOM is
> > anarchy when it comes to names, however.
> >
> > The way dotted keys do arrays is inconsistent with how QOM's automatic
> > arrayification (commit 3396590) do them: foo.0 vs. foo[0].  Backward
> > compatibility makes changing the dotted key convention awkward.  Perhaps
> > we can still change QOM.
> 
> Design flaw: there is no good way to denote an empty array or object
> other than the root object.
> 
> Empty KEY=VALUE,... is valid and results in an empty root object.
> 
> Presence of a KEY that contains periods results in additional non-root
> objects or arrays.  For instance, KEY a.b.c results in root object
> member "a" that has member "b" that has (scalar) member "c".
> 
> These additional objects and arrays all have at least one member, by
> construction.
> 
> Begs the question how to denote an empty object or array other than the
> root.
> 
> A natural idea is to interpret "absent in KEY=VALUE,..." as empty.
> After all, removing one key from it removes one member when there are
> more, so why not when there aren't.
> 
> Sadly, it doesn't work: "absent in KEY=VALUE,..." already means
> "optional object/array absent", which isn't the same as "empty
> object/array present".
> 
> Without additional syntax, all we can do is choose what exactly to make
> impossible:
> 
> * Absent key means absent, period.  No way to do empty array or object.
>   This is what I implemented.

I'm not currently aware of any places where the difference between a
present, but empty array and an absent array is actually significant, so
this is probably the most consistent and useful way to interpret things.

In other words, I agree with your implementation.

> * Absent key means absent, except when the member is visited it means
>   empty.  No way to do absent optional array or object.
> 
> * Likewise, but if the visit is preceeded by a test for presence with
>   visit_optional(), it means absent again.  No way to do present
>   optional empty array or object.  This requires keeping additional
>   state.
> 
> Any bright ideas on how to avoid making things impossible?

I can't see any other option than extending the syntax if we need this.
We can't tell the difference between a string and any other object
description after =, so we would need to make use of reserved characters
in the key name. Maybe just 'foo.array[]' (without any =) for an empty
array or something like that.

Before we introduce anything like this, do we actually need it?

Kevin

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-27 10:59   ` Kevin Wolf
@ 2017-02-27 13:36     ` Markus Armbruster
  2017-02-27 19:47       ` Eric Blake
  0 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2017-02-27 13:36 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Peter Krempa, qemu-devel, qemu-block

Kevin Wolf <kwolf@redhat.com> writes:

> Am 27.02.2017 um 11:27 hat Markus Armbruster geschrieben:
>> Markus Armbruster <armbru@redhat.com> writes:
>> 
>> [...]
>> > === Dotted keys ===
>> >
>> > One sufficiently powerful syntax extension already exists: the dotted
>> > key convention.  It's syntactically unambiguous only when none of the
>> > KEYs involved contains '.'  To adopt it across the board, we'd have to
>> > outlaw '.' in KEYs.  QAPI outlaws '.' already, but we have a bunch of
>> > QOM properties names with '.'.  We'd have to rename at least the ones
>> > that need to be accessible in -object.
>> >
>> > Dotted keys can't express member names that look like integers.  We'd
>> > have to outlaw them at least for the objects that are accessible on the
>> > command line.  Once again, QAPI outlaws such names already.  QOM is
>> > anarchy when it comes to names, however.
>> >
>> > The way dotted keys do arrays is inconsistent with how QOM's automatic
>> > arrayification (commit 3396590) do them: foo.0 vs. foo[0].  Backward
>> > compatibility makes changing the dotted key convention awkward.  Perhaps
>> > we can still change QOM.
>> 
>> Design flaw: there is no good way to denote an empty array or object
>> other than the root object.
>> 
>> Empty KEY=VALUE,... is valid and results in an empty root object.
>> 
>> Presence of a KEY that contains periods results in additional non-root
>> objects or arrays.  For instance, KEY a.b.c results in root object
>> member "a" that has member "b" that has (scalar) member "c".
>> 
>> These additional objects and arrays all have at least one member, by
>> construction.
>> 
>> Begs the question how to denote an empty object or array other than the
>> root.
>> 
>> A natural idea is to interpret "absent in KEY=VALUE,..." as empty.
>> After all, removing one key from it removes one member when there are
>> more, so why not when there aren't.
>> 
>> Sadly, it doesn't work: "absent in KEY=VALUE,..." already means
>> "optional object/array absent", which isn't the same as "empty
>> object/array present".
>> 
>> Without additional syntax, all we can do is choose what exactly to make
>> impossible:
>> 
>> * Absent key means absent, period.  No way to do empty array or object.
>>   This is what I implemented.
>
> I'm not currently aware of any places where the difference between a
> present, but empty array and an absent array is actually significant, so
> this is probably the most consistent and useful way to interpret things.
>
> In other words, I agree with your implementation.
>
>> * Absent key means absent, except when the member is visited it means
>>   empty.  No way to do absent optional array or object.
>> 
>> * Likewise, but if the visit is preceeded by a test for presence with
>>   visit_optional(), it means absent again.  No way to do present
>>   optional empty array or object.  This requires keeping additional
>>   state.
>> 
>> Any bright ideas on how to avoid making things impossible?
>
> I can't see any other option than extending the syntax if we need this.
> We can't tell the difference between a string and any other object
> description after =, so we would need to make use of reserved characters
> in the key name.

Think so, too.

>                  Maybe just 'foo.array[]' (without any =) for an empty
> array or something like that.

Yes, that should do.  Likewise foo.object{} for empty object.

{} doesn't even need quoting.  [] may.

A trailing period without '=' makes some sense, but looks a bit
error-prone, and can't distinguish between array and object.

> Before we introduce anything like this, do we actually need it?

I don't know whether anything needs optional, present and empty.  But
even if the answer is "no" today, it need not remain "no".

Anyone running into a case of "yes", will have to fall back to the JSON
form of -blockdev.  Strengthens my belief that providing JSON there is a
good idea.

The insufficient generality of dotted keys bugs me a bit.  Not sure
whether it justifies more syntax now.  But we should document it.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-27 10:27 ` Markus Armbruster
  2017-02-27 10:59   ` Kevin Wolf
@ 2017-02-27 19:43   ` Eric Blake
  2017-02-28  8:41     ` Markus Armbruster
  1 sibling, 1 reply; 55+ messages in thread
From: Eric Blake @ 2017-02-27 19:43 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel
  Cc: qemu-block, Kevin Wolf, Peter Krempa, Daniel P. Berrange

[-- Attachment #1: Type: text/plain, Size: 1772 bytes --]

On 02/27/2017 04:27 AM, Markus Armbruster wrote:
> Design flaw: there is no good way to denote an empty array or object
> other than the root object.
> 
> Empty KEY=VALUE,... is valid and results in an empty root object.
> 
> Presence of a KEY that contains periods results in additional non-root
> objects or arrays.  For instance, KEY a.b.c results in root object
> member "a" that has member "b" that has (scalar) member "c".
> 
> These additional objects and arrays all have at least one member, by
> construction.
> 
> Begs the question how to denote an empty object or array other than the
> root.

If a.b.c=1 means root object has member "a" with child object "b", and
object "b" has key "c" with scalar value, I suppose we could allow:

a.b,

(with no =val) to mean root object "a" has an empty child "b"
(indeterminate if "b" is an object or a list) - but only if we don't
allow the 'foo' => 'foo=on' magic already in use by QemuOpts.  And you
still have to figure out how to choose empty list vs. empty object.

> 
> Without additional syntax, all we can do is choose what exactly to make
> impossible:
> 
> * Absent key means absent, period.  No way to do empty array or object.
>   This is what I implemented.

I lean towards this meaning. It should generally possible to allow an
empty object/list to mean the same thing as an optional omitted
object/list in all contexts - so omitting KEY=VALUE for a list means you
are omitting the list, but the omitted list behaves the same as an
explicitly empty one would have done (even though dotted syntax doesn't
have an easy way to express an explicit empty list).

-- 
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] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-27 13:36     ` Markus Armbruster
@ 2017-02-27 19:47       ` Eric Blake
  2017-02-28  8:24         ` Markus Armbruster
  0 siblings, 1 reply; 55+ messages in thread
From: Eric Blake @ 2017-02-27 19:47 UTC (permalink / raw)
  To: Markus Armbruster, Kevin Wolf; +Cc: Peter Krempa, qemu-devel, qemu-block

[-- Attachment #1: Type: text/plain, Size: 1532 bytes --]

On 02/27/2017 07:36 AM, Markus Armbruster wrote:

> 
>>                  Maybe just 'foo.array[]' (without any =) for an empty
>> array or something like that.
> 
> Yes, that should do.  Likewise foo.object{} for empty object.
> 
> {} doesn't even need quoting.  [] may.

[contents] needs quoting, but [] does NOT need shell quoting (no shells
treat it as a glob), for the same reason that 'if [ -e "$file" ];' needs
no quoting around the [ or ] (the shell only requires quotes for [ if
the rest of the shell word can look like a valid glob, but globs require
intermediate content before the ]).

>> Before we introduce anything like this, do we actually need it?
> 
> I don't know whether anything needs optional, present and empty.  But
> even if the answer is "no" today, it need not remain "no".
> 
> Anyone running into a case of "yes", will have to fall back to the JSON
> form of -blockdev.  Strengthens my belief that providing JSON there is a
> good idea.
> 
> The insufficient generality of dotted keys bugs me a bit.  Not sure
> whether it justifies more syntax now.  But we should document it.

I agree that documenting it as a shortcoming of dotted form and pointing
to JSON form is okay.  I also like that we are leaving the door open for
future expansion, if needed, and think that is better than inventing the
syntax now, especially for what we are trying to get into 2.9.

-- 
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] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-27 19:47       ` Eric Blake
@ 2017-02-28  8:24         ` Markus Armbruster
  0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-28  8:24 UTC (permalink / raw)
  To: Eric Blake; +Cc: Kevin Wolf, Peter Krempa, qemu-devel, qemu-block

Eric Blake <eblake@redhat.com> writes:

> On 02/27/2017 07:36 AM, Markus Armbruster wrote:
>
>> 
>>>                  Maybe just 'foo.array[]' (without any =) for an empty
>>> array or something like that.
>> 
>> Yes, that should do.  Likewise foo.object{} for empty object.
>> 
>> {} doesn't even need quoting.  [] may.
>
> [contents] needs quoting, but [] does NOT need shell quoting (no shells
> treat it as a glob), for the same reason that 'if [ -e "$file" ];' needs
> no quoting around the [ or ] (the shell only requires quotes for [ if
> the rest of the shell word can look like a valid glob, but globs require
> intermediate content before the ]).

Bash shell options failglob and nullglob can still mess it up.

>>> Before we introduce anything like this, do we actually need it?
>> 
>> I don't know whether anything needs optional, present and empty.  But
>> even if the answer is "no" today, it need not remain "no".
>> 
>> Anyone running into a case of "yes", will have to fall back to the JSON
>> form of -blockdev.  Strengthens my belief that providing JSON there is a
>> good idea.
>> 
>> The insufficient generality of dotted keys bugs me a bit.  Not sure
>> whether it justifies more syntax now.  But we should document it.
>
> I agree that documenting it as a shortcoming of dotted form and pointing
> to JSON form is okay.  I also like that we are leaving the door open for
> future expansion, if needed, and think that is better than inventing the
> syntax now, especially for what we are trying to get into 2.9.

Okay, I'll work on improving the documentation.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-27 19:43   ` Eric Blake
@ 2017-02-28  8:41     ` Markus Armbruster
  0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-02-28  8:41 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Kevin Wolf, Peter Krempa, qemu-block

Eric Blake <eblake@redhat.com> writes:

> On 02/27/2017 04:27 AM, Markus Armbruster wrote:
>> Design flaw: there is no good way to denote an empty array or object
>> other than the root object.
>> 
>> Empty KEY=VALUE,... is valid and results in an empty root object.
>> 
>> Presence of a KEY that contains periods results in additional non-root
>> objects or arrays.  For instance, KEY a.b.c results in root object
>> member "a" that has member "b" that has (scalar) member "c".
>> 
>> These additional objects and arrays all have at least one member, by
>> construction.
>> 
>> Begs the question how to denote an empty object or array other than the
>> root.
>
> If a.b.c=1 means root object has member "a" with child object "b", and
> object "b" has key "c" with scalar value, I suppose we could allow:
>
> a.b,
>
> (with no =val) to mean root object "a" has an empty child "b"
> (indeterminate if "b" is an object or a list) - but only if we don't
> allow the 'foo' => 'foo=on' magic already in use by QemuOpts.  And you
> still have to figure out how to choose empty list vs. empty object.

What if "b" is an alternate?  Should it be [], {} or true?

>> Without additional syntax, all we can do is choose what exactly to make
>> impossible:
>> 
>> * Absent key means absent, period.  No way to do empty array or object.
>>   This is what I implemented.
>
> I lean towards this meaning. It should generally possible to allow an
> empty object/list to mean the same thing as an optional omitted
> object/list in all contexts - so omitting KEY=VALUE for a list means you
> are omitting the list, but the omitted list behaves the same as an
> explicitly empty one would have done (even though dotted syntax doesn't
> have an easy way to express an explicit empty list).

It certainly feels "natural" (whatever that may mean) to imagine QAPI
used this way, but nothing stops users from making "absent" and "empty"
mean different things.

Say we have a configurable object in QEMU that sports an arbitrary
number of configurable sub-objects.  Like BlockdevOptionsBlkdebug has
BlkdebugInjectErrorOptions.  Except in our case, and just to make my
point, the sub-object configuration has only optional members, because a
perfectly sensible default configuration exists.  Let's further assume
that one sub-object in default configuration is not the same as zero sub
objects.

Now let's configure a single sub-object that is completely default.  In
JSON, that's

    "sub-objects": [ {} ]

With dotted keys, you can't express it.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
                   ` (11 preceding siblings ...)
  2017-02-27 10:27 ` Markus Armbruster
@ 2017-03-01  9:24 ` Markus Armbruster
  2017-03-21  8:40 ` Markus Armbruster
  13 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-03-01  9:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Kevin Wolf, Peter Krempa, Eric Blake, Daniel P. Berrange

Markus Armbruster <armbru@redhat.com> writes:

[...]
> == Extensions of the traditional syntax ==
>
> Even if we accept JSON in addition to the traditional KEY=VALUE,...
> syntax, we might want to make the traditional syntax more expressive
> anyway.  Do we?
>
> Kevin brought up an argument for yes: without it, going from the simple,
> flat case to the nested case involves a complete syntax change from
> KEY=VALUE,... to JSON.
>
> === Dotted keys ===
>
> One sufficiently powerful syntax extension already exists: the dotted
> key convention.  It's syntactically unambiguous only when none of the
> KEYs involved contains '.'  To adopt it across the board, we'd have to
> outlaw '.' in KEYs.  QAPI outlaws '.' already, but we have a bunch of
> QOM properties names with '.'.  We'd have to rename at least the ones
> that need to be accessible in -object.
>
> Dotted keys can't express member names that look like integers.  We'd
> have to outlaw them at least for the objects that are accessible on the
> command line.  Once again, QAPI outlaws such names already.  QOM is
> anarchy when it comes to names, however.
>
> The way dotted keys do arrays is inconsistent with how QOM's automatic
> arrayification (commit 3396590) do them: foo.0 vs. foo[0].  Backward
> compatibility makes changing the dotted key convention awkward.  Perhaps
> we can still change QOM.
>
> === Structured values ===
>
> The dotted key convention messes with KEY syntax to permit structured
> values.  Works, but the more conventional way to support structured
> values is a syntax for structured values.  
>
> An obvious one is to use { KEY=VALUE, ...} for objects, and [ VALUE,
> ... ] for arrays.  Looks like this:
>
>     -drive 'driver=quorum,
>             child=[{ driver=file, filename=disk1.img },
>                    { driver=host_device, filename=/dev/sdb },
>                    { driver=nbd, host=localhost } ]'
>
> Again, lines broken and indented for legibility; you need to join them
> for actual use.
>
> There's a syntactic catch, though: a value of the form [ ... ] can
> either be an array or a string.  Which one it is depends on the type of
> the key.  To parse this syntax, you need to know the types, unlike JSON
> or traditional QemuOpts.  Unless we outlaw strings starting with '{' or
> '[', which feels impractical.
>
> But wait, there's another syntactic catch: in traditional QemuOpts, a
> value ends at the next unescaped ',' or '\0'.  Inside an object, it now
> also ends at the next unescaped '}', and inside an array, at the next
> unescaped ']'.  Or perhaps at the next space (the example above assumes
> it does).  That means we either have to provide a way to escape '}', ']'
> and space, or find another way to delimit string values, say require '"'
> around strings whenever the string contains "funny" characters.
>
> So, if escaped ',' wasn't ugly and confusing enough for you...

=== Implicit value types ===

In JSON, the type of a value is syntactically obvious: "9", "true" and
"null" are strings.  9, true and null are of number, boolean and null
type, respectively

Except our internal representation of numbers maps JSON number either to
an integer (QInt) or a double (QFloat), depending on the value.  The
QObject input visitor masks this detail: a visit of a numeric type
succeeds when the value is representable in this type, regardless of
QInt vs. QFloat.  The detail remains visible when you use type 'any',
then examine the QObject yourself.  I'd recommend examining it with the
QObject input visitor.

Actually, the visitor's masking isn't tight around
visit_start_alternate().  You have to choose whether QInt values trigger
the integer alternative, or the float alternative.  The generated
visitors choose the former when it can work, i.e. when the alternate
contains an integer type.  Even when it can't actually represent the
value.  Perhaps I can improve this some day.

Traditional KEY=VALUE,... syntax does not distingish types.  With dotted
keys, all values are scalars, so this affects only string, number,
boolean and null.  With structured values, it also affects array and
object.

The obvious solution (proposed and implemented by Daniel Berrange) is to
resolve this type ambiguity just like the integer vs. float ambiguity:
you get what you ask for.  This leads to just the same issues with 'any'
and with alternates.

Code examining the QObject needs to be prepared for the difference
between a QObject parsed from JSON (or built that way) and a QObject
parsed from KEY=VALUE,...  You can't just pass a QObject around anymore,
you have to pass along whether it's from JSON or from KEY=VALUE.  A good
way to do that is to wrap the correct QObject input visitor around the
QObject, and pass that instead.

The alternate issue is more serious than with numbers.  Which
alternative should be picked if one of them is string?  Or an enum with
sufficiently funny values.

Possible solutions:

* Document as restriction, point to JSON

  This is what we do for the "no way to denote empty array or object"
  flaw.  I figure it's what we do for 2.9.  I'll make sure we have test
  coverage.

* Make the QAPI generator reject problematic alternates

  Knee-jerk reaction; there may well be uses of such alternates that are
  safely isolated from KEY=VALUE,... QObjects, and therefore perfectly
  unambiguous.

* Optional syntax to disamiguate types

  We discussed this in the context of empty objects and arrays.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] Non-flat command line option argument syntax
  2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
                   ` (12 preceding siblings ...)
  2017-03-01  9:24 ` Markus Armbruster
@ 2017-03-21  8:40 ` Markus Armbruster
  13 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2017-03-21  8:40 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Kevin Wolf, Peter Krempa, Eric Blake, Daniel P. Berrange

For the record, we went with "either dotted keys or JSON" for -blockdev
in 2.9.

Certain uses of QAPI become problematic with dotted keys, because

(1) it's untyped except for inner tree nodes, and therefore can't
express numbers, boolean, null, empty list, empty object, and

(2) The keyval variant of the QObject input visitor (the thing returned
by qobject_input_visitor_new_keyval()) can't fully hide this.

I don't like this at all, but the whole non-flat command line argument
design has been an exercise in picking what I dislike least.

Example: object-add's use of 'any' for properties

    QOM properties aren't specified in the QAPI schema (let's ignore the
    question whether they should be here).  object-add uses type 'any'
    to take a dictionary of them.  object-add obviously needs to do the
    type checking itself.  In C, type 'any' is QObject *.

    If object-add examines the QObject directly, it now needs to know
    whether it was made from dotted keys, so it can cope with dotted
    keys' "everything's a string".

    Probably the only sane way to do that is to use the appropriate
    visitor.  Perhaps we should represent 'any' as QObjectInputVisitor *
    instead of QObject *.

Example: TCP service name / port number as alternate of string, number

    We use string, just like getaddrinfo(): if the string is a decimal
    number, it's a port number, else a service name.

    An alternate of string and number would be more idiomatic QAPI
    (let's ignore compatibility here, it's just an example).  Works fine
    with JSON.  Breaks with dotted keys, because you always get the
    alternate's string variant there.

Possible ways forward:

* When it breaks, fall back to JSON

  Tolerable if it breaks pretty much only in obscure corner cases.

* More syntax

  Add syntax to disambiguate the type (key sigils?).  Has to be optional
  for backward compatibility reasons.  When omitting type information
  breaks, you have to supply it, or fall back to JSON.

  More syntax for use in obscure cases is about the last thing the QEMU
  command line needs.

* More magic

  Make the keyval variant of the QObject input visitor shift the
  breakage to hopefully less common cases.

  - Empty list magic

    When the visitor is asked for a list, and the list's key wasn't
    specified, return an empty list instead of failure.  Unbreaks empty
    list, breaks absent optional list.

  - Alternate magic

    When the visitor is asked for an alternate, pick the alternate's
    variant based on the value rather than the type for scalar values
    (the type is always 'str' then).  Unbreaks alternates when this
    picks the variant you want, breaks them when you really want 'str'.

  - Possibly more

  When the magic breaks, fall back to JSON.

  More magic in the QEMU command line feels even worse to me than more
  syntax.

^ permalink raw reply	[flat|nested] 55+ messages in thread

end of thread, other threads:[~2017-03-21  8:40 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-02 19:42 [Qemu-devel] Non-flat command line option argument syntax Markus Armbruster
2017-02-02 20:06 ` Eric Blake
2017-02-02 20:23 ` Eric Blake
2017-02-03  7:57   ` Markus Armbruster
2017-02-02 20:27 ` Dr. David Alan Gilbert
2017-02-03  7:50   ` Markus Armbruster
2017-02-03 16:57     ` Dr. David Alan Gilbert
2017-02-04  9:44       ` Markus Armbruster
2017-02-06 10:20         ` Dr. David Alan Gilbert
2017-02-03 20:02     ` [Qemu-devel] [Qemu-block] " Max Reitz
2017-02-04  9:45       ` Markus Armbruster
2017-02-04 10:03         ` [Qemu-devel] " Paolo Bonzini
2017-02-04 11:52           ` Markus Armbruster
2017-02-04 12:43             ` Paolo Bonzini
2017-02-03 10:03 ` Daniel P. Berrange
2017-02-03 11:13   ` Markus Armbruster
2017-02-03 12:37 ` Peter Krempa
2017-02-03 13:53   ` Markus Armbruster
2017-02-03 17:25 ` Richard W.M. Jones
2017-02-04  9:51   ` Markus Armbruster
2017-02-05 20:46     ` [Qemu-devel] [Qemu-block] " Max Reitz
2017-02-03 20:28 ` Max Reitz
2017-02-04  9:56   ` Markus Armbruster
2017-02-04 12:21 ` [Qemu-devel] " Fam Zheng
2017-02-04 12:44   ` Paolo Bonzini
2017-02-04 13:02     ` Fam Zheng
2017-02-04 13:35   ` Markus Armbruster
2017-02-04 14:10     ` Fam Zheng
2017-02-06  6:24       ` Markus Armbruster
2017-02-06 11:08   ` Daniel P. Berrange
2017-02-06  6:57 ` Markus Armbruster
2017-02-06 13:23 ` Kevin Wolf
2017-02-06 15:36   ` Markus Armbruster
2017-02-06 16:33     ` Daniel P. Berrange
2017-02-06 17:24       ` Markus Armbruster
2017-02-06 17:50         ` Daniel P. Berrange
2017-02-06 18:56           ` Markus Armbruster
2017-02-06 17:38     ` Paolo Bonzini
2017-02-06 18:12       ` Markus Armbruster
2017-02-06 21:52         ` Paolo Bonzini
2017-02-07  7:02           ` Markus Armbruster
2017-02-07  9:26     ` Kevin Wolf
2017-02-24 16:04 ` Markus Armbruster
2017-02-24 16:39   ` Daniel P. Berrange
2017-02-24 17:17     ` Eric Blake
2017-02-24 19:15       ` Markus Armbruster
2017-02-27 10:27 ` Markus Armbruster
2017-02-27 10:59   ` Kevin Wolf
2017-02-27 13:36     ` Markus Armbruster
2017-02-27 19:47       ` Eric Blake
2017-02-28  8:24         ` Markus Armbruster
2017-02-27 19:43   ` Eric Blake
2017-02-28  8:41     ` Markus Armbruster
2017-03-01  9:24 ` Markus Armbruster
2017-03-21  8:40 ` Markus Armbruster

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.