Hello community,

here is the log from the commit of package kapidox for openSUSE:Factory checked 
in at 2014-03-10 12:18:17
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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  2014-02-24 
06:53:54.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.kapidox.new/kapidox.changes     2014-03-10 
12:18:18.000000000 +0100
@@ -1,0 +2,8 @@
+Tue Mar  4 16:39:09 UTC 2014 - hrvoje.sen...@gmail.com
+
+- Update to 4.97.0:
+  * Buildsystem fixes
+  * For more details please see:
+    http://www.kde.org/announcements/announce-frameworks5-alpha2.php
+
+-------------------------------------------------------------------

Old:
----
  kapidox-4.96.0.tar.xz

New:
----
  kapidox-4.97.0.tar.xz

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

Other differences:
------------------
++++++ kapidox.spec ++++++
--- /var/tmp/diff_new_pack.50ZuTS/_old  2014-03-10 12:18:19.000000000 +0100
+++ /var/tmp/diff_new_pack.50ZuTS/_new  2014-03-10 12:18:19.000000000 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           kapidox
-Version:        4.96.0
+Version:        4.97.0
 Release:        0
 Requires:       doxygen
 BuildRequires:  fdupes

++++++ kapidox-4.96.0.tar.xz -> kapidox-4.97.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/CMakeLists.txt 
new/kapidox-4.97.0/CMakeLists.txt
--- old/kapidox-4.96.0/CMakeLists.txt   2014-02-05 17:07:44.000000000 +0100
+++ new/kapidox-4.97.0/CMakeLists.txt   2014-02-27 11:48:02.000000000 +0100
@@ -22,6 +22,6 @@
      endif()
      execute_process(
         COMMAND ${PYTHON_EXECUTABLE} setup.py install --prefix 
${CMAKE_INSTALL_PREFIX} \${_root_arg}
-        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+        WORKING_DIRECTORY \"${CMAKE_SOURCE_DIR}\"
         )"
     )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/README.md new/kapidox-4.97.0/README.md
--- old/kapidox-4.96.0/README.md        2014-02-05 17:07:44.000000000 +0100
+++ new/kapidox-4.97.0/README.md        2014-02-27 11:48:02.000000000 +0100
@@ -15,12 +15,16 @@
 ## Dependencies
 
 Python 2 or 3 is required to run the scripts.  Whichever version of python you
-use needs to have the pystache and yaml (or pyyaml) modules.  To generate the
-dependency diagrams, you need the yapgvb module.
+use needs to have the pystache and yaml (or pyyaml) modules.
 
 The following command should install them for the current user:
 
-    pip install --user PyYAML pystache yapgvb
+    pip install --user PyYAML pystache
+
+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
@@ -87,73 +91,23 @@
 the frameworks-apidocs directory.  This will be about 500Mb in size, so make
 sure you have enough space!
 
+You can ask `kgenframeworksapidox` to generate dependency diagrams for all the
+frameworks.  To do so, you must first generate Graphviz .dot files for all
+frameworks with the `depdiagram-prepare` tool, like this:
 
-### Dependency diagrams
-
-Kapidox can also generate dependency diagrams for the frameworks.  This is done
-using two tools: `src/depdiagram-prepare` and `src/depdiagram-generate`.  The
-way you use it is as follow.
-
-First you need to prepare Graphviz dot files for all frameworks with
-`src/depdiagram-prepare`:
-
-    depdiagram-prepare ~/src/frameworks ~/dots
-
-This will generate many .dot files in ~/dots.
-
-Then you can generate the dependency diagrams with `src/depdiagram-generate`.
-This tool accepts a list of dot files and output a combined dot file to stdout.
-
-Here is how to generate a dependency diagram for all the frameworks:
-
-    depdiagram-generate ~/dots/tier*/*/*.dot | dot -Tpng > kf5.png
-
-The diagram might be very hard to read though, so for complex diagrams, you may
-want to pipe the output through the `tred` tool:
-
-    depdiagram-generate ~/dots/tier*/*/*.dot | tred | dot -Tpng > kf5.png
-
-You can also generate the diagram for one particular framework using the
-"--framework" option:
-
-    depdiagram-generate ~/dots/tier*/*/*.dot --framework kcrash | tred | dot 
-Tpng > kcrash.png
-
-To include Qt libs, use the "--qt" option:
-
-    depdiagram-generate ~/dots/tier*/*/*.dot --framework kcrash --qt | tred | 
dot -Tpng > kcrash.png
 
-And to include targets within the framework, use the "--detailed" option:
+    mkdir dot
+    ~/src/frameworks/kapidox/src/depdiagram-prepare --all ~/src/frameworks dot
 
-    depdiagram-generate ~/dots/tier*/*/*.dot --framework kcrash --detailed | 
tred | dot -Tpng > kcrash.png
+Then call `kgenframeworksapidox` with the `--depdiagram-dot-dir` option, like
+this:
 
+    mkdir frameworks-apidocs
+    cd frameworks-apidocs
+    ~/src/frameworks/kapidox/src/kgenframeworksapidox --depdiagram-dot-dir 
../dot ~/src/frameworks
 
-#### Useful tools
-
-`tred`, mentioned in Usage, reduces clutter in dot files.
-
-`xdot`, can be used instead of `dot` to display the graph:
-
-    depdiagram-generate ~/dots/tier*/*/*.dot --framework kcrash --qt | tred | 
xdot
-
-
-#### Generating all diagrams at once
-
-You can use the depdiagram-generate-all tool to generate diagrams for all
-frameworks at once:
-
-    depdiagram-generate-all ~/dots ~/pngs
-
-This command creates two pngs for each framework: "$framework.png" and
-"$framework-simplified.png" (same diagram, ran through tred). It also creates a
-diagram for all of the frameworks, named "kf5.png".
-
-
-#### Integration with kgenapidox
-
-Once you have generated dependency diagrams, you can run kgenapidox with the
-"--dependency-diagram-dir" option pointing to the dir containing the diagrams.
-When this option is set, kgenapidox creates a "Dependencies" page, accessible
-from the documentation sidebar. This page includes the framework diagram.
+More fine-grained tools are available for dependency diagrams. You can learn
+about them in [depdiagrams](depdiagrams.html).
 
 
 ## Links
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/docs/depdiagrams.md 
new/kapidox-4.97.0/docs/depdiagrams.md
--- old/kapidox-4.96.0/docs/depdiagrams.md      1970-01-01 01:00:00.000000000 
+0100
+++ new/kapidox-4.97.0/docs/depdiagrams.md      2014-02-27 11:48:02.000000000 
+0100
@@ -0,0 +1,84 @@
+Dependency diagrams {#depdiagrams}
+===================
+
+## Introduction
+
+In most case, you just want to call `kgenframeworksapidox` with the
+"--dependency-diagrams" option. However, if you want finer-grained control over
+diagram generation or want to work on its code, read on.
+
+## depdiagram tools
+
+Dependency diagram generation is done using two tools: `src/depdiagram-prepare`
+and `src/depdiagram-generate`.  The way you use it is as follow.
+
+### 1. Prepare dot files
+
+You need to prepare Graphviz dot files for all frameworks with
+`src/depdiagram-prepare`. You can prepare dot files for all frameworks at once
+using:
+
+    depdiagram-prepare --all ~/src/frameworks ~/dots
+
+This will generate many .dot files in ~/dots.
+
+Or you can prepare dot files for a single framework with:
+
+    depdiagram-prepare --single ~/src/frameworks/myframework ~/dots
+
+### 2. Generate the diagrams
+
+You can now generate the dependency diagrams with `src/depdiagram-generate`.
+This tool accepts a list of dot files and output a combined dot file to stdout.
+
+Here is how to generate a dependency diagram for all the frameworks:
+
+    depdiagram-generate ~/dots/*.dot | dot -Tpng > kf5.png
+
+The diagram might be very hard to read though. For complex diagrams, you may
+want to pipe the output through the `tred` tool:
+
+    depdiagram-generate ~/dots/*.dot | tred | dot -Tpng > kf5.png
+
+You can also generate the diagram for one particular framework using the
+"--framework" option:
+
+    depdiagram-generate ~/dots/*.dot --framework kcrash | tred | dot -Tpng > 
kcrash.png
+
+To include Qt libs, use the "--qt" option:
+
+    depdiagram-generate ~/dots/tier*/*/*.dot --framework kcrash --qt | tred | 
dot -Tpng > kcrash.png
+
+And to include targets within the framework, use the "--detailed" option:
+
+    depdiagram-generate ~/dots/*.dot --framework kcrash --detailed | tred | 
dot -Tpng > kcrash.png
+
+
+## Useful 3rd-party tools
+
+`tred`, mentioned in the previous section, reduces clutter in dot files.
+
+`xdot` can be used instead of `dot` to display the graph:
+
+    depdiagram-generate ~/dots/*.dot --framework kcrash --qt | tred | xdot
+
+
+## Generating all diagrams at once
+
+You can use the `depdiagram-generate-all` tool to generate diagrams for all
+frameworks at once:
+
+    depdiagram-generate-all ~/dots ~/pngs
+
+This command creates two pngs for each framework: "$framework.png" and
+"$framework-simplified.png" (same diagram, ran through `tred`). It also 
creates a
+diagram for all of the frameworks, named "kf5.png".
+
+
+## Integration with kgenapidox
+
+Once you have generated dependency diagrams, you can run kgenapidox with the
+"--dependency-diagram-dir" option pointing to the dir containing the diagrams.
+When this option is set, kgenapidox creates a "Dependencies" page, accessible
+from the documentation sidebar. This page includes the framework diagram.
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/src/depdiagram-generate 
new/kapidox-4.97.0/src/depdiagram-generate
--- old/kapidox-4.96.0/src/depdiagram-generate  2014-02-05 17:07:44.000000000 
+0100
+++ new/kapidox-4.97.0/src/depdiagram-generate  2014-02-27 11:48:02.000000000 
+0100
@@ -24,135 +24,13 @@
 # (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 argparse
-import itertools
 import sys
 
-
-from kapidox.depdiagram.block import Block, quote
-from kapidox.depdiagram.framework import Framework
-from kapidox.depdiagram.frameworkdb import FrameworkDb
+from kapidox import depdiagram
 
 DESCRIPTION = """\
 """
 
-ROOT_NODE_ATTRS = dict(fontsize=12, shape="box")
-
-GROUP_ATTRS = dict(style="filled", fillcolor="grey95", color="grey85")
-
-# Blocks within groups
-OTHER_ATTRS = dict(style="filled", fillcolor="cornsilk", color="black")
-
-QT_ATTRS = dict(style="filled", fillcolor="darkseagreen1", color="black")
-
-FW_ATTRS = dict(style="filled", fillcolor="azure", color="black")
-
-# Target blocks, used with --detailed
-FW_TARGET_ATTRS = dict(style="filled", fillcolor="paleturquoise")
-
-# Highlight the wanted framework, used with --framework
-WANTED_FW_ATTRS = dict(penwidth=2)
-
-class FrameworkCmp(object):
-    def __init__(self, db):
-        self.db = db
-        self.src = set(db)
-        self.dst = []
-
-    def __call__(self, fw1, fw2):
-        if self.depends_on(fw1, fw2):
-            return 1
-        if self.depends_on(fw2, fw1):
-            return -1
-        return 0
-
-    def depends_on(self, depender_fw, provider_fw):
-        for dep_target in depender_fw.get_all_target_dependencies():
-            if provider_fw.has_target(dep_target):
-                return True
-
-            try:
-                dep_fw = self.db.get_framework_for_target(dep_target)
-            except KeyError:
-                # No framework for this target, must be an external dependency,
-                # carry on
-                continue
-            if dep_fw != depender_fw and self.depends_on(dep_fw, provider_fw):
-                return True
-
-        return False
-
-
-class DotWriter(Block):
-    def __init__(self, db, out, wanted_fw=None, detailed=False):
-        Block.__init__(self, out)
-        self.db = db
-        self.detailed = detailed
-        self.wanted_fw = wanted_fw
-
-    def write(self):
-        with self.curly_block("digraph Root") as root:
-            root.write_list_attrs("node", **ROOT_NODE_ATTRS)
-
-            other_targets = self.db.find_external_targets()
-            qt_targets = set([x for x in other_targets if x.startswith("Qt")])
-            other_targets.difference_update(qt_targets)
-
-            if qt_targets:
-                with root.cluster_block("Qt", **GROUP_ATTRS) as b:
-                    b.write_list_attrs("node", **QT_ATTRS)
-                    b.write_nodes(qt_targets)
-
-            if other_targets:
-                with root.cluster_block("Others", **GROUP_ATTRS) as b:
-                    b.write_list_attrs("node", **OTHER_ATTRS)
-                    b.write_nodes(other_targets)
-
-            lst = sorted([x for x in self.db], key=lambda x: x.tier)
-            for tier, frameworks in itertools.groupby(lst, lambda x: x.tier):
-                with root.cluster_block(tier, **GROUP_ATTRS) as tier_block:
-                    tier_block.write_list_attrs("node", **FW_ATTRS)
-                    # Sort frameworks within the tier to ensure frameworks 
which
-                    # depend on other frameworks from that tier are listed 
after
-                    # their dependees.
-                    frameworks = list(frameworks)
-                    for fw in sorted(frameworks, cmp=FrameworkCmp(self.db)):
-                        if self.detailed:
-                            self.write_detailed_framework(tier_block, fw)
-                        else:
-                            self.write_framework(tier_block, fw)
-
-    def write_framework(self, tier_block, fw):
-        if fw == self.wanted_fw:
-            tier_block.write_list_attrs(quote(fw.name), **WANTED_FW_ATTRS)
-        else:
-            tier_block.write_nodes([fw.name])
-        edges = set([])
-        for target in fw.get_all_target_dependencies():
-            try:
-                target_fw = self.db.get_framework_for_target(target)
-                if fw == target_fw:
-                    continue
-                dep = target_fw.name
-            except KeyError:
-                dep = target
-            edges.add((fw.name, dep))
-        for dep_fw in fw.get_extra_frameworks():
-            edges.add((fw.name, dep_fw))
-        for edge in edges:
-            tier_block.writeln('"{}" -> "{}";'.format(*edge))
-
-    def write_detailed_framework(self, tier_block, fw):
-        with tier_block.cluster_block(fw.name, **FW_ATTRS) as fw_block:
-            if fw == self.wanted_fw:
-                fw_block.write_attrs(**WANTED_FW_ATTRS)
-            fw_block.write_list_attrs("node", **FW_TARGET_ATTRS)
-            targets = sorted(fw.get_targets())
-            fw_block.write_nodes(targets)
-            for target in targets:
-                deps = fw.get_dependencies_for_target(target)
-                for dep in sorted(deps):
-                    fw_block.writeln('"{}" -> "{}";'.format(target, dep))
-
 
 def main():
     parser = argparse.ArgumentParser(description=DESCRIPTION)
@@ -173,29 +51,17 @@
 
     args = parser.parse_args()
 
-    db = FrameworkDb()
-    db.populate(args.dot_files, with_qt=args.qt)
-
     if args.output == "-":
         out = sys.stdout
     else:
         out = open(args.output, "w")
 
-    if args.framework:
-        wanted_fw = db.find_by_name(args.framework)
-        if wanted_fw is None:
-            sys.stderr.write("No framework named {}.\n".format(args.framework))
-            return 1
-        db.remove_unused_frameworks(wanted_fw)
+    if depdiagram.generate(out, args.dot_files, framework=args.framework, 
with_qt=args.qt, detailed=args.detailed):
+        return 0
     else:
-        wanted_fw = None
-
-    writer = DotWriter(db, out, wanted_fw=wanted_fw, detailed=args.detailed)
-    writer.write()
-
-    return 0
-
+        return 1
 
 if __name__ == "__main__":
     sys.exit(main())
+
 # vi: ts=4 sw=4 et
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/src/depdiagram-generate-all 
new/kapidox-4.97.0/src/depdiagram-generate-all
--- old/kapidox-4.96.0/src/depdiagram-generate-all      2014-02-05 
17:07:44.000000000 +0100
+++ new/kapidox-4.97.0/src/depdiagram-generate-all      2014-02-27 
11:48:02.000000000 +0100
@@ -48,32 +48,34 @@
     die "'$dot_dir' is not a directory"
 fi
 
+read_tier() {
+    sed --quiet '/tier:/s/tier: *//p' $1
+}
+
 gen_fws() {
     tier=$1
-    qt=$2
-    if [ -n "$qt" ] ; then
-        opts=--qt
-    else
-        opts=""
-    fi
 
-    for fw_dir in $dot_dir/$tier/*/ ; do
-        fw=$(basename $fw_dir)
+    for fw_dot in $dot_dir/*.dot ; do
+        fw=$(basename $fw_dot .dot)
+        tier=$(read_tier $dot_dir/$fw.yaml)
+        echo "# $fw tier=$tier"
+        if [ $tier -lt 3 ] ; then
+            opts=--qt
+        else
+            opts=""
+        fi
         png=$png_dir/$fw.png
         echo $png
-        $generate $dot_dir/tier*/*/*.dot --framework $fw $opts | dot -Tpng > 
$png
+        $generate $dot_dir/*.dot --framework $fw $opts | dot -Tpng > $png
         png=$png_dir/$fw-simplified.png
         echo $png
-        $generate $dot_dir/tier*/*/*.dot --framework $fw $opts | tred | dot 
-Tpng > $png
+        $generate $dot_dir/*.dot --framework $fw $opts | tred | dot -Tpng > 
$png
     done
 }
 
 mkdir -p $png_dir
 
-gen_fws tier1 1
-gen_fws tier2 1
-gen_fws tier3
-gen_fws tier4
+gen_fws
 
 echo "kf5.png"
-$generate $dot_dir/tier*/*/*.dot | tred | dot -Tpng > $png_dir/kf5.png
+$generate $dot_dir/*.dot | tred | dot -Tpng > $png_dir/kf5.png
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/src/depdiagram-prepare 
new/kapidox-4.97.0/src/depdiagram-prepare
--- old/kapidox-4.96.0/src/depdiagram-prepare   2014-02-05 17:07:44.000000000 
+0100
+++ new/kapidox-4.97.0/src/depdiagram-prepare   2014-02-27 11:48:02.000000000 
+0100
@@ -23,60 +23,131 @@
 # 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.
+
+# Python 2/3 compatibility (NB: we require at least 2.7)
+from __future__ import division, absolute_import, print_function, 
unicode_literals
+
 import argparse
 import os
 import shutil
 import subprocess
 import sys
-
-import yaml
+import tempfile
 
 DESCRIPTION = """
-Generate Graphviz dot files for all frameworks.
+Generate Graphviz dot files for one or all frameworks.
 """
 
-fnull = open("/dev/null", "w")
+def err(msg):
+    print("ERROR:", msg, file=sys.stderr)
+
+
+def generate_dot(fw_dir, fw_name, output_dir):
+    """Calls cmake to generate the dot file for a framework.
+
+    Returns true on success, false on failure"""
+    dot_path = os.path.join(output_dir, fw_name + ".dot")
+    build_dir = tempfile.mkdtemp(prefix="depdiagram-prepare-build-")
+    try:
+        ret = subprocess.call(["cmake", fw_dir, 
"--graphviz={}".format(dot_path)],
+            stdout=open("/dev/null", "w"),
+            cwd=build_dir)
+        if ret != 0:
+            if os.path.exists(dot_path):
+                os.remove(dot_path)
+            err("Generating dot file for {} failed.".format(fw_name))
+            return False
+    finally:
+        shutil.rmtree(build_dir)
+    return True
+
+
+def find_fw_name(fw_dir):
+    """Returns the framework name for a give source dir
+
+    We can't always assume the framework dir is the name of the framework so
+    instead we use the name of the .yaml file (assuming there is no other .yaml
+    file in fw_dir)
+    """
+    for name in os.listdir(fw_dir):
+        root, ext = os.path.splitext(name)
+        if ext == ".yaml":
+            return root
+    err("Failed to find framework name: Could not find a .yaml file in 
{}.".format(fw_dir))
+    return None
+
+
+def prepare_one(fw_dir, output_dir):
+    fw_name = find_fw_name(fw_dir)
+    if fw_name is None:
+        return False
+
+    yaml_path = os.path.join(fw_dir, fw_name + ".yaml")
+    if not os.path.exists(yaml_path):
+        err("'{}' is not a framework: '{}' does not exist.".format(fw_dir, 
yaml_path))
+        return False
+
+    if not os.path.exists(output_dir):
+        os.makedirs(output_dir)
+
+    if not generate_dot(fw_dir, fw_name, output_dir):
+        return False
+    shutil.copy(yaml_path, output_dir)
+    return True
+
+
+def prepare_all(fw_base_dir, dot_dir):
+    """Generate dot files for all frameworks.
+
+    Looks for frameworks in `fw_base_dir`. Output the dot files in sub dirs of
+    `dot_dir`.
+    """
+    lst = os.listdir(fw_base_dir)
+    fails = []
+    for idx, fw_name in enumerate(lst):
+        fw_dir = os.path.join(fw_base_dir, fw_name)
+        if not os.path.isdir(fw_dir):
+            continue
+
+        progress = int(100 * (idx + 1) / len(lst))
+        print("{}% {}".format(progress, fw_name))
+        if not prepare_one(fw_dir, dot_dir):
+            fails.append(fw_name)
+    return fails
 
-def generate_dot(fw_dir, build_dir):
-    fw_name = os.path.basename(fw_dir)
-    ret = subprocess.call(["cmake", fw_dir, 
"--graphviz={}.dot".format(fw_name)],
-        stdout=fnull,
-        cwd=build_dir)
-    if ret != 0:
-        sys.stdout.write("Generating the dot file for {} 
failed.\n".format(fw_name))
-        sys.exit(ret)
 
 def main():
     parser = argparse.ArgumentParser(description=DESCRIPTION)
 
-    parser.add_argument("fw_base_dir",
-        help="Base dir containing all frameworks")
-    parser.add_argument("dot_base_dir",
+    group = parser.add_mutually_exclusive_group(required=True)
+    group.add_argument("-s", "--single",
+        help="Generate dot files for the framework stored in DIR",
+        metavar="DIR")
+    group.add_argument("-a", "--all",
+        help="Generate dot files for all frameworks whose dir is in BASE_DIR",
+        metavar="BASE_DIR")
+    parser.add_argument("dot_dir",
         help="Destination dir where dot files will be generated")
 
     args = parser.parse_args()
-    fw_base_dir = os.path.abspath(args.fw_base_dir)
-    dot_base_dir = os.path.abspath(args.dot_base_dir)
 
-    lst = os.listdir(fw_base_dir)
-    for idx, fw_name in enumerate(lst):
-        fw_dir = os.path.join(fw_base_dir, fw_name)
-        yaml_path = os.path.join(fw_dir, fw_name + ".yaml")
-        if not os.path.exists(yaml_path):
-            continue
+    dot_dir = os.path.abspath(args.dot_dir)
 
-        progress = 100 * (idx + 1) / len(lst)
-        print("{}% {}".format(progress, fw_name))
+    if args.single:
+        fw_dir = os.path.abspath(args.single)
+        if prepare_one(fw_dir, dot_dir):
+            return 0
+        else:
+            return 1
+    else:
+        fw_base_dir = os.path.abspath(args.all)
+        fails = prepare_all(fw_base_dir, dot_dir)
+        if fails:
+            err("{} framework(s) failed: {}".format(len(fails), ", 
".join(fails)))
+            return 1
+        else:
+            return 0
 
-        with open(yaml_path) as f:
-            fw_info = yaml.load(f)
-            tier = fw_info["tier"]
-
-        build_dir = os.path.join(dot_base_dir, "tier" + str(tier), fw_name)
-        if not os.path.exists(build_dir):
-            os.makedirs(build_dir)
-        generate_dot(fw_dir, build_dir)
-        shutil.copy(yaml_path, build_dir)
 
 if __name__ == "__main__":
     sys.exit(main())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/src/kapidox/__init__.py 
new/kapidox-4.97.0/src/kapidox/__init__.py
--- old/kapidox-4.96.0/src/kapidox/__init__.py  2014-02-05 17:07:44.000000000 
+0100
+++ new/kapidox-4.97.0/src/kapidox/__init__.py  2014-02-27 11:48:02.000000000 
+0100
@@ -43,9 +43,10 @@
 except ImportError:
     from urlparse import urljoin
 
+import pystache
+
 from .doxyfilewriter import DoxyfileWriter
 
-DEPENDENCY_DIAGRAM_PAGE = 'dependencies'
 
 def smartjoin(pathorurl1,*args):
     """Join paths or URLS
@@ -244,7 +245,7 @@
         print("The module does not provide a README.md file")
         return default
 
-def menu_items(htmldir):
+def menu_items(htmldir, modulename):
     """Menu items for standard Doxygen files
 
     Looks for a set of standard Doxygen files (like namespaces.html) and
@@ -266,7 +267,7 @@
             {'text': 'File Members', 'href': 'globals.html'},
             {'text': 'Modules', 'href': 'modules.html'},
             {'text': 'Directories', 'href': 'dirs.html'},
-            {'text': 'Dependencies', 'href': DEPENDENCY_DIAGRAM_PAGE + 
'.html'},
+            {'text': 'Dependencies', 'href': modulename + 
'-dependencies.html'},
             {'text': 'Related Pages', 'href': 'pages.html'},
             ]
     # NOTE In Python 3 filter() builtin returns an iterable, but not a list
@@ -283,7 +284,6 @@
     htmldir -- the directory containing the .html files
     mapping -- a dict of mappings
     """
-    import pystache
     renderer = pystache.Renderer(decode_errors='ignore',
                                  search_dirs=htmldir)
 
@@ -366,6 +366,16 @@
             searchpaths = ['.', '/usr/share/doc/kf5', '/usr/share/doc/kde'])
     return tagfiles
 
+def generate_dependencies_page(tmp_dir, doxdatadir, modulename):
+    """Create `modulename`-dependencies.md in `tmp_dir`"""
+    template_path = os.path.join(doxdatadir, 'dependencies.md.mustache')
+    out_path = os.path.join(tmp_dir, modulename + '-dependencies.md')
+    renderer = pystache.Renderer()
+    with codecs.open(out_path, 'w', 'utf-8') as outf:
+        txt = renderer.render_path(template_path, { 'modulename': modulename})
+        outf.write(txt)
+    return out_path
+
 def generate_apidocs(modulename, fancyname, srcdir, outputdir, doxdatadir,
         tagfiles=[], man_pages=False, qhp=False, searchengine=False,
         api_searchbox=False, doxygen='doxygen', 
qhelpgenerator='qhelpgenerator',
@@ -401,77 +411,72 @@
 
     input_list = [srcdir]
     image_path_list = []
-    if dependency_diagram:
-        name = os.path.join(doxdatadir, DEPENDENCY_DIAGRAM_PAGE + '.md')
-        input_list.append(name)
-
-        # We must copy the diagram because dependencies.md refers to it as
-        # dependencies.png
-        tmp_dependency_diagram = os.path.join(os.getcwd(), 'dependencies.png')
-        shutil.copy(dependency_diagram, tmp_dependency_diagram)
-        image_path_list.append(tmp_dependency_diagram)
-
-    with tempfile.NamedTemporaryFile(delete=False) as raw_doxyfile:
-        doxyfile_path = os.path.abspath(raw_doxyfile.name)
-        doxyfile = codecs.getwriter('utf-8')(raw_doxyfile)
-
-        # Global defaults
-        with codecs.open(os.path.join(doxdatadir,'Doxyfile.global'), 'r', 
'utf-8') as f:
-            for line in f:
-                doxyfile.write(line)
-
-        writer = DoxyfileWriter(doxyfile)
-        writer.write_entry('PROJECT_NAME', fancyname)
-        # FIXME: can we get the project version from CMake?
-
-        # Input locations
-        image_path_list.extend(find_src_subdir('docs/pics'))
-        writer.write_entries(
-                INPUT=input_list,
-                DOTFILE_DIRS=find_src_subdir('docs/dot'),
-                EXAMPLE_PATH=find_src_subdir('docs/examples'),
-                IMAGE_PATH=image_path_list)
-
-        # Other input settings
-        writer.write_entry('TAGFILES', [f + '=' + loc for f, loc in tagfiles])
-
-        # Output locations
-        writer.write_entries(
-                OUTPUT_DIRECTORY=outputdir,
-                GENERATE_TAGFILE=moduletagfile,
-                HTML_OUTPUT=html_subdir,
-                WARN_LOGFILE=os.path.join(outputdir, 'doxygen-warnings.log'))
-
-        # Other output settings
-        writer.write_entries(
-                HTML_HEADER=doxdatadir + '/header.html',
-                HTML_FOOTER=doxdatadir + '/footer.html',
-                HTML_STYLESHEET=doxdatadir + '/doxygen.css')
-
-        # Always write these, even if QHP is disabled, in case Doxygen.local
-        # overrides it
-        writer.write_entries(
-                QHP_VIRTUAL_FOLDER=modulename,
-                QHG_LOCATION=qhelpgenerator)
-
-        writer.write_entries(
-                GENERATE_MAN=man_pages,
-                GENERATE_QHP=qhp,
-                SEARCHENGINE=searchengine)
-
-        writer.write_entries(**doxyfile_entries)
-
-        # Module-specific overrides
-        localdoxyfile = os.path.join(srcdir, 'docs/Doxyfile.local')
-        if os.path.isfile(localdoxyfile):
-            with codecs.open(localdoxyfile, 'r', 'utf-8') as f:
+
+    tmp_dir = tempfile.mkdtemp(prefix='kgenapidox-')
+    try:
+        if dependency_diagram:
+            input_list.append(generate_dependencies_page(tmp_dir, doxdatadir, 
modulename))
+            image_path_list.append(dependency_diagram)
+
+        doxyfile_path = os.path.join(tmp_dir, 'Doxyfile')
+        with codecs.open(doxyfile_path, 'w', 'utf-8') as doxyfile:
+
+            # Global defaults
+            with codecs.open(os.path.join(doxdatadir,'Doxyfile.global'), 'r', 
'utf-8') as f:
                 for line in f:
                     doxyfile.write(line)
 
-    subprocess.call([doxygen, doxyfile_path])
-    os.remove(doxyfile_path)
-    if dependency_diagram:
-        os.remove(tmp_dependency_diagram)
+            writer = DoxyfileWriter(doxyfile)
+            writer.write_entry('PROJECT_NAME', fancyname)
+            # FIXME: can we get the project version from CMake?
+
+            # Input locations
+            image_path_list.extend(find_src_subdir('docs/pics'))
+            writer.write_entries(
+                    INPUT=input_list,
+                    DOTFILE_DIRS=find_src_subdir('docs/dot'),
+                    EXAMPLE_PATH=find_src_subdir('docs/examples'),
+                    IMAGE_PATH=image_path_list)
+
+            # Other input settings
+            writer.write_entry('TAGFILES', [f + '=' + loc for f, loc in 
tagfiles])
+
+            # Output locations
+            writer.write_entries(
+                    OUTPUT_DIRECTORY=outputdir,
+                    GENERATE_TAGFILE=moduletagfile,
+                    HTML_OUTPUT=html_subdir,
+                    WARN_LOGFILE=os.path.join(outputdir, 
'doxygen-warnings.log'))
+
+            # Other output settings
+            writer.write_entries(
+                    HTML_HEADER=doxdatadir + '/header.html',
+                    HTML_FOOTER=doxdatadir + '/footer.html',
+                    HTML_STYLESHEET=doxdatadir + '/doxygen.css')
+
+            # Always write these, even if QHP is disabled, in case 
Doxygen.local
+            # overrides it
+            writer.write_entries(
+                    QHP_VIRTUAL_FOLDER=modulename,
+                    QHG_LOCATION=qhelpgenerator)
+
+            writer.write_entries(
+                    GENERATE_MAN=man_pages,
+                    GENERATE_QHP=qhp,
+                    SEARCHENGINE=searchengine)
+
+            writer.write_entries(**doxyfile_entries)
+
+            # Module-specific overrides
+            localdoxyfile = os.path.join(srcdir, 'docs/Doxyfile.local')
+            if os.path.isfile(localdoxyfile):
+                with codecs.open(localdoxyfile, 'r', 'utf-8') as f:
+                    for line in f:
+                        doxyfile.write(line)
+
+        subprocess.call([doxygen, doxyfile_path])
+    finally:
+        shutil.rmtree(tmp_dir)
 
     classmap = build_classmap(moduletagfile)
     write_mapping_to_php(classmap, os.path.join(outputdir, 'classmap.inc'))
@@ -482,7 +487,7 @@
             'title': title,
             'copyright': copyright,
             'api_searchbox': api_searchbox,
-            'doxygen_menu': {'entries': menu_items(htmldir)},
+            'doxygen_menu': {'entries': menu_items(htmldir, modulename)},
             'class_map': {'classes': classmap}
         }
     mapping.update(template_mapping)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/src/kapidox/data/dependencies.md 
new/kapidox-4.97.0/src/kapidox/data/dependencies.md
--- old/kapidox-4.96.0/src/kapidox/data/dependencies.md 2014-02-05 
17:07:44.000000000 +0100
+++ new/kapidox-4.97.0/src/kapidox/data/dependencies.md 1970-01-01 
01:00:00.000000000 +0100
@@ -1,4 +0,0 @@
-Dependencies {#dependencies}
-============
-
-![Dependency diagram](dependencies.png)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kapidox-4.96.0/src/kapidox/data/dependencies.md.mustache 
new/kapidox-4.97.0/src/kapidox/data/dependencies.md.mustache
--- old/kapidox-4.96.0/src/kapidox/data/dependencies.md.mustache        
1970-01-01 01:00:00.000000000 +0100
+++ new/kapidox-4.97.0/src/kapidox/data/dependencies.md.mustache        
2014-02-27 11:48:02.000000000 +0100
@@ -0,0 +1,4 @@
+Dependencies {#{{modulename}}-dependencies}
+============
+
+![Dependency diagram]({{modulename}}.png)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/src/kapidox/depdiagram/__init__.py 
new/kapidox-4.97.0/src/kapidox/depdiagram/__init__.py
--- old/kapidox-4.96.0/src/kapidox/depdiagram/__init__.py       2014-02-05 
17:07:44.000000000 +0100
+++ new/kapidox-4.97.0/src/kapidox/depdiagram/__init__.py       2014-02-27 
11:48:02.000000000 +0100
@@ -0,0 +1 @@
+from generate import *
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/src/kapidox/depdiagram/frameworkdb.py 
new/kapidox-4.97.0/src/kapidox/depdiagram/frameworkdb.py
--- old/kapidox-4.96.0/src/kapidox/depdiagram/frameworkdb.py    2014-02-05 
17:07:44.000000000 +0100
+++ new/kapidox-4.97.0/src/kapidox/depdiagram/frameworkdb.py    2014-02-27 
11:48:02.000000000 +0100
@@ -22,15 +22,15 @@
 # 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 fnmatch
 import os
 import re
-import shutil
-import tempfile
 
+import gv
 import yaml
-import yapgvb
 
+import gvutils
 from framework import Framework
 
 
@@ -51,17 +51,8 @@
     ]
 
 
-def to_temp_file(dirname, fname, content):
-    path = os.path.join(dirname, os.path.basename(fname))
-    if os.path.exists(path):
-        raise Exception("{} already exists".format(path))
-    open(path, "w").write(content)
-    return path
-
-
 def preprocess(fname):
-    lst = []
-    gfx = yapgvb.Graph().read(fname)
+    graph_handle = gv.read(fname)
     txt = open(fname).read()
     targets = []
 
@@ -80,7 +71,8 @@
     #
     # Using real framework names as labels makes it possible to merge multiple
     # .dot files.
-    for node in gfx.nodes:
+    for node_handle in gvutils.get_node_list(graph_handle):
+        node = gvutils.Node(node_handle)
         label = node.label.replace("KF5::", "")
         if node.shape in TARGET_SHAPES:
             targets.append(label)
@@ -102,8 +94,7 @@
     return txt
 
 
-def _add_extra_dependencies(fw, yaml_file):
-    dct = yaml.load(open(yaml_file))
+def _add_extra_dependencies(fw, dct):
     lst = dct.get("framework-dependencies")
     if lst is None:
         return
@@ -112,40 +103,35 @@
 
 
 class DotFileParser(object):
-    def __init__(self, tmp_dir, with_qt):
-        self._tmp_dir = tmp_dir
+    def __init__(self, with_qt):
         self._with_qt = with_qt
 
-    def parse(self, dot_file):
-        # dot_file is of the form:
-        # <dot-dir>/<tier>/<framework>/<framework>.dot
-        lst = dot_file.split("/")
-        tier = lst[-3]
-        name = lst[-2]
+    def parse(self, tier, dot_file):
+        name = os.path.basename(dot_file).replace(".dot", "")
         fw = Framework(tier, name)
 
-        # Preprocess dot files so that they can be merged together. The
-        # output needs to be stored in a temp file because yapgvb
-        # crashes when reading from a StringIO
-        tmp_file = to_temp_file(self._tmp_dir, dot_file, preprocess(dot_file))
-        self._init_fw_from_dot_file(fw, tmp_file, self._with_qt)
+        # Preprocess dot files so that they can be merged together.
+        dot_data =  preprocess(dot_file)
+        self._init_fw_from_dot_data(fw, dot_data, self._with_qt)
 
         return fw
 
-    def _init_fw_from_dot_file(self, fw, dot_file, with_qt):
+    def _init_fw_from_dot_data(self, fw, dot_data, with_qt):
         def target_from_node(node):
             return node.name.replace("KF5", "")
 
-        src = yapgvb.Graph().read(dot_file)
+        src_handle = gv.readstring(dot_data)
 
         targets = set()
-        for node in src.nodes:
+        for node_handle in gvutils.get_node_list(src_handle):
+            node = gvutils.Node(node_handle)
             if node.shape in TARGET_SHAPES and self._want(node):
                 target = target_from_node(node)
                 targets.add(target)
                 fw.add_target(target)
 
-        for edge in src.edges:
+        for edge_handle in gvutils.get_edge_list(src_handle):
+            edge = gvutils.Edge(edge_handle)
             target = target_from_node(edge.tail)
             if target in targets and self._want(edge.head):
                 dep_target = target_from_node(edge.head)
@@ -173,17 +159,18 @@
         """
         Init db from dot files
         """
-        tmp_dir = tempfile.mkdtemp(prefix="depdiagram")
-        parser = DotFileParser(tmp_dir, with_qt)
-        try:
-            for dot_file in dot_files:
-                fw = parser.parse(dot_file)
-                yaml_file = dot_file.replace(".dot", ".yaml")
-                if os.path.exists(yaml_file):
-                    _add_extra_dependencies(fw, yaml_file)
-                self._fw_list.append(fw)
-        finally:
-            shutil.rmtree(tmp_dir)
+        parser = DotFileParser(with_qt)
+        for dot_file in dot_files:
+            yaml_file = dot_file.replace(".dot", ".yaml")
+            with open(yaml_file) as f:
+                dct = yaml.load(f)
+
+            tier = dct["tier"]
+            dot_file = dot_file.encode("utf-8")
+            fw = parser.parse(tier, dot_file)
+
+            _add_extra_dependencies(fw, dct)
+            self._fw_list.append(fw)
         self._update_fw_for_target()
 
     def _update_fw_for_target(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/src/kapidox/depdiagram/generate.py 
new/kapidox-4.97.0/src/kapidox/depdiagram/generate.py
--- old/kapidox-4.96.0/src/kapidox/depdiagram/generate.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/kapidox-4.97.0/src/kapidox/depdiagram/generate.py       2014-02-27 
11:48:02.000000000 +0100
@@ -0,0 +1,173 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2014  Aurélien Gâteau <agat...@kde.org>
+#
+# 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 itertools
+import sys
+
+from kapidox.depdiagram.block import Block, quote
+from kapidox.depdiagram.framework import Framework
+from kapidox.depdiagram.frameworkdb import FrameworkDb
+
+__all__ = ('generate',)
+
+ROOT_NODE_ATTRS = dict(fontsize=12, shape="box")
+
+GROUP_ATTRS = dict(style="filled", fillcolor="grey95", color="grey85")
+
+# Blocks within groups
+OTHER_ATTRS = dict(style="filled", fillcolor="cornsilk", color="black")
+
+QT_ATTRS = dict(style="filled", fillcolor="darkseagreen1", color="black")
+
+FW_ATTRS = dict(style="filled", fillcolor="azure", color="black")
+
+# Target blocks, used with --detailed
+FW_TARGET_ATTRS = dict(style="filled", fillcolor="paleturquoise")
+
+# Highlight the wanted framework, used with --framework
+WANTED_FW_ATTRS = dict(penwidth=2)
+
+class FrameworkCmp(object):
+    def __init__(self, db):
+        self.db = db
+        self.src = set(db)
+        self.dst = []
+
+    def __call__(self, fw1, fw2):
+        if self.depends_on(fw1, fw2):
+            return 1
+        if self.depends_on(fw2, fw1):
+            return -1
+        return 0
+
+    def depends_on(self, depender_fw, provider_fw):
+        for dep_target in depender_fw.get_all_target_dependencies():
+            if provider_fw.has_target(dep_target):
+                return True
+
+            try:
+                dep_fw = self.db.get_framework_for_target(dep_target)
+            except KeyError:
+                # No framework for this target, must be an external dependency,
+                # carry on
+                continue
+            if dep_fw != depender_fw and self.depends_on(dep_fw, provider_fw):
+                return True
+
+        return False
+
+
+class DotWriter(Block):
+    def __init__(self, db, out, wanted_fw=None, detailed=False):
+        Block.__init__(self, out)
+        self.db = db
+        self.detailed = detailed
+        self.wanted_fw = wanted_fw
+
+    def write(self):
+        with self.curly_block("digraph Root") as root:
+            root.write_list_attrs("node", **ROOT_NODE_ATTRS)
+
+            other_targets = self.db.find_external_targets()
+            qt_targets = set([x for x in other_targets if x.startswith("Qt")])
+            other_targets.difference_update(qt_targets)
+
+            if qt_targets:
+                with root.cluster_block("Qt", **GROUP_ATTRS) as b:
+                    b.write_list_attrs("node", **QT_ATTRS)
+                    b.write_nodes(qt_targets)
+
+            if other_targets:
+                with root.cluster_block("Others", **GROUP_ATTRS) as b:
+                    b.write_list_attrs("node", **OTHER_ATTRS)
+                    b.write_nodes(other_targets)
+
+            lst = sorted([x for x in self.db], key=lambda x: x.tier)
+            for tier, frameworks in itertools.groupby(lst, lambda x: x.tier):
+                cluster_title = "Tier {}".format(tier)
+                with root.cluster_block(cluster_title, **GROUP_ATTRS) as 
tier_block:
+                    tier_block.write_list_attrs("node", **FW_ATTRS)
+                    # Sort frameworks within the tier to ensure frameworks 
which
+                    # depend on other frameworks from that tier are listed 
after
+                    # their dependees.
+                    frameworks = list(frameworks)
+                    for fw in sorted(frameworks, cmp=FrameworkCmp(self.db)):
+                        if self.detailed:
+                            self.write_detailed_framework(tier_block, fw)
+                        else:
+                            self.write_framework(tier_block, fw)
+
+    def write_framework(self, tier_block, fw):
+        if fw == self.wanted_fw:
+            tier_block.write_list_attrs(quote(fw.name), **WANTED_FW_ATTRS)
+        else:
+            tier_block.write_nodes([fw.name])
+        edges = set([])
+        for target in fw.get_all_target_dependencies():
+            try:
+                target_fw = self.db.get_framework_for_target(target)
+                if fw == target_fw:
+                    continue
+                dep = target_fw.name
+            except KeyError:
+                dep = target
+            edges.add((fw.name, dep))
+        for dep_fw in fw.get_extra_frameworks():
+            edges.add((fw.name, dep_fw))
+        for edge in edges:
+            tier_block.writeln('"{}" -> "{}";'.format(*edge))
+
+    def write_detailed_framework(self, tier_block, fw):
+        with tier_block.cluster_block(fw.name, **FW_ATTRS) as fw_block:
+            if fw == self.wanted_fw:
+                fw_block.write_attrs(**WANTED_FW_ATTRS)
+            fw_block.write_list_attrs("node", **FW_TARGET_ATTRS)
+            targets = sorted(fw.get_targets())
+            fw_block.write_nodes(targets)
+            for target in targets:
+                deps = fw.get_dependencies_for_target(target)
+                for dep in sorted(deps):
+                    fw_block.writeln('"{}" -> "{}";'.format(target, dep))
+
+
+def generate(out, dot_files, framework=None, with_qt=False, detailed=False):
+    db = FrameworkDb()
+    db.populate(dot_files, with_qt=with_qt)
+
+    if framework:
+        wanted_fw = db.find_by_name(framework)
+        if wanted_fw is None:
+            sys.stderr.write("No framework named {}.\n".format(framework))
+            return False
+        db.remove_unused_frameworks(wanted_fw)
+    else:
+        wanted_fw = None
+
+    writer = DotWriter(db, out, wanted_fw=wanted_fw, detailed=detailed)
+    writer.write()
+
+    return True
+
+# vi: ts=4 sw=4 et
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/src/kapidox/depdiagram/gvutils.py 
new/kapidox-4.97.0/src/kapidox/depdiagram/gvutils.py
--- old/kapidox-4.96.0/src/kapidox/depdiagram/gvutils.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/kapidox-4.97.0/src/kapidox/depdiagram/gvutils.py        2014-02-27 
11:48:02.000000000 +0100
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2014  Aurélien Gâteau <agat...@kde.org>
+#
+# 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.
+
+"""
+A set of classes and functions to make it easier to work with Graphviz graphs
+"""
+
+from __future__ import division, absolute_import, print_function, 
unicode_literals
+
+import gv
+
+
+class Node(object):
+    def __init__(self, node_handle):
+        self.handle = node_handle
+
+    @property
+    def name(self):
+        return gv.nameof(self.handle)
+
+    @property
+    def label(self):
+        return gv.getv(self.handle, b"label")
+
+    @property
+    def shape(self):
+        return gv.getv(self.handle, b"shape")
+
+
+class Edge(object):
+    def __init__(self, edge_handle):
+        self.handle = edge_handle
+
+    @property
+    def head(self):
+        handle = gv.headof(self.handle)
+        if handle is None:
+            return None
+        else:
+            return Node(handle)
+
+    @property
+    def tail(self):
+        handle = gv.tailof(self.handle)
+        if handle is None:
+            return None
+        else:
+            return Node(handle)
+
+
+def get_node_list(graph_h):
+    """Generator to iterate over all nodes of a graph"""
+    handle = gv.firstnode(graph_h)
+    while gv.ok(handle):
+        yield handle
+        handle = gv.nextnode(graph_h, handle)
+
+
+def get_edge_list(graph_h):
+    """Generator to iterate over all edges of a graph"""
+    handle = gv.firstedge(graph_h)
+    while gv.ok(handle):
+        yield handle
+        handle = gv.nextedge(graph_h, handle)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kapidox-4.96.0/src/kgenframeworksapidox 
new/kapidox-4.97.0/src/kgenframeworksapidox
--- old/kapidox-4.96.0/src/kgenframeworksapidox 2014-02-05 17:07:44.000000000 
+0100
+++ new/kapidox-4.97.0/src/kgenframeworksapidox 2014-02-27 11:48:02.000000000 
+0100
@@ -29,9 +29,19 @@
 # Python 2/3 compatibility (NB: we require at least 2.7)
 from __future__ import division, absolute_import, print_function, 
unicode_literals
 
-import argparse, os, shutil, sys
+import argparse
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
 
 from kapidox import *
+try:
+    from kapidox import depdiagram
+    DEPDIAGRAM_AVAILABLE = True
+except ImportError:
+    DEPDIAGRAM_AVAILABLE = False
 
 def get_tier(yaml_file):
     """Parse the tier out of a yaml file"""
@@ -101,6 +111,38 @@
     with open(outputfile, 'w') as outf:
         outf.write(renderer.render_path(inputfile, mapping))
 
+
+def find_dot_files(dot_dir):
+    """Returns a list of path to files ending with .dot in subdirs of 
`dot_dir`."""
+    lst = []
+    for (root, dirs, files) in os.walk(dot_dir):
+        lst.extend([os.path.join(root, x) for x in files if 
x.endswith('.dot')])
+    return lst
+
+
+def generate_diagram(fw_name, tier, dot_files, diagram_dir):
+    """Generate a dependency diagram for a framework.
+
+    Returns the full path to the generated png
+    """
+    dot_path = os.path.join(diagram_dir, fw_name + '.dot')
+    with open(dot_path, 'w') as f:
+        with_qt = tier <= 2
+        depdiagram.generate(f, dot_files, framework=fw_name, with_qt=with_qt)
+
+    png_path = os.path.join(diagram_dir, fw_name + '.png')
+    tred_proc = subprocess.Popen(['tred', dot_path], stdout=subprocess.PIPE)
+    dot_proc = subprocess.Popen(['dot', '-Tpng', '-o' + png_path],
+                                stdin=tred_proc.stdout)
+    tred_proc.stdout.close()
+    dot_proc.communicate()
+    assert dot_proc >= 0
+    if dot_proc.returncode != 0:
+        print('dot failed with error code {}'.format(dot_proc.returncode))
+        sys.exit(dot_proc.returncode)
+    return png_path
+
+
 def main():
     parser = argparse.ArgumentParser(description='Generate API documentation ' 
+
             'for the KDE Frameworks')
@@ -112,6 +154,9 @@
             help='Generate man page documentation.')
     parser.add_argument('--qhp', action='store_true',
             help='Generate Qt Compressed Help documentation.')
+    parser.add_argument('--depdiagram-dot-dir',
+            help='Generate dependency diagrams, using the .dot files from 
DIR.',
+            metavar="DIR")
     parser.add_argument('--searchengine', action='store_true',
             help="Enable Doxygen's search engine feature.")
     parser.add_argument('--api-searchbox', action='store_true',
@@ -133,8 +178,14 @@
             help='(Path to) the doxygen executable.')
     parser.add_argument('--qhelpgenerator', default='qhelpgenerator',
             help='(Path to) the qhelpgenerator executable.')
+    parser.add_argument('--keep-temp-dirs', action='store_true',
+            help='Do not delete temporary dirs, useful for debugging.')
     args = parser.parse_args()
 
+    if args.depdiagram_dot_dir and not DEPDIAGRAM_AVAILABLE:
+        print('ERROR: You need to install the Graphviz Python bindings to 
generate dependency diagrams.\nSee <http://www.graphviz.org/Download.php>.')
+        exit(1)
+
     doxdatadir = find_doxdatadir_or_exit(args.doxdatadir)
     tagfiles = search_for_tagfiles(
             suggestion = args.qtdoc_dir,
@@ -170,6 +221,7 @@
                     'fancyname': fancyname,
                     'srcdir': fwdir,
                     'outputdir': outputdir,
+                    'dependency_diagram': None,
                     })
 
     for t in range(1,5):
@@ -187,6 +239,7 @@
                 outputdir = fwinfo['outputdir'],
                 doxdatadir = doxdatadir,
                 tagfiles = tagfiles,
+                dependency_diagram = fwinfo['dependency_diagram'],
                 man_pages = args.man_pages,
                 qhp = args.qhp,
                 searchengine = args.searchengine,
@@ -225,15 +278,31 @@
     process_toplevel_html_file(os.path.join(doxdatadir, 'frameworks.html'), 
'index.html',
             title=args.title, tiers=tiers, api_searchbox=args.api_searchbox)
 
-    for t in range(1,5):
-        for fwinfo in tiers[t]:
-            gen_fw_apidocs(fwinfo)
-        if (t >= 3):
-            # Rebuild for interdependencies
-            # FIXME: can we be cleverer about deps?
+    try:
+        if args.depdiagram_dot_dir:
+            tmp_dir = tempfile.mkdtemp(prefix='kapidox-deps-')
+            dot_files = find_dot_files(args.depdiagram_dot_dir)
+            assert(dot_files)
+        else:
+            tmp_dir = None
+
+        for t in range(1,5):
             for fwinfo in tiers[t]:
-                shutil.rmtree(fwinfo['outputdir'])
-                gen_fw_apidocs(fwinfo, rebuild=True)
+                if args.depdiagram_dot_dir:
+                    fwinfo['dependency_diagram'] = 
generate_diagram(fwinfo['framework'], t, dot_files, tmp_dir)
+                gen_fw_apidocs(fwinfo)
+            if (t >= 3):
+                # Rebuild for interdependencies
+                # FIXME: can we be cleverer about deps?
+                for fwinfo in tiers[t]:
+                    shutil.rmtree(fwinfo['outputdir'])
+                    gen_fw_apidocs(fwinfo, rebuild=True)
+    finally:
+        if tmp_dir:
+            if args.keep_temp_dirs:
+                print('Kept temp dir at {}'.format(tmp_dir))
+            else:
+                shutil.rmtree(tmp_dir)
 
 
 if __name__ == "__main__":

-- 
To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org
For additional commands, e-mail: opensuse-commit+h...@opensuse.org

Reply via email to