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