Hello community,

here is the log from the commit of package kapidox for openSUSE:Factory checked 
in at 2016-08-22 14:00:35
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/kapidox (Old)
 and      /work/SRC/openSUSE:Factory/.kapidox.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "kapidox"

Changes:
--------
--- /work/SRC/openSUSE:Factory/kapidox/kapidox.changes  2016-07-16 
22:13:30.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.kapidox.new/kapidox.changes     2016-08-22 
14:00:38.000000000 +0200
@@ -1,0 +2,10 @@
+Sun Aug  7 21:50:16 UTC 2016 - hrvoje.sen...@gmail.com
+
+- Update to 5.25.0
+  * Qt >= 5.5 is now required
+  * Many improvements to the output formatting
+  * Mainpage.dox has now higher priority than README.md
+  * For more details please see:
+    https://www.kde.org/announcements/kde-frameworks-5.25.0.php
+
+-------------------------------------------------------------------

Old:
----
  kapidox-5.24.0.tar.xz

New:
----
  kapidox-5.25.0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ kapidox.spec ++++++
--- /var/tmp/diff_new_pack.NpJdvT/_old  2016-08-22 14:00:39.000000000 +0200
+++ /var/tmp/diff_new_pack.NpJdvT/_new  2016-08-22 14:00:39.000000000 +0200
@@ -16,9 +16,9 @@
 #
 
 
-%define _tar_path 5.24
+%define _tar_path 5.25
 Name:           kapidox
-Version:        5.24.0
+Version:        5.25.0
 Release:        0
 Requires:       doxygen
 BuildRequires:  fdupes

++++++ kapidox-5.24.0.tar.xz -> kapidox-5.25.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/README.md new/kapidox-5.25.0/README.md
--- old/kapidox-5.24.0/README.md        2016-06-20 15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/README.md        2016-08-06 01:24:22.000000000 +0200
@@ -14,6 +14,7 @@
 
 ## Dependencies
 
+### Required
 Python 2 or 3 is required to run the scripts.  Whichever version of python you
 use needs to have the jinja2 and yaml (or pyyaml) modules.
 
@@ -21,12 +22,17 @@
 
     pip install --user PyYAML jinja2
 
+Of course, you need Doxygen!
+
+### Optional
+Doxyqml and doxypypy might be needed to let doxygen document respectevely qml
+and python sources.
+
 To generate the dependency diagrams, you need the Graphviz Python bindings.
 They are currently not available from pip, but most distributions provide them.
 You can get binaries and source archives from
 <http://www.graphviz.org/Download.php>.
 
-
 ## Installation
 
 Unlike almost every other KDE module, kapidox does not use CMake.  This is
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/setup.py new/kapidox-5.25.0/setup.py
--- old/kapidox-5.24.0/setup.py 2016-06-20 15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/setup.py 2016-08-06 01:24:22.000000000 +0200
@@ -6,7 +6,7 @@
 
 setup(
         name='kapidox',
-        version='5.24.0',
+        version='5.25.0',
         description='KDE API documentation generation tools',
         maintainer = 'Alex Merry',
         maintainer_email = 'alex.me...@kde.org',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/src/kapidox/__init__.py 
new/kapidox-5.25.0/src/kapidox/__init__.py
--- old/kapidox-5.24.0/src/kapidox/__init__.py  2016-06-20 15:51:32.000000000 
+0200
+++ new/kapidox-5.25.0/src/kapidox/__init__.py  2016-08-06 01:24:22.000000000 
+0200
@@ -1,2 +1,4 @@
-
-from . import generator, preprocessing, utils, argparserutils
+## @package kapidox
+#
+# The root of the module
+#
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/src/kapidox/argparserutils.py 
new/kapidox-5.25.0/src/kapidox/argparserutils.py
--- old/kapidox-5.24.0/src/kapidox/argparserutils.py    2016-06-20 
15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/src/kapidox/argparserutils.py    2016-08-06 
01:24:22.000000000 +0200
@@ -37,7 +37,7 @@
         description='Generate API documentation for the KDE Products'
         )
     group = add_sources_group(parser)
-    group.add_argument('frameworksdir',
+    group.add_argument('sourcesdir',
             help='Location of the sources.')
     group.add_argument('--depdiagram-dot-dir',
             help='Generate dependency diagrams, using the .dot files from 
DIR.',
@@ -55,8 +55,8 @@
                       'See <http://www.graphviz.org/Download.php>.')
         exit(1)
 
-    if not os.path.isdir(args.frameworksdir):
-        logging.error(args.frameworksdir + " is not a directory")
+    if not os.path.isdir(args.sourcesdir):
+        logging.error(args.sourcesdir + " is not a directory")
         exit(2)
 
     return args
@@ -68,7 +68,7 @@
 
 def add_output_group(parser):
     group = parser.add_argument_group('output options')
-    group.add_argument('--title', default='KDE API Documentation',
+    group.add_argument('--title', default='API Documentation',
             help='String to use for page titles.')
     group.add_argument('--man-pages', action='store_true',
             help='Generate man page documentation.')
@@ -77,7 +77,7 @@
     group.add_argument('--searchengine', action='store_true',
             help="Enable Doxygen's search engine feature.")
     group.add_argument('--api-searchbox', action='store_true',
-            help="Enable the API searchbox (only useful for api.kde.org).")
+            help="Enable the API searchbox.")
     return group
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/src/kapidox/data/Doxyfile.global 
new/kapidox-5.25.0/src/kapidox/data/Doxyfile.global
--- old/kapidox-5.24.0/src/kapidox/data/Doxyfile.global 2016-06-20 
15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/src/kapidox/data/Doxyfile.global 2016-08-06 
01:24:22.000000000 +0200
@@ -117,7 +117,7 @@
 
 # Use doxyqml filter for qml files
 FILTER_PATTERNS        = *.qml=doxyqml
-
+EXTENSION_MAPPING      = qml=C++
 USE_MDFILE_AS_MAINPAGE = README.md
 
 #---------------------------------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/src/kapidox/data/htmlresource/kde.css 
new/kapidox-5.25.0/src/kapidox/data/htmlresource/kde.css
--- old/kapidox-5.24.0/src/kapidox/data/htmlresource/kde.css    2016-06-20 
15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/src/kapidox/data/htmlresource/kde.css    2016-08-06 
01:24:22.000000000 +0200
@@ -102,17 +102,22 @@
     font-weight: bold;
 }
 
