mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-07 00:31:11 +00:00
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:
parent
8232c3473f
commit
86dcb31ab3
|
@ -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 \
|
||||
|
|
|
@ -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@'
|
||||
|
|
|
@ -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/&/&/sg;
|
||||
$val =~ s/</</sg;
|
||||
$val =~ s/>/>/sg;
|
||||
$val =~ s/"/"/sg;
|
||||
$val =~ s/'/'/sg;
|
||||
}
|
||||
}
|
||||
|
146
tools/generate-docs-nm-property-infos.py
Executable file
146
tools/generate-docs-nm-property-infos.py
Executable 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("&", "&")
|
||||
text = text.replace("<", "<")
|
||||
text = text.replace(">", ">")
|
||||
text = text.replace('"', """)
|
||||
text = text.replace("'", "'")
|
||||
|
||||
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()
|
Loading…
Reference in a new issue