build: replace ./tools/generate-docs-nm-property-infos.pl with python script

In order to have more structured settings in man page and make it more
manageable to generate the docbook, it is recommended to use python
script to replace `./tools/generate-docs-nm-property-infos.pl` (this
tool is used to parse the comment section starting with `---nmcli---`,
`---dbus---`, `---keyfile---`, `---ifcfg-rh---`).

Signed-off-by: Wen Liang <liangwen12year@gmail.com>

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/824
This commit is contained in:
Wen Liang 2021-04-22 18:41:50 -04:00 committed by Thomas Haller
parent 8232c3473f
commit 86dcb31ab3
No known key found for this signature in database
GPG Key ID: 29C2366E4DFC5728
4 changed files with 151 additions and 165 deletions

View File

@ -1890,8 +1890,8 @@ endif
libnm_docs_sources = $(src_libnm_core_impl_lib_c_settings_real)
src/libnm-client-impl/nm-property-infos-%.xml: tools/generate-docs-nm-property-infos.pl $(libnm_docs_sources)
$(AM_V_GEN) $(srcdir)/tools/generate-docs-nm-property-infos.pl $(patsubst nm-property-infos-%.xml,%,$(notdir $@)) $@ $(filter-out $<,$^)
src/libnm-client-impl/nm-property-infos-%.xml: tools/generate-docs-nm-property-infos.py $(libnm_docs_sources)
$(AM_V_GEN) "$(PYTHON)" $(srcdir)/tools/generate-docs-nm-property-infos.py $(patsubst nm-property-infos-%.xml,%,$(notdir $@)) $@ $(filter-out $<,$^)
src/libnm-client-impl/nm-settings-docs-gir.xml: tools/generate-docs-nm-settings-docs-gir.py src/libnm-client-impl/NM-1.0.gir src/libnm-client-impl/NM-1.0.typelib src/libnm-client-impl/libnm.la $(libnm_docs_sources)
$(AM_V_GEN) \
@ -1918,7 +1918,7 @@ DISTCLEANFILES += $(libnm_noinst_data)
endif
EXTRA_DIST += \
tools/generate-docs-nm-property-infos.pl \
tools/generate-docs-nm-property-infos.py \
tools/generate-docs-nm-settings-docs-merge.py \
tools/generate-docs-nm-settings-docs-gir.py \
src/libnm-client-impl/meson.build \

View File