-dt a {
+.menu_box dl {
+    padding: 0 0 0 10px;
+}
+
+.menu_box dt a {
     font-weight: bold;
 }
 
-dt {
+.menu_box dt {
+    font-weight: bold;
     margin-top: 0.8em;
 }
-dt:first-child {
+.menu_box dt:first-child {
     margin-top: 0;
 }
-dd {
+.menu_box dd {
     margin-left: 1em;
     color: #323232;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/src/kapidox/data/templates/base.html 
new/kapidox-5.25.0/src/kapidox/data/templates/base.html
--- old/kapidox-5.24.0/src/kapidox/data/templates/base.html     2016-06-20 
15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/src/kapidox/data/templates/base.html     2016-08-06 
01:24:22.000000000 +0200
@@ -27,7 +27,9 @@
   <script type="text/javascript" src="dynsections.js"></script>
   <link rel="shortcut icon" href="{{resources}}/favicon.ico" />
   <link rel="icon" href="{{resources}}/favicon.ico" />
+{% if doxygencss %}
   <link rel="stylesheet" type="text/css" href="{{doxygencss}}" />
+{% endif %}
   <link rel="stylesheet" type="text/css" href="{{resources}}/kde.css" />
 
 {% block head %}{% endblock %}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kapidox-5.24.0/src/kapidox/data/templates/frontpage.html 
new/kapidox-5.25.0/src/kapidox/data/templates/frontpage.html
--- old/kapidox-5.24.0/src/kapidox/data/templates/frontpage.html        
2016-06-20 15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/src/kapidox/data/templates/frontpage.html        
2016-08-06 01:24:22.000000000 +0200
@@ -40,7 +40,13 @@
                     <ul class="list-unstyled">
                       <li class=product-name><a name="prod-{{ product.name }}" 
href="{{ product.href }}">{{ product.fancyname }}</a></li>
                       <li>{{ product.description }}</li>
-                      <li class="prod-maintainers">{% include 
"maintainers.html" %}</li>
+                      <li class="prod-maintainers">
+                {% for maintainer in product.maintainers %}
+                        <a href="mailto:{{ maintainer.email }}">{{ 
maintainer.name }}</a>{% if not loop.last %},{% endif %}
+                {% else %}
+                        <a href="mailto:kde-de...@kde.org";>The KDE 
Community</a>
+                {% endfor %}
+                      </li>
                     {% if product.platforms %}
                       <li class="prod-platforms">{{ product.platforms | join(' 
| ') }}</li>
                     {% endif %}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kapidox-5.24.0/src/kapidox/data/templates/libinfo.html 
new/kapidox-5.25.0/src/kapidox/data/templates/libinfo.html
--- old/kapidox-5.24.0/src/kapidox/data/templates/libinfo.html  2016-06-20 
15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/src/kapidox/data/templates/libinfo.html  2016-08-06 
01:24:22.000000000 +0200
@@ -10,7 +10,7 @@
   <p>{{ fwinfo.description }}</p>
 
   <dl>
-    <dt>Maintainer{% if fwinfo.maintainers|count != 0 %}s{% endif %}</dt>
+    <dt>Maintainer{% if fwinfo.maintainers|count > 1 %}s{% endif %}</dt>
       <dd>{% set product = fwinfo %}{% include "maintainers.html" %}</dd>
 
 {#    <dt>Dependencies</dt>
@@ -36,8 +36,8 @@
       </dd>
 
     <dt>Community</dt>
-      <dd>IRC channel: #{{ fwinfo.irc }} on Freenode</dd>
-      <dd><a href="https://mail.kde.org/mailman/listinfo/{{ fwinfo.mailinglist 
}}">Mailing list</a></dd>
+      <dd>IRC channel: <a href="irc://freenode/#{{ fwinfo.irc }}">#{{ 
fwinfo.irc }}</a> on Freenode</dd>
+      <dd>Mailing list: <a href="https://mail.kde.org/mailman/listinfo/{{ 
fwinfo.mailinglist }}">{{ fwinfo.mailinglist }}</a></dd>
 
 {% if fwinfo.libraries is iterable and fwinfo.libraries|count != 0 %}
     <dt>Use with <a 
href="https://techbase.kde.org/Development/Tutorials/CMake";>CMake</a></dt>
@@ -50,7 +50,9 @@
       <dd><pre class="fragment">QT +={% for lib in 
fwinfo.libraries|selectattr("qmake") %} {{ lib.qmake }}{% endfor %} {% for line 
in fwinfo.qmakepro %}<br/>{{ line }} {% endfor %}</pre></dd>
 {% endif %}
 
-    <dt>Clone URL</dt>
-      <dd><pre class="fragment">git clone <a 
href="https://quickgit.kde.org/?p={{ fwinfo.name 
}}.git">git://anongit.kde.org/{{ fwinfo.name }}.git</a></pre></dd>
+    <dt>Clone</dt>
+      <dd><pre class="fragment">git clone git://anongit.kde.org/{{ fwinfo.name 
}}.git</pre></dd>
+    <dt>Browse source</dt>
+      <dd>{{ fwinfo.fancyname }} on <a href="https://quickgit.kde.org/?p={{ 
fwinfo.name }}.git">Quickgit</a></dd>
   </dl>
 </div>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kapidox-5.24.0/src/kapidox/data/templates/maintainers.html 
new/kapidox-5.25.0/src/kapidox/data/templates/maintainers.html
--- old/kapidox-5.24.0/src/kapidox/data/templates/maintainers.html      
2016-06-20 15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/src/kapidox/data/templates/maintainers.html      
2016-08-06 01:24:22.000000000 +0200
@@ -1,5 +1,5 @@
     {% for maintainer in product.maintainers %}
-      <a href="mailto:{{ maintainer.email }}">{{ maintainer.name }} &lt;{{ 
maintainer.email }}&gt;</a>{% if not loop.last %},<br/>{% endif %}
+      <a href="mailto:{{ maintainer.email }}">{{ maintainer.name }}</a>{% if 
not loop.last %},<br/>{% endif %}
     {% else %}
       <a href="mailto:kde-de...@kde.org";>The KDE Community</a>
     {% endfor %}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kapidox-5.24.0/src/kapidox/data/templates/subgroup.html 
new/kapidox-5.25.0/src/kapidox/data/templates/subgroup.html
--- old/kapidox-5.24.0/src/kapidox/data/templates/subgroup.html 2016-06-20 
15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/src/kapidox/data/templates/subgroup.html 2016-08-06 
01:24:22.000000000 +0200
@@ -83,16 +83,16 @@
               </div>
               <h2>List of the libraries</h2>
 
-              {% if group.libraries | selectattr('subgroup', 'none') | list | 
length > 0 %}
-                {% if group.subgroups | length > 0 %}
-                <h3><a name="sg-{{ nosubgroup }}"></a>Without subgroup</h3>
+              {% if group.libraries | selectattr('subproduct', 'none') | list 
| length > 0 %}
+                {% if group.subproducts | length > 0 %}
+                <h3><a name="sg-{{ nosubproduct }}"></a>Without subgroup</h3>
                 {% endif %}
-                {{ write_library_list(group.libraries | selectattr('subgroup', 
'none') )}}
+                {{ write_library_list(group.libraries | 
selectattr('subproduct', 'none') )}}
               {% endif %}
-              {% for subgroup in group.subgroups |sort(attribute='order') %}
-                <h3><a name="sg-{{ subgroup.name }}"></a>{{ subgroup.fancyname 
}}</h3>
-                <p> {{ subgroup.description }}</p>
-                {{ write_library_list(subgroup.libraries) }}
+              {% for subproduct in group.subproducts |sort(attribute='order') 
%}
+                <h3><a name="sg-{{ subproduct.name }}"></a>{{ 
subproduct.fancyname }}</h3>
+                <p> {{ subproduct.description }}</p>
+                {{ write_library_list(subproduct.libraries) }}
               {% endfor %}
 
 
@@ -112,15 +112,15 @@
             <ul>
               <li>
                 <ul>
-                  {% if group.libraries | selectattr('subgroup', 'none') | 
list | length > 0 %}
-                    {% if group.subgroups | length > 0 %}
-                    <li><a href="#sg-{{ nosubgroup }}">Without 
subgroups</a></li>
+                  {% if group.libraries | selectattr('subproducts', 'none') | 
list | length > 0 %}
+                    {% if group.subproduct | length > 0 %}
+                    <li><a href="#sg-{{ nosubproduct }}">Without 
subgroup</a></li>
                     {% else  %}
                     <li><a href="#content">All</a></li>
                     {% endif %}
                   {% endif %}
-                  {% for subgroup in group.subgroups | sort(attribute='order') 
%}
-                    <li><a href="#sg-{{ subgroup.name }}">{{ 
subgroup.fancyname }}</a></li>
+                  {% for subproduct in group.subproducts | 
sort(attribute='order') %}
+                    <li><a href="#sg-{{ subproduct.name }}">{{ 
subproduct.fancyname }}</a></li>
                   {% endfor %}
                 </ul>
               </li>
@@ -160,4 +160,24 @@
           </div>
         </div>
 
