On June 4, 2024 11:28 am, Max Carrara wrote: > In order to make the parser somewhat more maintainable in the future, > this commit cleans up its logic and makes its control flow easier to > follow.
it also mixes deeper changes with things like variable renaming, which makes it unnecessarily hard to review.. > > Signed-off-by: Max Carrara <m.carr...@proxmox.com> > --- > src/PVE/SectionConfig.pm | 189 ++++++++++++++++++++------------------- > 1 file changed, 98 insertions(+), 91 deletions(-) > > diff --git a/src/PVE/SectionConfig.pm b/src/PVE/SectionConfig.pm > index a6b0183..30faaa4 100644 > --- a/src/PVE/SectionConfig.pm > +++ b/src/PVE/SectionConfig.pm > @@ -1014,25 +1014,26 @@ The error. > sub parse_config { > my ($class, $filename, $raw, $allow_unknown) = @_; > > - my $pdata = $class->private(); > + if (!defined($raw)) { > + return { > + ids => {}, > + order => {}, > + digest => Digest::SHA::sha1_hex(''), > + }; > + } > + > + my $re_begins_with_comment = qr/^\s*#/; > + my $re_kv_pair = qr/^\s+ (\S+) (\s+ (.*\S) )? \s*$/x; I am not sure this is really more readable? especially in a RE that is basically only concerned with whitespace.. and for a RE that is only used once.. > > my $ids = {}; > my $order = {}; > - > - $raw = '' if !defined($raw); > - > my $digest = Digest::SHA::sha1_hex($raw); > > - my $pri = 1; > + my $current_order = 1; this is actually a worse name than before. this would be something like current_index? current_position? section_no? > + my $line_no = 0; > > - my $lineno = 0; > my @lines = split(/\n/, $raw); > - my $nextline = sub { > - while (defined(my $line = shift @lines)) { > - $lineno++; > - return $line if ($line !~ /^\s*#/); > - } > - }; > + my @errors; what do we gain from this? > > my $is_array = sub { > my ($type, $key) = @_; > @@ -1043,106 +1044,112 @@ sub parse_config { > return $schema->{type} eq 'array'; > }; > > - my $errors = []; > - while (@lines) { > - my $line = $nextline->(); > + my $get_next_line = sub { > + while (scalar(@lines)) { > + my $line = shift(@lines); > + $line_no++; > + > + next if ($line =~ m/$re_begins_with_comment/); > + > + return $line; > + } > + > + return undef; > + }; > + > + my $skip_to_next_empty_line = sub { > + while ($get_next_line->() ne '') {} > + }; > + > + while (defined(my $line = $get_next_line->())) { > next if !$line; > > - my $errprefix = "file $filename line $lineno"; > + my $errprefix = "file $filename line $line_no"; > > - my ($type, $sectionId, $errmsg, $config) = > $class->parse_section_header($line); > - if ($config) { > - my $skip = 0; > - my $unknown = 0; > + my ($type, $section_id, $errmsg, $config) = > $class->parse_section_header($line); > > - my $plugin; > + if (!defined($config)) { > + warn "$errprefix - ignore config line: $line\n"; > + next; > + } > > - if ($errmsg) { > - $skip = 1; > - chomp $errmsg; > - warn "$errprefix (skip section '$sectionId'): $errmsg\n"; > - } elsif (!$type) { > - $skip = 1; > - warn "$errprefix (skip section '$sectionId'): missing type - > internal error\n"; > - } else { > - if (!($plugin = $pdata->{plugins}->{$type})) { > - if ($allow_unknown) { > - $unknown = 1; > - } else { > - $skip = 1; > - warn "$errprefix (skip section '$sectionId'): > unsupported type '$type'\n"; > - } > - } > - } > + if ($errmsg) { > + chomp $errmsg; > + warn "$errprefix (skip section '$section_id'): $errmsg\n"; > + $skip_to_next_empty_line->(); > + next; > + } > + > + if (!$type) { > + warn "$errprefix (skip section '$section_id'): missing type - > internal error\n"; > + $skip_to_next_empty_line->(); > + next; > + } > + > + my $plugin = eval { $class->lookup($type) }; > + my $is_unknown_type = defined($@) && $@ ne ''; > + > + if ($is_unknown_type && !$allow_unknown) { > + warn "$errprefix (skip section '$section_id'): unsupported type > '$type'\n"; > + $skip_to_next_empty_line->(); > + next; > + } > + > + # Parse kv-pairs of section - will go on until empty line is encountered > + while (my $section_line = $get_next_line->()) { > + if ($section_line =~ m/$re_kv_pair/) { > + my ($key, $value) = ($1, $3); > > - while ($line = $nextline->()) { > - next if $skip; > - > - $errprefix = "file $filename line $lineno"; > - > - if ($line =~ m/^\s+(\S+)(\s+(.*\S))?\s*$/) { > - my ($k, $v) = ($1, $3); > - > - eval { > - if ($unknown) { > - if (!defined($config->{$k})) { > - $config->{$k} = $v; > - } else { > - if (!ref($config->{$k})) { > - $config->{$k} = [$config->{$k}]; > - } > - push $config->{$k}->@*, $v; > - } > - } elsif ($is_array->($type, $k)) { > - $v = $plugin->check_value($type, $k, $v, > $sectionId); > - $config->{$k} = [] if !defined($config->{$k}); > - push $config->{$k}->@*, $v; > + eval { > + if ($is_unknown_type) { > + if (!defined($config->{$key})) { > + $config->{$key} = $value; > } else { > - die "duplicate attribute\n" if > defined($config->{$k}); > - $v = $plugin->check_value($type, $k, $v, > $sectionId); > - $config->{$k} = $v; > + $config->{$key} = [$config->{$key}] if > !ref($config->{$key}); > + push $config->{$key}->@*, $value; > } > - }; > - if (my $err = $@) { > - warn "$errprefix (section '$sectionId') - unable to > parse value of '$k': $err"; > - push $errors->@*, { > - context => $errprefix, > - section => $sectionId, > - key => $k, > - err => $err, > - }; > + } elsif ($is_array->($type, $key)) { > + $value = $plugin->check_value($type, $key, $value, > $section_id); > + $config->{$key} = [] if !defined($config->{$key}); > + push $config->{$key}->@*, $value; > + } else { > + die "duplicate attribute\n" if defined($config->{$key}); > + $value = $plugin->check_value($type, $key, $value, > $section_id); > + $config->{$key} = $value; > } > - > - } else { > - warn "$errprefix (section '$sectionId') - ignore config > line: $line\n"; > + }; > + if (my $err = $@) { > + warn "$errprefix (section '$section_id') - unable to parse > value of '$key': $err"; > + push @errors, { > + context => $errprefix, > + section => $section_id, > + key => $key, > + err => $err, > + }; > } > } > + } > > - if ($unknown) { > - $config->{type} = $type; > - $ids->{$sectionId} = $config; > - $order->{$sectionId} = $pri++; > - } elsif (!$skip && $type && $plugin && $config) { > - $config->{type} = $type; > - if (!$unknown) { > - $config = eval { $config = > $plugin->check_config($sectionId, $config, 1, 1); }; > - warn "$errprefix (skip section '$sectionId'): $@" if $@; > - } > - $ids->{$sectionId} = $config; > - $order->{$sectionId} = $pri++; > + if ($is_unknown_type || ($type && $plugin && $config)) { > + $config->{type} = $type; > + > + if (!$is_unknown_type) { > + $config = eval { $config = $plugin->check_config($section_id, > $config, 1, 1); }; > + warn "$errprefix (skip section '$section_id'): $@" if $@; > } > > - } else { > - warn "$errprefix - ignore config line: $line\n"; > + $ids->{$section_id} = $config; > + $order->{$section_id} = $current_order++; > } > } > > my $cfg = { > ids => $ids, > order => $order, > - digest => $digest > + digest => $digest, > }; > - $cfg->{errors} = $errors if scalar($errors->@*) > 0; > + > + $cfg->{errors} = \@errors if scalar(@errors) > 0; > > return $cfg; > } > -- > 2.39.2 > > > > _______________________________________________ > pve-devel mailing list > pve-devel@lists.proxmox.com > https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel > > > _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel