[pve-devel] [RFC common] schema_get_type_text: summarize enumeration for docs

Thomas Lamprecht t.lamprecht at proxmox.com
Wed Nov 7 07:48:47 CET 2018


On 11/6/18 8:00 PM, Fabian Grünbichler wrote:
> On Tue, Nov 06, 2018 at 04:03:16PM +0100, Thomas Lamprecht wrote:
>> We use the changed method mainly in pve-docs to generate synopsis
>> from a schema. For now enums where always printed fully, which is not
>> a big problem for those with a relative small set of possibilities.
>>
>> But we allow to use up to 256 mounpoints in pve-container now, and a
>> patch is pending to sync this number for (unused ?) disks in VMs,
>> so manpages which have an option referring to such a enum get pretty
>> long and not really nice, e.g. fsck command in man pct (ensure to
>> look in a recent version).
>>
>> Initially I played with the idea to add a new type, 'range' which
>> would declare a basic key and a min (default to 0) to max range,
>> e.g. for the mountpoint case we'd had something alike:
>>
>> mp => {
>>     description => 'A Mountpoint...',
>>     range => {
>>         base => 'mp',
>>         max => 255,
>>     }
>> }
>>
>> but as in the containercase we often have the set of ( mp0, mp1, ...,
>> mp255, rootfs) this is not really practicable I guess.
>>
>> So I opted to summarize enum entries which consist of a word plus a
>> number, e.g., in the pct fsck man page case I output:
>>
>>> pct fsck <vmid> [OPTIONS]
>>> ...
>>> --device <mp[0..255] | rootfs>
>>
>> This happens only on build time for packages using pve-docs to
>> generate manpages, so even if it's a bit expensive that doesn't
>> matters much - and it should be pretty fast.
>>
>> Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
>> ---
>>
>> RFC for obvious reasons, it worked at the first try which worries me a
>> bit, so some subtle breakage may be there ^^
> 
> at first glance (i.e., not tested, just looking), it seems to handle
> 'base base2 base3'[1] or enums with holes like 'base1 base4 base6'[2]
> incorrectly.

ah yeah, sure, but the principal design looks OK for you?

> 
> also, I think the RE needs to be anchored, because in the 'w2k' example
> from [2] the w2k ones would be matched as $base = 'k', $id = 3 (or 8)?
> 
> I'd suggest a two-pass approach:
> - keep the existing scan, but record all candidate bases/ids separately
>   from the non-candidate values

I had that initially, just optimized to record the min/max directly

> - scan those candidate values again, and collapse only those sequences
>   without holes which contain more than X elements (where x is something
>   like 5 or 10?)

or 3, like we do in generate_typetext to decide if we print the full
enumeration values out or the verbatim text 'enum'?
But 5 sound good too.

We could also ouput another format, like:

( mp1 | mp2 | ... | mp255 )

makes it a bit more useable as some values can be copied and used immediately,
and it's, personally observed, a common notation.

> - combine and sort non-candidate values and reduced values
> 
> since this is only done at build time, the extra pass does not hurt that
> much, but makes the end result much less error prone for all those weird
> corner cases.

sounds good in general, if there are no objections to the base design
I'll get on it.

> 
> 1: QemuServer.pm has 'qcow' and 'qcow2' in the same enum, as well as
> 'pentium', 'pentium2', 'pentium3' in another

although pentium does not count here ^^

> 2: again, QemuServer.pm has 'w2k', 'w2k3', 'w2k8', as well as 'win7',
> 'win8', 'win10', as well as 'l24' and 'l26' all in one enum ;)

yes, holes mustn't be printed like this, that's for sure.

Thanks for your comments, appreciated!

> 
>>  src/PVE/JSONSchema.pm | 28 +++++++++++++++++++++++++++-
>>  1 file changed, 27 insertions(+), 1 deletion(-)
>>
>> diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm
>> index fb58ad3..92a5b04 100644
>> --- a/src/PVE/JSONSchema.pm
>> +++ b/src/PVE/JSONSchema.pm
>> @@ -1807,7 +1807,33 @@ sub schema_get_type_text {
>>      } elsif ($phash->{format_description}) {
>>  	return "<$phash->{format_description}>";
>>      } elsif ($phash->{enum}) {
>> -	return "<" . join(' | ', sort @{$phash->{enum}}) . ">";
>> +	my $items = $phash->{enum};
>> +	my $reduced = {};
>> +	foreach my $v (@$items) {
>> +	    if ($v =~ /([^\s\d]+)(\d+)/) {
>> +		my ($base, $id) = ($1, $2);
>> +		if (!exists($reduced->{$base})) {
>> +		    $reduced->{$base}->{max} = $reduced->{$base}->{min} = $id;
>> +		} elsif ($id > $reduced->{$base}->{max}) {
>> +		    $reduced->{$base}->{max} = $id;
>> +		} elsif ($id < $reduced->{$base}->{min}) {
>> +		    $reduced->{$base}->{min} = $id;
>> +		}
>> +	    } else {
>> +		$reduced->{$v} = undef;
>> +	    }
>> +	}
>> +	$items = [];
>> +	foreach my $k (sort keys %$reduced) {
>> +	    if (!defined($reduced->{$k})) {
>> +		push @$items, $k;
>> +	    } else {
>> +		my ($min, $max) = $reduced->{$k}->@{qw(min max)};
>> +		push @$items, "${k}[$min..$max]";
>> +	    }
>> +	}
>> +
>> +	return "<" . join(' | ', @$items) . ">";
>>      } elsif ($phash->{pattern}) {
>>  	return $phash->{pattern};
>>      } elsif ($type eq 'integer' || $type eq 'number') {
>> -- 
>> 2.19.1






More information about the pve-devel mailing list