+        <div class="menu_box">
+          <div class="menutitle">
+            <div>
+              <h2>About</h2>
+            </div>
+          </div>
+
+          <p>{{ group.description }}</p>
+
+          <dl>
+            <dt>Maintainer{% if group.maintainers|count > 1 %}s{% endif %}</dt>
+            <dd>{% set product = group %}{% include "maintainers.html" %}</dd>
+            <dt>Supported platforms</dt>
+            <dd>{{ group.platforms | join(', ') }}</dd>
+            <dt>Community</dt>
+            <dd>IRC channel: <a href="irc://freenode/#{{ group.irc }}">#{{ 
group.irc }}</a> on Freenode</dd>
+            <dd>Mailing list: <a 
href="https://mail.kde.org/mailman/listinfo/{{ group.mailinglist }}">{{ 
group.mailinglist }}</a></dd>
+          </dl>
+        </div>
+
 {% endblock %} {# sidebar #}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/src/kapidox/doxyfilewriter.py 
new/kapidox-5.25.0/src/kapidox/doxyfilewriter.py
--- old/kapidox-5.24.0/src/kapidox/doxyfilewriter.py    2016-06-20 
15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/src/kapidox/doxyfilewriter.py    2016-08-06 
01:24:22.000000000 +0200
@@ -40,8 +40,11 @@
     def write_entry(self, key, value):
         """Write an entry
 
-        key -- the key part of the entry
-        value -- the value part of the entry. Can be a string, a list, a tuple 
or a boolean"""
+        Args:
+            key: the key part of the entry
+            value: the value part of the entry. Can be a string, a list, a
+        tuple or a boolean
+        """
         if isinstance(value, (list, tuple)):
             txt = ' '.join([_quote(x) for x in value])
         elif isinstance(value, bool):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/src/kapidox/generator.py 
new/kapidox-5.25.0/src/kapidox/generator.py
--- old/kapidox-5.24.0/src/kapidox/generator.py 2016-06-20 15:51:32.000000000 
+0200
+++ new/kapidox-5.25.0/src/kapidox/generator.py 2016-08-06 01:24:22.000000000 
+0200
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright 2016  Olivier Churlaud <oliv...@churlaud.com>
 # Copyright 2014  Alex Merry <alex.me...@kdemail.net>
 # Copyright 2014  Aurélien Gâteau <agat...@kde.org>
 # Copyright 2014  Alex Turbov <i.za...@gmail.com>
+# Copyright 2016  Olivier Churlaud <oliv...@churlaud.com>
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -54,6 +54,11 @@
 
 from .doxyfilewriter import DoxyfileWriter
 
+
+## @package kapidox.generator
+#
+# The generator
+
 __all__ = (
     "Context",
     "generate_apidocs",
@@ -88,6 +93,7 @@
         'srcdir',
         'tagfiles',
         'dependency_diagram',
+        'copyright',
         # Output
         'outputdir',
         'htmldir',
@@ -129,13 +135,12 @@
 def process_toplevel_html_file(outputfile, doxdatadir, products, title,
                                api_searchbox=False):
 
-    products.sort(key=lambda x: x['name'].lower())
+    products.sort(key=lambda x: x.fancyname.lower())
     mapping = {
             'resources': './resources',
             'api_searchbox': api_searchbox,
             # steal the doxygen css from one of the frameworks
             # this means that all the doxygen-provided images etc. will be 
found
-            'doxygencss': products[0]['outputdir'] + '/html/doxygen.css',
             'title': title,
             'breadcrumbs': {
                 'entries': [
@@ -159,9 +164,6 @@
         mapping = {
             'resources': '../resources',
             'api_searchbox': api_searchbox,
-            # steal the doxygen css from one of the frameworks
-            # this means that all the doxygen-provided images etc. will be 
found
-            'doxygencss': group['libraries'][0]['outputdir'] + 
'/html/doxygen.css',
             'title': title,
             'breadcrumbs': {
                 'entries': [
@@ -171,7 +173,7 @@
                     },
                     {
                         'href': './index.html',
-                        'text': group['fancyname']
+                        'text': group.fancyname
                     }
                     ]
                 },
@@ -179,9 +181,9 @@
             'available_platforms': sorted(available_platforms),
         }
 
-        if not os.path.isdir(group['name']):
-            os.mkdir(group['name'])
-        outputfile = group['name']+'/index.html'
+        if not os.path.isdir(group.name):
+            os.mkdir(group.name)
+        outputfile = group.name + '/index.html'
         tmpl = 
create_jinja_environment(doxdatadir).get_template('subgroup.html')
         with codecs.open(outputfile, 'w', 'utf-8') as outf:
             outf.write(tmpl.render(mapping))
@@ -189,7 +191,7 @@
 
 def create_dirs(ctx):
     ctx.htmldir = os.path.join(ctx.outputdir, HTML_SUBDIR)
-    ctx.tagfile = os.path.join(ctx.htmldir, ctx.modulename + '.tags')
+    ctx.tagfile = os.path.join(ctx.htmldir, ctx.fwinfo.fancyname + '.tags')
 
     if not os.path.exists(ctx.outputdir):
         os.makedirs(ctx.outputdir)
@@ -215,21 +217,24 @@
 
 
 def find_tagfiles(docdir, doclink=None, flattenlinks=False, exclude=None, 
_depth=0):
-    """Find Doxygen-generated tag files in a directory
+    """Find Doxygen-generated tag files in a directory.
 
     The tag files must have the extention .tags, and must be in the listed
     directory, a subdirectory or a subdirectory named html of a subdirectory.
 
-    docdir       -- the directory to search
-    doclink      -- the path or URL to use when creating the documentation
-                    links; if None, this will default to docdir
-    flattenlinks -- if this is True, generated links will assume all the html
-                    files are directly under doclink; if False (the default),
-                    the html files are assumed to be at the same relative
-                    location to doclink as the tag file is to docdir; ignored
-                    if doclink is not set
+    Args:
+        docdir:       (string) the directory to search.
+        doclink:      (string) the path or URL to use when creating the
+                      documentation links; if None, this will default to
+                      docdir. (optional, default None)
+        flattenlinks: (bool) if True, generated links will assume all the html
+                      files are directly under doclink; else the html files are
+                      assumed to be at the same relative location to doclink as
+                      the tag file is to docdir; ignored if doclink is not set.
+                      (optional, default False)
 
-    Returns a list of pairs of (tag_file,link_path)
+    Returns:
+        A list of pairs of (tag_file,link_path).
     """
 
     if not os.path.isdir(docdir):
@@ -283,18 +288,20 @@
 
     At least one of docdir or searchpaths must be given for it to find 
anything.
 
-    suggestion   -- the first place to look (will complain if there are no
-                    documentation tag files there)
-    doclink      -- the path or URL to use when creating the documentation
-                    links; if None, this will default to docdir
-    flattenlinks -- if this is True, generated links will assume all the html
-                    files are directly under doclink; if False (the default),
-                    the html files are assumed to be at the same relative
-                    location to doclink as the tag file is to docdir; ignored
-                    if doclink is not set
-    searchpaths  -- other places to look for documentation tag files
+    Args:
+        suggestion:   the first place to look (will complain if there are no
+                      documentation tag files there)
+        doclink:      the path or URL to use when creating the documentation
+                      links; if None, this will default to docdir
+        flattenlinks: if this is True, generated links will assume all the html
+                      files are directly under doclink; if False (the default),
+                      the html files are assumed to be at the same relative
+                      location to doclink as the tag file is to docdir; ignored
+                      if doclink is not set
+        searchpaths:  other places to look for documentation tag files
 
-    Returns a list of pairs of (tag_file,link_path)
+    Returns:
+        A list of pairs of (tag_file,link_path)
     """
 
     if not suggestion is None:
@@ -323,9 +330,12 @@
     Looks for a set of standard Doxygen files (like namespaces.html) and
     provides menu text for those it finds in htmldir.
 
-    htmldir -- the directory the HTML files are contained in
+    Args:
+        htmldir:    (string) the directory the HTML files are contained in.
+        modulname:  (string) the name of the library
 
-    Returns a list of maps with 'text' and 'href' keys
+    Returns:
+        A list of maps with 'text' and 'href' keys.
     """
     entries = [
             {'text': 'Main Page', 'href': 'index.html'},
@@ -355,20 +365,21 @@
     The HTML files produced by Doxygen with our custom header and footer files
     look like this:
 
-        <!--
-        key1: value1
-        key2: value2
-        ...
-        -->
-        <html>
-        <head>
-        ...
-        </head>
-        <body>
-        ...
-        </body>
-        </html>
-
+    @code
+    <!--
+    key1: value1
+    key2: value2
+    ...
+    -->
+    <html>
+    <head>
+    ...
+    </head>
+    <body>
+    ...
+    </body>
+    </html>
+    @endcode
 
     The parser fills the dict from the top key/value block, and add the content
     of the body to the dict using the "content" key.
@@ -417,8 +428,10 @@
 
     Performs text substitutions on each line in each .html file in a directory.
 
-    htmldir -- the directory containing the .html files
-    mapping -- a dict of mappings
+    Args:
+        htmldir: (string) the directory containing the .html files.
+        mapping: (dict) a dict of mappings.
+
     """
     for name in os.listdir(htmldir):
         if name.endswith('.html'):
@@ -447,9 +460,11 @@
 def build_classmap(tagfile):
     """Parses a tagfile to get a map from classes to files
 
-    tagfile -- the Doxygen-generated tagfile to parse
+    Args:
+        tagfile: the Doxygen-generated tagfile to parse.
 
-    Returns a list of maps (keys: classname and filename)
+    Returns:
+        A list of maps (keys: classname and filename).
     """
     import xml.etree.ElementTree as ET
     tree = ET.parse(tagfile)
@@ -469,14 +484,19 @@
     """Write a mapping out as PHP code
 
     Creates a PHP array as described by mapping.  For example, the mapping
-      [("foo","bar"),("x","y")]
+
+        [("foo","bar"),("x","y")]
+
     would cause the file
-      <?php $map = array('foo' => 'bar','x' => 'y') ?>
+
+        <?php $map = array('foo' => 'bar','x' => 'y') ?>
+
     to be written out.
 
-    mapping    -- a list of pairs of strings
-    outputfile -- the file to write to
-    varname    -- override the PHP variable name (defaults to 'map')
+    Args:
+        mapping:    a list of pairs of strings
+        outputfile: the file to write to
+        varname:    override the PHP variable name (defaults to 'map')
     """
     logging.info('Generating PHP mapping')
     with codecs.open(outputfile, 'w', 'utf-8') as f:
@@ -511,7 +531,7 @@
     def find_src_subdir(dirlist, deeper_subd=None):
         returnlist = []
         for d in dirlist:
-            pth = os.path.join(ctx.fwinfo['path'], d)
+            pth = os.path.join(ctx.fwinfo.path, d)
             if deeper_subd is not None:
                 pth = os.path.join(pth, deeper_subd)
             if os.path.isdir(pth) or os.path.isfile(pth):
@@ -520,20 +540,14 @@
                 pass  # We drop it
         return returnlist
 
-    # Paths and basic project info
-
-    # FIXME: preprocessing?
-    # What about providing the build directory? We could get the version
-    # as well, then.
-
     input_list = []
-    if os.path.isfile(ctx.fwinfo['path']+"/README.md"):
-        input_list.append(ctx.fwinfo['path']+"/README.md")
-    if os.path.isfile(ctx.fwinfo['path']+"/Mainpage.dox"):
-        input_list.append(ctx.fwinfo['path']+"/Mainpage.dox")
+    if os.path.isfile(ctx.fwinfo.path + "/Mainpage.dox"):
+        input_list.append(ctx.fwinfo.path + "/Mainpage.dox")
+    elif os.path.isfile(ctx.fwinfo.path + "/README.md"):
+        input_list.append(ctx.fwinfo.path + "/README.md")
 
-    input_list.extend(find_src_subdir(ctx.fwinfo['srcdirs']))
-    input_list.extend(find_src_subdir(ctx.fwinfo['docdir']))
+    input_list.extend(find_src_subdir(ctx.fwinfo.srcdirs))
+    input_list.extend(find_src_subdir(ctx.fwinfo.docdir))
     image_path_list = []
 
     if ctx.dependency_diagram:
@@ -556,11 +570,11 @@
         # FIXME: can we get the project version from CMake? No from GIT TAGS!
 
         # Input locations
-        image_path_list.extend(find_src_subdir(ctx.fwinfo['docdir'], 'pics'))
+        image_path_list.extend(find_src_subdir(ctx.fwinfo.docdir, 'pics'))
         writer.write_entries(
                 INPUT=input_list,
-                DOTFILE_DIRS=find_src_subdir(ctx.fwinfo['docdir'], 'dot'),
-                EXAMPLE_PATH=find_src_subdir(ctx.fwinfo['exampledir']),
+                DOTFILE_DIRS=find_src_subdir(ctx.fwinfo.docdir, 'dot'),
+                EXAMPLE_PATH=find_src_subdir(ctx.fwinfo.exampledir),
                 IMAGE_PATH=image_path_list)
 
         # Other input settings
@@ -595,8 +609,8 @@
             writer.write_entries(**doxyfile_entries)
 
         # Module-specific overrides
-        if find_src_subdir(ctx.fwinfo['docdir']):
-            localdoxyfile = 
os.path.join(find_src_subdir(ctx.fwinfo['docdir'])[0], 'Doxyfile.local')
+        if find_src_subdir(ctx.fwinfo.docdir):
+            localdoxyfile = 
os.path.join(find_src_subdir(ctx.fwinfo.docdir)[0], 'Doxyfile.local')
             if os.path.isfile(localdoxyfile):
                 with codecs.open(localdoxyfile, 'r', 'utf-8') as f:
                     for line in f:
@@ -607,14 +621,12 @@
 
 
 def postprocess(ctx, classmap, template_mapping=None):
-    # TODO: copyright must be set from outside
-    copyright = '1996-' + str(datetime.date.today().year) + ' The KDE 
developers'
     mapping = {
             'doxygencss': 'doxygen.css',
             'resources': ctx.resourcedir,
             'title': ctx.title,
             'fwinfo': ctx.fwinfo,
-            'copyright': copyright,
+            'copyright': ctx.copyright,
             'api_searchbox': ctx.api_searchbox,
             'doxygen_menu': {'entries': menu_items(ctx.htmldir, 
ctx.modulename)},
             'class_map': {'classes': classmap},
@@ -671,21 +683,21 @@
     return True
 
 
-def create_fw_context(args, lib, tagfiles):
+def create_fw_context(args, lib, tagfiles, copyright=''):
     return Context(args,
                    # Names
-                   modulename=lib['name'],
-                   fancyname=lib['fancyname'],
+                   modulename=lib.name,
+                   fancyname=lib.fancyname,
                    fwinfo=lib,
                    # KApidox files
-                   resourcedir=('../../resources' if lib['parent'] is None
-                                else '../../../resources'),
+                   resourcedir=('../../../resources' if lib.part_of_group
+                                else '../../resources'),
                    # Input
-                   #srcdir=lib['srcdir'],
+                   copyright=copyright,
                    tagfiles=tagfiles,
-                   dependency_diagram=lib['dependency_diagram'],
+                   dependency_diagram=lib.dependency_diagram,
                    # Output
-                   outputdir=lib['outputdir'],
+                   outputdir=lib.outputdir,
                    )
 
 
@@ -706,11 +718,11 @@
         'href': '../../index.html',
         'text': 'KDE API Reference'
         }]
-    if ctx.fwinfo['parent'] is not None:
+    if  ctx.fwinfo.part_of_group:
         entries[0]['href'] = '../' + entries[0]['href']
         entries.append({
             'href': '../../index.html',
-            'text': ctx.fwinfo['product']['fancyname']
+            'text': ctx.fwinfo.product.fancyname
             })
     entries.append({
         'href': 'index.html',
@@ -745,7 +757,11 @@
 def create_fw_tagfile_tuple(lib):
     tagfile = os.path.abspath(
                 os.path.join(
-                    lib['outputdir'],
+                    lib.outputdir,
                     'html',
-                    lib['fancyname']+'.tags'))
-    return (tagfile, '../../' + lib['outputdir'] + '/html/')
+                    lib.fancyname+'.tags'))
+    if lib.part_of_group:
+        prefix = '../../../'
+    else:
+        prefix = '../../'
+    return (tagfile, prefix + lib.outputdir + '/html/')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/src/kapidox/models.py 
new/kapidox-5.25.0/src/kapidox/models.py
--- old/kapidox-5.24.0/src/kapidox/models.py    1970-01-01 01:00:00.000000000 
+0100
+++ new/kapidox-5.25.0/src/kapidox/models.py    2016-08-06 01:24:22.000000000 
+0200
@@ -0,0 +1,193 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2016  Olivier Churlaud <oliv...@churlaud.com>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+import os.path
+import string
+from kapidox import utils
+
+## @package kapidox.models
+#
+# Contains the classes representing the objects used by kapidox
+#
+
+class Library(object):
+    """ Library
+    """
+    def __init__(self, metainfo, products, platforms, all_maintainers):
+
+        # If it does not belong to a product, no need to go further
+        self.product = None
+        self.subproduct = None
+
+        if 'group' in metainfo:
+            productname = metainfo['group']
+            self.part_of_group = True
+        else:
+            productname = metainfo['name']
+            self.part_of_group = False
+        if utils.serialize_name(productname) not in products:
+            productname = metainfo['name']
+            del metainfo['group']
+            products[metainfo['name']] = Product(metainfo, all_maintainers)
+            self.part_of_group = False
+            logging.warning("Group of {} not found: 
dropped.".format(metainfo['fancyname']))
+        self.product = products[utils.serialize_name(productname)]
+        if self.product is None:
+            raise ValueError("'{}' does not belong to a product."
+                             .format(metainfo['name']))
+
+        if 'subgroup' in metainfo:
+            for sp in self.product.subproducts:
+                if sp.name == utils.serialize_name(metainfo['subgroup']):
+                    self.subproduct = sp
+            if self.subproduct is None:
+                logging.warning("Subgroup {} of library {} not documentated, 
subgroup will be None"
+                                .format(metainfo['subgroup'], 
metainfo['name']))
+
+        if self.subproduct is not None:
+            self.parent = self.subproduct
+            self.subproduct.libraries.append(self)
+        else:
+            self.parent = self.product
+        self.product.libraries.append(self)
+
+        self.name = metainfo['name']
+        self.fancyname = metainfo['fancyname']
+        self.description = metainfo.get('description')
+        self.maintainers = utils.set_maintainers(metainfo.get('maintainer'), 
all_maintainers)
+        self.platforms = platforms
+        self.outputdir = self._set_outputdir(self.part_of_group)
+        self.href = '../' + self.outputdir.lower() + '/html/index.html'
+        self.path = metainfo['path']
+        self.srcdirs = utils.tolist(metainfo.get('public_source_dirs', 
['src']))
+        self.docdir = utils.tolist(metainfo.get('public_doc_dir', ['docs']))
+        self.exampledir = utils.tolist(metainfo.get('public_example_dir', 
['examples']))
+        self.dependency_diagram = None
+        self.type = metainfo.get('type', '')
+        self.portingAid = metainfo.get('portingAid', False)
+        self.deprecated = metainfo.get('deprecated', False)
+        self.libraries = metainfo.get('libraries', [])
+        self.cmakename = metainfo.get('cmakename', '')
+        self.irc = metainfo.get('irc', self.product.irc)
+        self.mailinglist = metainfo.get('mailinglist', 
self.product.mailinglist)
+
+    def _extend_parent(self, metainfo, key, key_obj, default):
+        if key in metainfo:
+            return metainfo[key]
+        elif getattr(self.product, key_obj) is not None:
+            return getattr(self.product, key_obj)
+        else:
+            return default
+
+    def _set_outputdir(self, grouped):
+        outputdir = self.name
+        if grouped:
+            outputdir = self.product.outputdir + '/' + outputdir
+        return outputdir.lower()
+
+
+class Product(object):
+    """ Product
+    """
+    parent = None
+    # if there is a group, the product is the group
+    # else the product is directly the library
+    def __init__(self, metainfo, all_maintainers):
+        if 'group_info' in metainfo:
+            self.name = utils.serialize_name(metainfo['group'])
+            self.fancyname = metainfo['group_info'].get('fancyname', 
string.capwords(metainfo['group']))
+            self.description = metainfo['group_info'].get('description')
+            self.long_description = 
metainfo['group_info'].get('long_description', [])
+            self.maintainers = 
utils.set_maintainers(metainfo['group_info']['maintainer'],
+                                                     all_maintainers)
+            self.platforms = metainfo['group_info'].get('platforms')
+            self.outputdir = self.name
+            self.href = self.outputdir + '/index.html'
+            self.logo_url_src = self._set_logo_src(metainfo['path'],
+                                                   metainfo['group_info'])
+            self.logo_url = self._set_logo()
+            self.libraries = []  # We'll set this later
+            self.subgroups = []  # We'll set this later
+            self.irc = metainfo['group_info'].get('irc', 'kde-devel')
+            self.mailinglist = metainfo['group_info'].get('mailinglist', 
'kde-devel')
+            self.subproducts = 
self._extract_subproducts(metainfo['group_info'])
+
+        elif 'group' not in metainfo:
+            self.name = utils.serialize_name(metainfo['name'])
+            self.fancyname = metainfo['fancyname']
+            self.description = metainfo.get('description')
+            self.maintainers = 
utils.set_maintainers(metainfo.get('maintainer'), all_maintainers)
+            self.platforms = [x['name'] for x in metainfo.get('platforms', 
[{'name': None}])]
+            self.outputdir = self.name
+            self.href = self.outputdir + '/html/index.html'
+            self.logo_url_src = self._set_logo_src(metainfo['path'], metainfo)
+            self.logo_url = self._set_logo()
+            self.libraries = []
+            self.irc = None
+            self.mailinglist = None
+        else:
+            raise ValueError("I do not recognize a product in {}."
+                             .format(metainfo['name']))
+
+    def _extract_subproducts(self, groupinfo):
+        subproducts = []
+        if 'subgroups' in groupinfo:
+            for sg in groupinfo['subgroups']:
+                sg
+                if 'name' in sg:
+                    subproducts.append(Subproduct(sg, self))
+        return subproducts
+
+    def _set_logo(self):
+        if self.logo_url_src is not None:
+            filename, ext = os.path.splitext(self.logo_url_src)
+            return self.outputdir + '/' + self.name + ext
+        else:
+            return None
+
+    def _set_logo_src(self, path, dct):
+        if 'logo' in dct:
+            logo_url = os.path.join(path, dct['logo'])
+            if os.path.isfile(logo_url):
+                return logo_url
+            else:
+                logging.warning("{} logo file doesn't exist, set back to None"
+                                .format(self.fancyname))
+                return None
+        else:
+            return None
+
+class Subproduct(object):
+    """ Subproduct
+    """
+    def __init__(self, sginfo, product):
+        self.fancyname = sginfo['name']
+        self.name = utils.serialize_name(sginfo['name'])
+        self.description = sginfo.get('description')
+        self.order = sginfo.get('order', 99)  # If no order, go to end
+        self.libraries = []
+        self.product = product
+        self.parent = product
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/src/kapidox/preprocessing.py 
new/kapidox-5.25.0/src/kapidox/preprocessing.py
--- old/kapidox-5.24.0/src/kapidox/preprocessing.py     2016-06-20 
15:51:32.000000000 +0200
+++ new/kapidox-5.25.0/src/kapidox/preprocessing.py     2016-08-06 
01:24:22.000000000 +0200
@@ -32,7 +32,6 @@
 
 import logging
 import os
-import string
 
 try:
     from urllib2 import Request, urlopen, HTTPError
@@ -43,11 +42,11 @@
 import yaml
 
 from kapidox import utils
+from kapidox.models import Library, Product
 
 __all__ = (
     "create_metainfo",
-    "parse_tree",
-    "set_maintainers")
+    "parse_tree")
 
 
 PLATFORM_ALL = "All"
@@ -56,7 +55,7 @@
 
 ## @package kapidox.preprocessing
 #
-# Preprocess the needed information.
+# Preprocessing of the needed information.
 #
 # The module allow to walk through folders, read metainfo files and create
 # products, subgroups and libraries representing the projects.
@@ -90,7 +89,7 @@
     """Look for a `metadata.yaml` file and create a dictionary out it.
 
     Args:
-        path: (string) the current path to search;
+        path: (string) the current path to search.
     Returns:
         A dictionary containing all the parsed information, or `None` if it
     did not fullfill some conditions.
@@ -105,7 +104,8 @@
 
     try:
         metainfo = yaml.load(open(metainfo_file))
-    except:
+    except Exception as e:
+        print(e)
         logging.warning('Could not load metainfo.yaml for {}, skipping it'
                         .format(path))
         return None
@@ -121,12 +121,17 @@
         return None
 
     name = os.path.basename(path)
-    fancyname = utils.parse_fancyname(path)
+    if 'fancyname' in metainfo:
+        fancyname = metainfo['fancyname']
+    else:
+        fancyname = utils.parse_fancyname(path)
+
     if not fancyname:
         logging.warning('Could not find fancy name for {}, skipping it'
                         .format(path))
         return None
-
+    # A fancyname has 1st char capitalized
+    fancyname = fancyname[0].capitalize() + fancyname[1:]
     metainfo.update({
         'fancyname': fancyname,
         'name': name,
@@ -142,10 +147,10 @@
     """Recursively call create_metainfo() in subdirs of rootdir
 
     Args:
-        rootdir: (string)  Top level directory containing the libraries
+        rootdir: (string)  Top level directory containing the libraries.
 
     Returns:
-        A list of metainfo dictionary (see create_metainfo())
+        A list of metainfo dictionary (see create_metainfo()).
 
     """
     metalist = []
@@ -165,22 +170,31 @@
 
 
 def sort_metainfo(metalist, all_maintainers):
-    products = []
+    """Extract the structure (Product/Subproduct/Library) from the metainfo
+    list.
+
+    Args:
+        metalist: (list of dict) lists of the metainfo extracted in
+    parse_tree().
+        all_maintainers: (dict of dict)  all possible maintainers.
+
+    Returns:
+        A list of Products, a list of groups (which are products containing
+    several libraries), a list of Libraries and the available platforms.
+    """
+    products = dict()
     groups = []
     libraries = []
     available_platforms = set(['Windows', 'MacOSX', 'Linux'])
 
-    all_groups = []
-    defined_groups = []
+    # First extract the structural info
     for metainfo in metalist:
-        if 'group' in metainfo:
-            all_groups.append(metainfo['group'])
-        if 'group_info' in metainfo:
-            defined_groups.append(metainfo['group'])
-    undefined_groups = [x for x in list(set(all_groups)) if x not in 
defined_groups]
+        product = extract_product(metainfo, all_maintainers)
+        if product is not None:
+            products[product.name] = product
 
+    # Second extract the libraries
     for metainfo in metalist:
-
         try:
             platforms = metainfo['platforms']
             platform_lst = [x['name'] for x in platforms
@@ -189,7 +203,7 @@
 
             available_platforms.update(set(platform_lst))
         except (KeyError, TypeError):
-            logging.warning('{} framework lacks valid platform definitions'
+            logging.warning('{} library lacks valid platform definitions'
                             .format(metainfo['fancyname']))
             platforms = [dict(name=PLATFORM_UNKNOWN)]
 
@@ -197,217 +211,33 @@
 
         expand_platform_all(dct, available_platforms)
         platforms = dct
-
-        lib = extract_lib(metainfo, platforms, all_maintainers)
+        lib = Library(metainfo, products, platforms, all_maintainers)
         libraries.append(lib)
 
-        product = extract_product(metainfo, platforms, all_maintainers, 
undefined_groups)
-        if product is not None:
-            products.append(product)
+    groups = [p for p in list(products.values()) if len(p.libraries) > 1]
 
-    # We have all groups and libraries, let set the parents.
-    # and check the platforms
-    for lib in libraries:
-        if lib['parent'].get('group') is not None:
-            product_list = [x for x in products if x['name'].lower() == 
lib['parent']['group'].lower()]
-            if not product_list:
-                continue  # The group_info was not defined
-            else:
-                product = product_list[0]
-            lib['product'] = product
-            if lib['mailinglist'] is None:
-                if product['mailinglist'] is not None:
-                    lib['mailinglist'] = product['mailinglist']
-                else:
-                    lib['mailinglist'] = 'kde-devel'
-            if lib['irc'] is None:
-                if product['irc'] is not None:
-                    lib['irc'] = product['irc']
-                else:
-                    lib['irc'] = 'kde-devel'
-
-            product['libraries'].append(lib)
-            if lib['parent'].get('subgroup') is None:
-                lib['subgroup'] = None
-            else:
-                subgroup_list = [x for x in lib['product']['subgroups'] if 
x['name'].lower() == lib['parent']['subgroup'].lower()]
-                if not subgroup_list:
-                    logging.warning("Subgroup {} of library {} not 
documentated, setting subgroup to None"
-                                    .format(lib['parent']['subgroup'], 
lib['name']))
-                    lib['subgroup'] = None
-                    lib['parent'] = product
-                else:
-                    subgroup = subgroup_list[0]
-                    lib['subgroup'] = subgroup
-                    subgroup['libraries'].append(lib)
-            groups.append(product)
-        else:
-            lib['parent'] = None
-
-    return products, groups, libraries, available_platforms
-
-
-def extract_lib(metainfo, platforms, all_maintainers):
-    def tolist(a):
-        if type(a) is list:
-            return a
-        else:
-            return [a]
-
-    outputdir = metainfo.get('name')
-    if 'group' in metainfo:
-        outputdir = metainfo.get('group') + '/' + outputdir
-    outputdir = utils.serialize_name(outputdir)
-    lib = {
-        'name': metainfo['name'],
-        'fancyname': metainfo['fancyname'],
-        'description': metainfo.get('description'),
-        'maintainers': set_maintainers(metainfo, 'maintainer', 
all_maintainers),
-        'platforms': platforms,
-        'parent': {'group': utils.serialize_name(metainfo.get('group')),
-                   'subgroup': utils.serialize_name(metainfo.get('subgroup'))},
-        'href': '../'+outputdir.lower() + '/html/index.html',
-        'outputdir': outputdir.lower(),
-        'path': metainfo['path'],
-        'srcdirs': tolist(metainfo.get('public_source_dirs', ['src'])),
-        'docdir': tolist(metainfo.get('public_doc_dir', ['docs'])),
-        'exampledir': tolist(metainfo.get('public_example_dir', ['examples'])),
-        'dependency_diagram': None,
-        'type': metainfo.get('type', ''),
-        'portingAid': metainfo.get('portingAid', False),
-        'deprecated': metainfo.get('deprecated', False),
-        'libraries': metainfo.get('libraries', []),
-        'cmakename': metainfo.get('cmakename', ''),
-        'irc': metainfo.get('irc'),
-        'mailinglist': metainfo.get('mailinglist'),
-        }
-
-    return lib
-
-
-def extract_product(metainfo, platforms, all_maintainers, undefined_groups):
-    def get_logo_url(dct, name):
-        # take care of the logo
-        if 'logo' in dct:
-            logo_url = os.path.join(metainfo['path'], dct['logo'])
-            if os.path.isfile(logo_url):
-                return logo_url
-            else:
-                logging.warning("{} logo file doesn't exist, set back to 
None".format(name))
-                return None
-        else:
-            return None
-
-    def set_logo(product):
-        if product['logo_url_src'] is not None:
-            filename = os.path.basename(product['logo_url_src'])
-            product['logo_url'] = outputdir + '/'+ product['name'] + '.' + 
filename.split('.')[-1]
-
-    # if there is a group, the product is the group
-    # else the product is directly the library
-    if 'group_info' in metainfo:
-        outputdir = utils.serialize_name(metainfo['group'])
-        product = {
-            'name': utils.serialize_name(metainfo['group']),
-            'fancyname': metainfo['group_info'].get('fancyname', 
string.capwords(metainfo['group'])),
-            'description': metainfo['group_info'].get('description'),
-            'long_description': metainfo['group_info'].get('long_description', 
[]),
-            'maintainers': set_maintainers(metainfo['group_info'],
-                                           'maintainer',
-                                           all_maintainers),
-            'platforms': metainfo['group_info'].get('platforms'),
-            'logo_url_src': get_logo_url(metainfo['group_info'],
-                                         metainfo['group']),
-            'logo_url': None,  # We'll set this later
-            'outputdir': outputdir,
-            'href': outputdir + '/index.html',
-            'libraries': [],  # We'll set this later
-            'subgroups': [],  # We'll set this later
-            'irc': metainfo['group_info'].get('irc'),
-            'mailinglist': metainfo['group_info'].get('mailinglist'),
-            }
-
-        if 'subgroups' in metainfo['group_info']:
-            for sg in metainfo['group_info']['subgroups']:
-                if 'name' in sg:
-                    product['subgroups'].append({
-                            'fancyname': sg['name'],
-                            'name': utils.serialize_name(sg['name']),
-                            'description': sg.get('description'),
-                            'order': sg.get('order', 99),  # If no order, go 
to end
-                            'libraries': []
-                            })
-        set_logo(product)
-        return product
-    elif 'group' in metainfo and metainfo['group'] in undefined_groups:
-        outputdir = utils.serialize_name(metainfo['group'])
-        product = {
-            'name': utils.serialize_name(metainfo['group']),
-            'fancyname': string.capwords(metainfo['group']),
-            'description': '',
-            'long_description': [],
-            'maintainers': set_maintainers(dict(),
-                                           'maintainer',
-                                           all_maintainers),
-            'platforms': None,
-            'logo_url_src': None,
-            'logo_url': None,  # We'll set this later
-            'outputdir': outputdir,
-            'href': outputdir + '/index.html',
-            'libraries': [],  # We'll set this later
-            'subgroups': [],  # We'll set this later
-            'irc': None,
-            'mailinglist': None,
-            }
-        return product
-    elif 'group' not in metainfo:
-        outputdir = metainfo['name']
+    return list(products.values()), groups, libraries, available_platforms
 
-        product = {
-            'name': utils.serialize_name(metainfo['name']),
-            'fancyname': metainfo['fancyname'],
-            'description': metainfo.get('description'),
-            'maintainers': set_maintainers(metainfo,
-                                          'maintainer',
-                                          all_maintainers),
-            'platforms': platforms,
-            'logo_url_src': get_logo_url(metainfo, metainfo['fancyname']),
-            'logo_url': None,  # We'll set that later
-            'href': outputdir + '/html/index.html',
-            'outputdir': outputdir
-            }
-        set_logo(product)
-        return product
-    else:
-        return None
 
-def set_maintainers(dictionary, key, maintainers):
-    """ Expend the name of the maintainers.
+def extract_product(metainfo, all_maintainers):
+    """Extract a product from a metainfo dictionary.
 
     Args:
-        dictonary: (dict) Dictionary from which the name to expend will be 
read.
-        key: (string) Key of the dictionary where the name to expend is saved.
-        maintainers: (list of dict) Look-up table where the names and emails of
-    the maintainers are stored.
-
-    Examples:
-
-        metainfo = { 'key1': 'something', 'maintainers': ['arthur', 'toto']}
-        myteam = [{'arthur': {'name': 'Arthur Pendragon',
-                              'email': 'art...@example.com'},
-                   'toto': {'name': 'Toto',
-                            'email: 'toto...@example.com'}
-                    }]
-        set_maintainers(metainfo, "maintainers", my_team)
+        metainfo: (dict) metainfo created by the create_metainfo() function.
+        all_maintainer: (dict of dict) all possible maintainers
+
+    Returns:
+        A Product or None if the metainfo does not describe a product.
     """
 
-    if key not in dictionary:
-        fw_maintainers = []
-    elif isinstance(dictionary[key], list):
-        fw_maintainers = map(lambda x: maintainers.get(x, None),
-                             dictionary[key])
-    else:
-        fw_maintainers = [maintainers.get(dictionary[key], None)]
+    if 'group_info' not in metainfo and 'group' in metainfo:
+        # This is not a product but a simple lib
+        return None
 
-    fw_maintainers = [x for x in fw_maintainers if x is not None]
-    return fw_maintainers
+    try:
+        product = Product(metainfo, all_maintainers)
+    except ValueError as e:
+        logging.error(e)
+        product = None
+    finally:
+        return product
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/src/kapidox/utils.py 
new/kapidox-5.25.0/src/kapidox/utils.py
--- old/kapidox-5.24.0/src/kapidox/utils.py     2016-06-20 15:51:32.000000000 
+0200
+++ new/kapidox-5.25.0/src/kapidox/utils.py     2016-08-06 01:24:22.000000000 
+0200
@@ -36,29 +36,74 @@
 import sys
 import tempfile
 
-"""
-This module contains code which is shared between depdiagram-prepare and other
-components.
-
-Code in this dir should not import any module which is not shipped with Python
-because this module is used by depdiagram-prepare, which must be able to run
-on builds.kde.org, which may not have all the required dependencies.
-"""
+## @package kapidox.utils
+#
+# Multiple usage utils.
+#
+# This module contains code which is shared between depdiagram-prepare and
+# other components.
+#
+# Code in this dir should not import any module which is not shipped with
+# Python because this module is used by depdiagram-prepare, which must be able
+# to run on builds.kde.org, which may not have all the required dependencies.
+#
 
 def setup_logging():
     FORMAT = '%(asctime)s %(levelname)s %(message)s'
     logging.basicConfig(format=FORMAT, datefmt='%H:%M:%S', level=logging.DEBUG)
 
 
+def tolist(a):
+    """ Return a list based on `a`. """
+    return a if type(a) is list else [a]
+
+
 def serialize_name(name):
+    """ Return a serialized name.
+
+    For now it only replaces ' ' with '_' and lower the letters.
+    """
     if name is not None:
         return '_'.join(name.lower().split(' '))
     else:
         return None
 
 
+def set_maintainers(maintainer_keys, all_maintainers):
+    """ Expend the name of the maintainers.
+
+    Args:
+        dictonary: (dict) Dictionary from which the name to expend will be 
read.
+        key: (string) Key of the dictionary where the name to expend is saved.
+        all_maintainers: (dict of dict) Look-up table where the names and 
emails of
+    the maintainers are stored.
+
+    Examples:
+        >>> maintainer_keys = ['arthur', 'toto']
+
+        >>> myteam = {'arthur': {'name': 'Arthur Pendragon',
+                                 'email': 'art...@example.com'},
+                      'toto': {'name': 'Toto',
+                               'email: 'toto...@example.com'}
+                      }
+
+        >>> set_maintainers(maintainer_keys, my_team)
+    """
+
+    if not maintainer_keys:
+        maintainers = []
+    elif isinstance(maintainer_keys, list):
+        maintainers = map(lambda x: all_maintainers.get(x, None),
+                             maintainer_keys)
+    else:
+        maintainers = [all_maintainers.get(maintainer_keys, None)]
+
+    maintainers = [x for x in maintainers if x is not None]
+    return maintainers
+
+
 def parse_fancyname(fw_dir):
-    """Returns the framework name for a given source dir
+    """Return the framework name for a given source dir
 
     The framework name is the name of the toplevel CMake project
     """
@@ -66,7 +111,7 @@
     if not os.path.exists(cmakelists_path):
         logging.error("No CMakeLists.txt in {}".format(fw_dir))
         return None
-    project_re = re.compile(r"project\s*\(\s*(\w+)", re.I)
+    project_re = re.compile(r"project\s*\(\s*([\w\-\_]+)", re.I)
     with open(cmakelists_path) as f:
         for line in f.readlines():
             match = project_re.search(line)
@@ -112,7 +157,18 @@
 def svn_export(remote, local, overwrite=False):
     """Wraps svn export.
 
-    Raises an exception on failure.
+    Args:
+        remote:     (string) the remote url.
+        local:      (string) the local path where to dowload.
+        overwrite:  (bool) whether to overwrite `local` or not. (optional,
+    default = False)
+
+    Returns:
+        True if success.
+
+    Raises:
+        FileNotFoundError: &nbsp;
+        subprocess.CalledProcessError: &nbsp;
     """
     try:
         import svn.core
@@ -134,7 +190,7 @@
         try:
             subprocess.check_call(cmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise StandardException(e.output)
+            raise subprocess.StandardException(e.output)
         except FileNotFoundError as e:
             logging.debug("External svn client not found")
             return False
@@ -146,8 +202,9 @@
 def copy_dir_contents(directory, dest):
     """Copy the contents of a directory
 
-    directory -- the directory to copy the contents of
-    dest      -- the directory to copy them into
+    Args:
+        directory: (string) the directory to copy the contents of.
+        dest: (string) the directory to copy them into.
     """
     ignored = ['CMakeLists.txt']
     ignore = shutil.ignore_patterns(*ignored)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-5.24.0/src/kapidox_generate 
new/kapidox-5.25.0/src/kapidox_generate
--- old/kapidox-5.24.0/src/kapidox_generate     2016-06-20 15:51:32.000000000 
+0200
+++ new/kapidox-5.25.0/src/kapidox_generate     2016-08-06 01:24:22.000000000 
+0200
@@ -1,10 +1,10 @@
 #! /usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-# Copyright 2016  Olivier Churlaud <oliv...@churlaud.com>
 # Copyright 2014  Alex Merry <alex.me...@kdemail.net>
 # Copyright 2014  Aurélien Gâteau <agat...@kde.org>
 # Copyright 2014  Alex Turbov <i.za...@gmail.com>
+# Copyright 2016  Olivier Churlaud <oliv...@churlaud.com>
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -37,14 +37,14 @@
 import sys
 import tempfile
 import time
+import datetime
 
 if sys.version_info.major < 3:
     from urllib import urlretrieve
 else:
     from urllib.request import urlretrieve
 
-import kapidox as kdx
-from kapidox import generator
+from kapidox import generator, utils, argparserutils, preprocessing
 
 try:
     from kapidox import depdiagram
@@ -65,7 +65,7 @@
     """Download the "accounts" file on the KDE SVN repository in order to get
        the KDE identities with their name and e-mail address
     """
-    cache_file = os.path.join(kdx.utils.cache_dir(), 'kde-accounts')
+    cache_file = os.path.join(utils.cache_dir(), 'kde-accounts')
     needs_download = True
     if os.path.exists(cache_file):
         logging.debug("Found cached identities file at %s", cache_file)
@@ -79,7 +79,7 @@
     if needs_download:
         logging.info("Downloading KDE identities")
         try:
-            if not kdx.utils.svn_export(
+            if not utils.svn_export(
                     'svn://anonsvn.kde.org/home/kde/trunk/kde-common/accounts',
                     cache_file,
                     overwrite=True):
@@ -109,8 +109,9 @@
 
 
 def main():
-    kdx.utils.setup_logging()
-    args = kdx.argparserutils.parse_args(DEPDIAGRAM_AVAILABLE)
+    kde_copyright = '1996-' + str(datetime.date.today().year) + ' The KDE 
developers'
+    utils.setup_logging()
+    args = argparserutils.parse_args(DEPDIAGRAM_AVAILABLE)
 
     tagfiles = generator.search_for_tagfiles(
         suggestion=args.qtdoc_dir,
@@ -119,10 +120,10 @@
         searchpaths=['/usr/share/doc/qt5', '/usr/share/doc/qt'])
 
     maintainers = download_kde_identities()
-    rootdir = args.frameworksdir
+    rootdir = args.sourcesdir
 
-    metalist = kdx.preprocessing.parse_tree(rootdir)
-    products, groups, libraries, available_platforms = 
kdx.preprocessing.sort_metainfo(metalist, maintainers)
+    metalist = preprocessing.parse_tree(rootdir)
+    products, groups, libraries, available_platforms = 
preprocessing.sort_metainfo(metalist, maintainers)
 
     dirsrc = os.path.join(args.doxdatadir, 'htmlresource')
     dirdest = 'resources'
@@ -131,13 +132,13 @@
     shutil.copytree(dirsrc, dirdest)
     os.rename(dirdest+'/favicon.ico', './favicon.ico')
 
-    kdx.generator.process_toplevel_html_file('index.html',
+    generator.process_toplevel_html_file('index.html',
                                args.doxdatadir,
                                title=args.title,
                                products=products,
                                api_searchbox=args.api_searchbox
                                )
-    kdx.generator.process_subgroup_html_files('index.html',
+    generator.process_subgroup_html_files('index.html',
                                 args.doxdatadir,
                                 title=args.title,
                                 groups=groups,
@@ -152,34 +153,34 @@
             assert(dot_files)
 
         for lib in libraries:
-            logging.info('# Generating doc for {}'.format(lib['fancyname']))
+            logging.info('# Generating doc for {}'.format(lib.fancyname))
             if args.depdiagram_dot_dir:
-                png_path = os.path.join(tmp_dir, lib['name']) + '.png'
-                ok = kdx.generator.generate_diagram(png_path, lib['fancyname'],
+                png_path = os.path.join(tmp_dir, lib.name) + '.png'
+                ok = generator.generate_diagram(png_path, lib.fancyname,
                                       dot_files, tmp_dir)
                 if ok:
-                    lib['dependency_diagram'] = png_path
-            ctx = kdx.generator.create_fw_context(args, lib, tagfiles)
-            kdx.generator.gen_fw_apidocs(ctx, tmp_dir)
-            tagfiles.append(kdx.generator.create_fw_tagfile_tuple(lib))
+                    lib.dependency_diagram = png_path
+            ctx = generator.create_fw_context(args, lib, tagfiles)
+            generator.gen_fw_apidocs(ctx, tmp_dir)
+            tagfiles.append(generator.create_fw_tagfile_tuple(lib))
 
         # Rebuild for interdependencies
         # FIXME: can we be cleverer about deps?
         for lib in libraries:
             logging.info('# Rebuilding {} for interdependencies'
-                         .format(lib['name']))
-            shutil.rmtree(lib['outputdir'])
-            ctx = kdx.generator.create_fw_context(args, lib, tagfiles)
-            kdx.generator.gen_fw_apidocs(ctx, tmp_dir)
-            kdx.generator.finish_fw_apidocs(ctx, None)
+                         .format(lib.fancyname))
+            shutil.rmtree(lib.outputdir)
+            ctx = generator.create_fw_context(args, lib, tagfiles, 
kde_copyright)
+            generator.gen_fw_apidocs(ctx, tmp_dir)
+            generator.finish_fw_apidocs(ctx, None)
         logging.info('# Done')
     finally:
         for product in products:
-            if product['logo_url'] is not None:
-                logodir = os.path.dirname(product['logo_url'])
+            if product.logo_url is not None:
+                logodir = os.path.dirname(product.logo_url)
                 if not os.path.isdir(logodir):
                     os.mkdir(logodir)
-                shutil.copy(product['logo_url_src'], product['logo_url'])
+                shutil.copy(product.logo_url_src, product.logo_url)
 
         if args.keep_temp_dirs:
             logging.info('Kept temp dir at {}'.format(tmp_dir))


Reply via email to