diff options
author | Jiří Klimeš <jklimes@redhat.com> | 2014-07-04 09:23:25 +0200 |
---|---|---|
committer | Jiří Klimeš <jklimes@redhat.com> | 2014-08-29 13:59:44 +0200 |
commit | 1c2174a80296a38416fc6b5c1009035c5f7e6dbf (patch) | |
tree | e927815ffc9f89d2d27cf5593f7fc96b8a3422d3 | |
parent | def5d6c3a7eb941571f27f45c1fbd1df31656f98 (diff) | |
download | NetworkManager-1c2174a80296a38416fc6b5c1009035c5f7e6dbf.tar.gz |
libnm-util: generate-plugin-docs.pl script for extracting plugin docs
The scripts extracts plugin description from document comments for particular
properties and builds a XML file out of the data. The XML file can be used
later for generating manual pages or other documentation.
Unfortunately, gtk-doc won't allow descriptions that would be separated from
the main gtk-doc stuff. But it is still useful to have plugin description bits
co-located with property definitions. We use our home-grown comments and parse
them ourself. Afterall it's not that bad, and in addition it brings us a
freedom in shaping the comments to our needs.
-rw-r--r-- | configure.ac | 27 | ||||
-rw-r--r-- | libnm-util/Makefile.am | 11 | ||||
-rwxr-xr-x | libnm-util/generate-plugin-docs.pl | 198 |
3 files changed, 231 insertions, 5 deletions
diff --git a/configure.ac b/configure.ac index d6ffd106c4..6bc94b948f 100644 --- a/configure.ac +++ b/configure.ac @@ -773,6 +773,8 @@ install_pregen_manpages=no if test "$enable_gtk_doc" != "yes" \ -a -f man/NetworkManager.conf.5 \ -a -f man/nm-settings.5 \ + -a -f man/nm-settings-keyfile.5 \ + -a -f man/nm-settings-ifcfg-rh.5 \ -a -f man/nmcli-examples.5 \ -a -f man/NetworkManager.8; then install_pregen_manpages=yes @@ -783,14 +785,35 @@ AM_CONDITIONAL(INSTALL_PREGEN_MANPAGES, test "x${install_pregen_manpages}" = "xy if test -n "$INTROSPECTION_MAKEFILE" -a "$enable_gtk_doc" = "yes"; then # If g-i is installed we know we have python, but we might not have pygobject if python -c 'from gi.repository import GObject' >& /dev/null; then - AC_DEFINE(BUILD_SETTING_DOCS, [1], [Define if you we can build nm-setting-docs.xml]) - build_setting_docs=yes + have_pyobject=yes + fi + + # gtk-doc depends on perl, but we can check for it anyway + AC_PATH_PROG(PERL, perl, no) + # check for needed perl modules (use YAML; YAML::XS is better, but may not be so widespread) + required_perl_modules="YAML" + for module in $required_perl_modules; do + AC_MSG_CHECKING([checking for perl module '$module']) + if ${PERL} -e 'use '$module 2>/dev/null ; then + AC_MSG_RESULT([Ok]) + have_perl_modules=yes + else + AC_MSG_RESULT([Failed]) + AC_MSG_ERROR([You must have Perl modules to build settings plugin docs: $required_perl_modules.]) + fi + done + + if test "$have_pyobject" = "yes" -a "$have_perl_modules" = "yes"; then + AC_DEFINE(BUILD_SETTING_DOCS, [1], [Define if you we can build nm-setting-docs.xml, nm-keyfile-docs.xml and nm-ifcfg-rh-docs.xml]) + build_setting_docs=yes fi fi # check for pre-built setting docs if test "$build_setting_docs" != "yes" \ -a -f man/nm-settings.xml \ + -a -f man/nm-settings-keyfile.xml \ + -a -f man/nm-settings-ifcfg-rh.xml \ -a -f docs/api/settings-spec.xml \ -a -f cli/src/settings-docs.c; then AC_DEFINE(HAVE_SETTING_DOCS, [1], [Define if you have pre-built settings docs]) diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am index 873e8547dc..af43b29def 100644 --- a/libnm-util/Makefile.am +++ b/libnm-util/Makefile.am @@ -188,7 +188,7 @@ endif if BUILD_SETTING_DOCS -noinst_DATA = nm-setting-docs.xml +noinst_DATA = nm-setting-docs.xml nm-keyfile-docs.xml nm-ifcfg-rh-docs.xml nm-setting-docs.xml: generate-setting-docs.py NetworkManager-1.0.gir NetworkManager-1.0.typelib libnm-util.la export GI_TYPELIB_PATH=$(abs_builddir)$${GI_TYPELIB_PATH:+:$$GI_TYPELIB_PATH}; \ @@ -197,11 +197,16 @@ nm-setting-docs.xml: generate-setting-docs.py NetworkManager-1.0.gir NetworkMana --gir $(builddir)/NetworkManager-1.0.gir \ --output $@ +nm-keyfile-docs.xml: generate-plugin-docs.pl $(libnm_util_la_csources) + $(srcdir)/generate-plugin-docs.pl keyfile $@ +nm-ifcfg-rh-docs.xml: generate-plugin-docs.pl $(libnm_util_la_csources) + $(srcdir)/generate-plugin-docs.pl ifcfg-rh $@ + endif -DISTCLEANFILES += nm-setting-docs.xml +DISTCLEANFILES += nm-setting-docs.xml nm-keyfile-docs.xml nm-ifcfg-rh-docs.xml -EXTRA_DIST += generate-setting-docs.py +EXTRA_DIST += generate-setting-docs.py generate-plugin-docs.pl if ENABLE_TESTS diff --git a/libnm-util/generate-plugin-docs.pl b/libnm-util/generate-plugin-docs.pl new file mode 100755 index 0000000000..a986fae058 --- /dev/null +++ b/libnm-util/generate-plugin-docs.pl @@ -0,0 +1,198 @@ +#!/usr/bin/env perl +# vim: ft=perl ts=2 sts=2 sw=2 et ai +# -*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# +# Copyright 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; +#YAML:XS is based on libyaml C library and it is a good and fast YAML implementation. +#However it may not be present everywhere. So use YAML instead. +#use YAML::XS qw(Load); +use YAML qw(Load); + +# global variables +my @keywords = ("property", "variable", "format", "values", "default", "example", "description"); +my @source_files; +my @data; +my $fo; + +(scalar @ARGV == 2) or die "Usage: $0 <plugin> <output-xml-file>\n"; +($ARGV[0] eq "keyfile" || $ARGV[0] eq "ifcfg-rh") or die "Allowed <plugin> values: keyfile, ifcfg-rh\n"; +my ($plugin, $output) = @ARGV; +my $start_tag = "---$plugin---\\s*\$"; +my $end_tag = '---end---'; + +# get source files to scan for documentation comments (nm-setting-<something>.c) +my $file = 'Makefile.am'; +open my $fh, '<', $file or die "Can't open $file: $!"; +while (my $line = <$fh>) { + chomp $line; + my @strings = $line =~ /(?:^|\s)(nm-setting-[^.]*\.c)(?:\s|$)/g; + push @source_files, @strings +} +close $fh; + +# open output file +open $fo, '>', $output or die "Can't open $output: $!"; + +# write XML header +write_header(); + +# write generated documenation for each setting +foreach my $c_file (@source_files) { + my $path = "$c_file"; + my $setting_name = get_setting_name($path); + write_item("<setting name=\"$setting_name\">"); + scan_doc_comments($path, $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/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 (as a YAML document) +sub process_data { + return if not @data; + my $kwd_pat = join("|", @keywords); + my $yaml_literal_seq = "|\n"; + + foreach (@data) { + # make a proper YAML document from @data + $_ =~ s/^\s*\**\s+|\s+$//; # remove leading spaces and *, and traling spaces + # Properly indent the text so that it is a valid YAML, and insert | (for literal text) + if ($_ =~ /^($kwd_pat):\s+/) { + # add | after "keyword:" that allows using literal text (YAML won't break on special character) + # http://learnxinyminutes.com/docs/yaml/ and http://www.yaml.org/spec/1.2/spec.html#id2795688 + $_ =~ s/(^($kwd_pat):)/$1 $yaml_literal_seq/; + } else { + $_ = " " . $_; # indent the text + } + } + my $str = join ("", @data); + my $yaml_data = Load($str); + + # now write ia line into the XML + my $name = $yaml_data->{property} // ""; + my $var = $yaml_data->{variable} // $name; # fallback to "property: " + my $format = $yaml_data->{format} // ""; + my $values = $yaml_data->{values} // ""; + my $def = $yaml_data->{default} // ""; + my $exam = $yaml_data->{example} // ""; + my $desc = $yaml_data->{description} // ""; + + 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{<?xml version=\"1.0\"?> + <!DOCTYPE nm-$plugin-docs [ + ]> + + <nm-$plugin-docs> + }) =~ s/^ {7}//mg; + print {$fo} $header; +} + +sub write_footer { + my $footer = "</nm-$plugin-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; + } +} + |