Skip to content
Snippets Groups Projects
Commit ce61b079 authored by Tiago de Freitas Pereira's avatar Tiago de Freitas Pereira Committed by André Anjos
Browse files

Removed Dependency graph script

parent fde2bfa6
No related branches found
No related tags found
No related merge requests found
from .dependency_graph import main as dependency_graph
from .main_cli import main as main_cli from .main_cli import main as main_cli
from . import click_helper from . import click_helper
......
#!../bin/python
"""
This script will generate a dependency graph of the given bob package(s) using the external tool ``dot``.
Packages can be either specified as a list of ``--packages`` or read from (several) ``--package-files``.
The latter option is mostly useful to generate a dot graph for all Bob packages.
The output is written to the given ``--output-file``, writing either the specified intermediate ``--dot-file``, or a temporary file.
When the ``--plot-external-dependencies`` is selected, also external (Python-)dependencies will be plotted as well, in red ellipses.
"""
from __future__ import print_function
import subprocess
import pkg_resources
import tempfile, os
import argparse
def main(command_line_options = None):
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("--packages", '-p', nargs = '+', default = [], help = "Which packages do you want to have dependencies for?")
parser.add_argument("--package-files", '-P', nargs = '+', default = [], help = "Read packages from the given files (usually requirement?.txt files of bob).")
parser.add_argument("--dot-file", "-W", help = "If specified, the .dot file is written to the given file.")
parser.add_argument("--output-file", "-w", default="dependencies.png", help = "Specify the (.png) file to write.")
parser.add_argument("--limit-packages", '-l', nargs = '+', default = ['bob', 'facereclib', 'antispoofing'], help = "Limit packages read from --package-files to the given namespaces")
parser.add_argument("--plot-external-dependencies", '-X', action='store_true', help = "Include external dependencies into the plot?")
parser.add_argument("--rank-base-tools-same", '-R', action = 'store_true', help = "Set the rank of packages bob.extension, bob.core and bob.blitz at the same size")
parser.add_argument("--vertical", '-V', action = 'store_true', help = "Display the dot graph in vertical direction")
parser.add_argument("--verbose", '-v', action = 'store_true', help = "Print more information")
args = parser.parse_args(command_line_options)
args.limit_packages = tuple(args.limit_packages)
# collect packages
packages = args.packages[:]
for package_file in args.package_files:
for line in open(package_file):
splits = line.rstrip().split()
packages.extend([p for p in splits if p not in packages and p.startswith(args.limit_packages)])
# generate dependencies
dependencies = {}
cpp_dependencies = {}
has_parents = set()
# function to add dependencies of packages recursively
def _add_recursive(p):
# check if package already parsed
if p not in dependencies:
if args.verbose:
print("Checking %s" % p)
deps = pkg_resources.require(p)
dependencies[p] = [d.key for d in deps[1:]]
if args.plot_external_dependencies and p.startswith(args.limit_packages):
# also load the C++ dependencies, stored in the .version package
import importlib
lib = importlib.import_module(p)
try:
cpp_dependencies[p] = [dep for dep in lib.version.externals.keys() if not dep.startswith(args.limit_packages)]
except AttributeError:
cpp_dependencies[p] = []
for d in dependencies[p]:
has_parents.add(d)
_add_recursive(d)
for package in packages:
_add_recursive(package)
# prune dependencies
pruned_dependencies = {}
for package in dependencies:
indirect_dependencies = set(d for i in [dependencies[dep] for dep in dependencies[package] if dep in dependencies] for d in i)
pruned_dependencies[package] = [dep for dep in dependencies[package] if dep not in indirect_dependencies]
# split all dependencies that are from bob (i.e., that belong to the --limit-packages) or not
bob = set(package for package in pruned_dependencies if package.startswith(args.limit_packages))
non_bob = set(dep for package in bob for dep in pruned_dependencies[package] if not dep.startswith(args.limit_packages))
final = set(package for package in bob if package not in has_parents)
# also prune the C++ dependencies
if args.plot_external_dependencies:
pruned_cpp_dependencies = {}
for package in cpp_dependencies:
indirect_dependencies = set(d for i in [cpp_dependencies[dep] for dep in dependencies[package] if dep in dependencies and dep in cpp_dependencies] for d in i)
pruned_cpp_dependencies[package] = [dep for dep in cpp_dependencies[package] if dep not in indirect_dependencies]
cpp = set(dep for package in bob for dep in pruned_cpp_dependencies[package])
# function to return a name for the package that can serve as a dot variable
def _n(p):
return p.replace(".", "_").replace("-","_").replace("+","X")
# write dependency graph
dot_file = args.dot_file if args.dot_file is not None else tempfile.mkstemp(suffix='.dot')[1]
with open(dot_file, 'w') as f:
# open plot
f.write("digraph Bob {\n")
if not args.vertical:
f.write("\trankdir=LR;\n")
# write bob packages in squares
for package in bob:
f.write('\t%s [label="%s",shape=box,group=%s,style=filled,color=%s];\n' % (_n(package), package, "_".join(package.split('.')[:2]), 'green' if package in final else 'lightblue'))
# write non-bob packages in squares
if args.plot_external_dependencies:
for package in non_bob:
f.write('\t%s [label="%s",shape=box,color=red];\n' % (_n(package), package))
for package in cpp:
f.write('\t%s [label="%s",color=red];\n' % (_n(package), package))
# write dependencies
for package in bob:
for dep in pruned_dependencies[package]:
if dep in bob:
f.write('\t%s -> %s [color=blue];\n' % (_n(package), _n(dep)))
elif args.plot_external_dependencies:
f.write('\t%s -> %s [color=red,style=dashed];\n' % (_n(package), _n(dep)))
if args.plot_external_dependencies:
for dep in pruned_cpp_dependencies[package]:
f.write('\t%s -> %s [color=red,style=dashed];\n' % (_n(package), _n(dep)))
# rank base tools at the same level
if args.rank_base_tools_same:
f.write('\t{rank=same; bob_extension bob_core bob_blitz}\n')
f.write("}\n")
if args.verbose and args.dot_file is not None:
print("Wrote dot file %s" % dot_file)
# call dot
call = ["dot", '-y', '-o', args.output_file, '-Tpng:cairo:gd', dot_file]
if args.verbose:
call[1:1] = ['-v']
print("Calling dot: '%s'" % " ".join(call))
subprocess.call(call)
if args.verbose:
print("\nWrote file %s" % args.output_file)
# clean-up
if args.dot_file is None:
os.remove(dot_file)
...@@ -6,8 +6,6 @@ package: ...@@ -6,8 +6,6 @@ package:
version: {{ environ.get('BOB_PACKAGE_VERSION', '0.0.1') }} version: {{ environ.get('BOB_PACKAGE_VERSION', '0.0.1') }}
build: build:
entry_points:
- bob_dependecy_graph.py = bob.extension.scripts:dependency_graph
number: {{ environ.get('BOB_BUILD_NUMBER', 0) }} number: {{ environ.get('BOB_BUILD_NUMBER', 0) }}
run_exports: run_exports:
- {{ pin_subpackage(name) }} - {{ pin_subpackage(name) }}
...@@ -34,7 +32,6 @@ test: ...@@ -34,7 +32,6 @@ test:
imports: imports:
- {{ name }} - {{ name }}
commands: commands:
- bob_dependecy_graph.py --help
- bob -h - bob -h
- bob --help - bob --help
- bob config -h - bob config -h
......
...@@ -27,7 +27,6 @@ setup( ...@@ -27,7 +27,6 @@ setup(
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [
'bob = bob.extension.scripts:main_cli', 'bob = bob.extension.scripts:main_cli',
'bob_dependecy_graph.py = bob.extension.scripts:dependency_graph',
], ],
'bob.cli': [ 'bob.cli': [
'config = bob.extension.scripts.config:config', 'config = bob.extension.scripts.config:config',
......
3.2.1b0 4.0.0b0
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment