X-Git-Url: https://git.proxmox.com/?p=pve-common.git;a=blobdiff_plain;f=src%2FPVE%2FSectionConfig.pm;h=cc03aeaed638db1a4f6c4a736ade97ea90633649;hp=d4d2ed57e43437db4a73b231862f25452d07d2fc;hb=e97f807c388c10250f442b1f16c5315df2ffc2af;hpb=516dfb55e1d1e542cafe72c09798f658db950fd2 diff --git a/src/PVE/SectionConfig.pm b/src/PVE/SectionConfig.pm index d4d2ed5..cc03aea 100644 --- a/src/PVE/SectionConfig.pm +++ b/src/PVE/SectionConfig.pm @@ -26,6 +26,9 @@ sub register { my $type = $class->type(); my $pdata = $class->private(); + die "duplicate plugin registration (type = $type)" + if defined($pdata->{plugins}->{$type}); + my $plugindata = $class->plugindata(); $pdata->{plugindata}->{$type} = $plugindata; $pdata->{plugins}->{$type} = $class; @@ -48,20 +51,62 @@ sub plugindata { } sub createSchema { - my ($class) = @_; + my ($class, $skip_type) = @_; my $pdata = $class->private(); my $propertyList = $pdata->{propertyList}; + my $plugins = $pdata->{plugins}; + + my $props = {}; + + my $copy_property = sub { + my ($src) = @_; + + my $res = {}; + foreach my $k (keys %$src) { + $res->{$k} = $src->{$k}; + } + + return $res; + }; + + foreach my $p (keys %$propertyList) { + next if $skip_type && $p eq 'type'; + + if (!$propertyList->{$p}->{optional}) { + $props->{$p} = $propertyList->{$p}; + next; + } + + my $required = 1; + + my $copts = $class->options(); + $required = 0 if defined($copts->{$p}) && $copts->{$p}->{optional}; + + foreach my $t (keys %$plugins) { + my $opts = $pdata->{options}->{$t} || {}; + $required = 0 if !defined($opts->{$p}) || $opts->{$p}->{optional}; + } + + if ($required) { + # make a copy, because we modify the optional property + my $res = &$copy_property($propertyList->{$p}); + $res->{optional} = 0; + $props->{$p} = $res; + } else { + $props->{$p} = $propertyList->{$p}; + } + } return { type => "object", additionalProperties => 0, - properties => $propertyList, + properties => $props, }; } sub updateSchema { - my ($class) = @_; + my ($class, $single_class) = @_; my $pdata = $class->private(); my $propertyList = $pdata->{propertyList}; @@ -69,8 +114,15 @@ sub updateSchema { my $props = {}; + my $filter_type = $class->type() if $single_class; + foreach my $p (keys %$propertyList) { next if $p eq 'type'; + + my $copts = $class->options(); + + next if defined($filter_type) && !defined($copts->{$p}); + if (!$propertyList->{$p}->{optional}) { $props->{$p} = $propertyList->{$p}; next; @@ -78,6 +130,8 @@ sub updateSchema { my $modifyable = 0; + $modifyable = 1 if defined($copts->{$p}) && !$copts->{$p}->{fixed}; + foreach my $t (keys %$plugins) { my $opts = $pdata->{options}->{$t} || {}; next if !defined($opts->{$p}); @@ -138,7 +192,7 @@ sub init { } $propertyList->{type}->{type} = 'string'; - $propertyList->{type}->{enum} = [keys %$plugins]; + $propertyList->{type}->{enum} = [sort keys %$plugins]; } sub lookup { @@ -157,7 +211,7 @@ sub lookup_types { my $pdata = $class->private(); - return [ keys %{$pdata->{plugins}} ]; + return [ sort keys %{$pdata->{plugins}} ]; } sub decode_value { @@ -205,6 +259,10 @@ sub check_value { } } + if ($ct eq 'boolean' || $ct eq 'integer' || $ct eq 'number') { + return $value + 0; # convert to number + } + return $value; } @@ -221,7 +279,7 @@ sub parse_section_header { } sub format_section_header { - my ($class, $type, $sectionId) = @_; + my ($class, $type, $sectionId, $scfg, $done_hash) = @_; return "$type: $sectionId\n"; } @@ -350,8 +408,12 @@ my $format_config_line = sub { my $ct = $schema->{type}; + die "property '$key' contains a line feed\n" + if ($key =~ m/[\n\r]/) || ($value =~ m/[\n\r]/); + if ($ct eq 'boolean') { - return $value ? "\t$key\n" : ''; + return "\t$key " . ($value ? 1 : 0) . "\n" + if defined($value); } else { return "\t$key $value\n" if "$value" ne ''; } @@ -386,18 +448,23 @@ sub write_config { die "unknown section type '$type'\n" if !$opts; - my $data = $class->format_section_header($type, $sectionId); - if ($scfg->{comment}) { + my $done_hash = {}; + + my $data = $class->format_section_header($type, $sectionId, $scfg, $done_hash); + if ($scfg->{comment} && !$done_hash->{comment}) { my $k = 'comment'; my $v = $class->encode_value($type, $k, $scfg->{$k}); $data .= &$format_config_line($propertyList->{$k}, $k, $v); } - $data .= "\tdisable\n" if $scfg->{disable}; + $data .= "\tdisable\n" if $scfg->{disable} && !$done_hash->{disable}; - my $done_hash = { comment => 1, disable => 1}; + $done_hash->{comment} = 1; + $done_hash->{disable} = 1; - foreach my $k (keys %$opts) { + my @option_keys = sort keys %$opts; + foreach my $k (@option_keys) { + next if defined($done_hash->{$k}); next if $opts->{$k}->{optional}; $done_hash->{$k} = 1; my $v = $scfg->{$k}; @@ -407,7 +474,7 @@ sub write_config { $data .= &$format_config_line($propertyList->{$k}, $k, $v); } - foreach my $k (keys %$opts) { + foreach my $k (@option_keys) { next if defined($done_hash->{$k}); my $v = $scfg->{$k}; next if !defined($v);