@ -162,8 +162,8 @@ if enable_introspection
input: libnm_core_settings_sources,
output: 'nm-propery-infos-' + info + '.xml',
command: [
perl,
join_paths(meson.source_root(), 'tools', 'generate-docs-nm-property-infos.pl'),
python.path(),
join_paths(meson.source_root(), 'tools', 'generate-docs-nm-property-infos.py'),
info,
'@OUTPUT@',
'@INPUT@'

View File

@ -1,160 +0,0 @@
#!/usr/bin/env perl
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright (C) 2014 Red Hat, Inc.
#
#
# The script parses nm-setting-*.c files and extracts documentation related
# to setting plugins. The documentation is in a simple format of lines
# "keyword: value". The documentation is enclosed between tags
# ---<plugin-name>--- and ---end---
# Recognized keywords are:
# "property: " - property name
# "variable: " - name of the variable used by the plugin
# "format: " - format of the value in 'keyfile' plugin
# "default: " - default value when variable is not used
# "values: " - allowed values (e.g. for enumerations)
# "example: " - example(s)
# "description: " - description text
# Value is an arbitrary string that can span over multiple lines.
#
# ifcfg-rh specifics:
# - mark NM extension variables with (+), e.g. variable: UUID(+)
#
use strict;
use warnings;
use v5.10;
# global variables
my @keywords = ("property", "variable", "format", "values", "default", "example", "description");
my @data;
my $fo;
(scalar @ARGV >= 3) or die "Usage: $0 <plugin> <output-xml-file> <srcfiles>\n";
my ($plugin, $output, (@source_files)) = @ARGV;
my $start_tag = "---$plugin---\\s*\$";
my $end_tag = '---end---';
# open output file
open $fo, '>', $output or die "Can't open $output: $!";
# write XML header
write_header();
# write generated documentation for each setting
foreach my $c_file (@source_files) {
my $setting_name = get_setting_name($c_file);
if ($setting_name) {
write_item("<setting name=\"$setting_name\">");
scan_doc_comments($c_file, $start_tag, $end_tag);
write_item("</setting>");
}
}
# write XML footer
write_footer();
# close output file
close $fo;
### --- subroutines --- ###
# get setting name from NM_SETTING_*_SETTING_NAME constant in C header file
sub get_setting_name {
my $path = $_[0];
$path =~ s/\/libnm-core-impl\/nm-setting-(.*)\.c$/\/libnm-core-public\/nm-setting-$1.h/; # use header file to find out setting name
$path =~ s/\.c$/.h/; # use header file to find out setting name
open my $fh, '<', $path or die "Can't open $path: $!";
while (my $line = <$fh>) {
if ($line =~ /NM_SETTING_.+SETTING_NAME\s+\"(\S+)\"/) {
return $1;
}
}
}
# scan source setting file for documentation tags and write them to XML
sub scan_doc_comments {
my($setting_file, $start, $end) = @_;
open my $fi, '<', $setting_file or die "Can't open $setting_file: $!";
while (<$fi>) {
if (/$start/ .. /$end/) {
next if /$start/;
if (/$end/) {
process_data();
} else {
push @data, $_;
}
next;
}
# ignore text not inside marks
}
close $fi;
}
# process plugin property documentation comments
sub process_data {
return if not @data;
my $kwd_pat = join("|", @keywords);
my %parsed_data;
my $this_key;
foreach (@data) {
if (/^\s*\**\s+($kwd_pat):\s+(.*?)\s*$/) {
$this_key = $1;
$parsed_data{$this_key} = "$2\n";
} elsif (/^\s*\**\s+(.*?)\s*$/) {
die "Extra mess in a comment: $_" unless $this_key;
$parsed_data{$this_key} .= "$1\n";
}
}
# now write a line into the XML
my $name = $parsed_data{property} // "";
my $var = $parsed_data{variable} // $name; # fallback to "property: "
my $format = $parsed_data{format} // "";
my $values = $parsed_data{values} // "";
my $def = $parsed_data{default} // "";
my $exam = $parsed_data{example} // "";
my $desc = $parsed_data{description} // "";
chomp($name, $var, $format, $values, $def, $exam, $desc);
escape_xml_chars($name, $var, $format, $values, $def, $exam, $desc);
my $foo = sprintf("<property name=\"%s\" variable=\"%s\" format=\"%s\" values=\"%s\" ".
"default=\"%s\" example=\"%s\" description=\"%s\"/>",
$name, $var, $format, $values, $def, $exam, $desc);
write_item($foo);
@data = ();
}
# - XML handling -
sub write_header {
(my $header =
qq{<nm-setting-docs>
}) =~ s/^ {7}//mg;
print {$fo} $header;
}
sub write_footer {
my $footer = "</nm-setting-docs>";
print {$fo} $footer;
}
sub write_item {
my $str = join("", @_);
print {$fo} $str, "\n";
}
sub escape_xml_chars {
# http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Predefined%5Fentities%5Fin%5FXML
foreach my $val (@_) {
$val =~ s/&/&amp;/sg;
$val =~ s/</&lt;/sg;
$val =~ s/>/&gt;/sg;
$val =~ s/"/&quot;/sg;
$val =~ s/'/&apos;/sg;
}
}

View File

@ -0,0 +1,146 @@
#!/usr/bin/env python
# SPDX-License-Identifier: LGPL-2.1-or-later
import os, re, sys
def get_setting_name(one_file):
setting_name = ""
assert re.match(r".*/libnm-core-impl/nm-setting-.*\.c$", one_file)
header_path = one_file.replace("libnm-core-impl", "libnm-core-public")
header_path = header_path.replace(".c", ".h")
try:
header_reader = open(header_path, "r")
except OSError:
print("Can not open header file: %s" % (header_path))
exit(1)
line = header_reader.readline()
while line != "":
setting_name_found = re.search(r"NM_SETTING_.+SETTING_NAME\s+\"(\S+)\"", line)
if setting_name_found:
setting_name = setting_name_found.group(1)
break
line = header_reader.readline()
header_reader.close()
return setting_name
def scan_doc_comments(plugin, outfile, file, start_tag, end_tag):
data = []
push_flag = 0
try:
file_reader = open(file, "r")
except OSError:
print("Can not open file: %s" % (file))
exit(1)
line = file_reader.readline()
while line != "":
if start_tag in line:
push_flag = 1
elif end_tag in line and push_flag == 1:
push_flag = 0
parsed_data = process_data(data)
if parsed_data:
write_data(outfile, parsed_data)
data = []
elif push_flag == 1:
data.append(line)
line = file_reader.readline()
file_reader.close()
return
def process_data(data):
parsed_data = {}
if not data:
return parsed_data
keywords = [
"property",
"variable",
"format",
"values",
"default",
"example",
"description",
]
kwd_pat = "|".join(keywords)
keyword = ""
for line in data:
kwd_first_line_found = re.search(
r"^\s*\**\s+({}):\s+(.*?)\s*$".format(kwd_pat), line
)
kwd_more_line_found = re.search(r"^\s*\**\s+(.*?)\s*$", line)
if kwd_first_line_found:
keyword = kwd_first_line_found.group(1)
value = kwd_first_line_found.group(2) + "\n"
parsed_data[keyword] = escape_xml_char(value)
elif kwd_more_line_found:
if not keyword:
print("Extra mess in a comment: %s" % (line))
exit(1)
else:
value = kwd_more_line_found.group(1) + "\n"
parsed_data[keyword] += escape_xml_char(value)
for keyword in keywords:
if keyword == "variable" and keyword not in parsed_data:
parsed_data[keyword] = parsed_data["property"]
elif keyword not in parsed_data:
parsed_data[keyword] = ""
for key in parsed_data.keys():
parsed_data[key] = parsed_data[key].rstrip()
return parsed_data
def write_data(outfile, parsed_data):
outfile.write(
'<property name="{0}" variable="{1}" format="{2}" values="{3}" default="{4}" example="{5}" description="{6}"/>\n'.format(
parsed_data["property"],
parsed_data["variable"],
parsed_data["format"],
parsed_data["values"],
parsed_data["default"],
parsed_data["example"],
parsed_data["description"],
)
)
def escape_xml_char(text):
text = text.replace("&", "&amp;")
text = text.replace("<", "&lt;")
text = text.replace(">", "&gt;")
text = text.replace('"', "&quot;")
text = text.replace("'", "&apos;")
return text
if len(sys.argv) < 4:
print("Usage: %s [plugin] [output-xml-file] [srcfiles]" % (sys.argv[0]))
exit(1)
argv = list(sys.argv[1:])
plugin, output, source_files = argv[0], argv[1], argv[2:]
start_tag = "---" + plugin + "---"
end_tag = "---end---"
outfile = open(output, mode="w")
# write XML header
outfile.write("<nm-setting-docs>\n")
outfile.write(" ")
for one_file in source_files:
setting_name = get_setting_name(one_file)
if setting_name:
outfile.write('<setting name="' + setting_name + '">\n')
scan_doc_comments(plugin, outfile, one_file, start_tag, end_tag)
outfile.write("</setting>\n")
# write XML footer
outfile.write("</nm-setting-docs>")
# close output file
outfile.close()