Commit a700c950 authored by Tiago de Freitas Pereira's avatar Tiago de Freitas Pereira Committed by André Anjos

Implemented a mechanism to run a dependency graph

parent 23eb0125
Pipeline #35373 passed with stage
in 2 minutes and 59 seconds
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import conda.cli.python_api
import json
from .log import verbosity_option, get_logger, echo_info
logger = get_logger(__name__)
from graphviz import Digraph
def get_graphviz_dependency_graph(
graph_dict,
file_name,
prefix="bob.",
black_list=["python", "setuptools", "libcxx", "numpy", "libblitz", "boost"],
):
"""
Given a dictionary with the dependency graph, compute the graphviz DAG and save it
in SVG
"""
d = Digraph(format="svg", engine="dot")
for i in graph_dict:
for j in graph_dict[i]:
# Conections to python, setuptools....gets very messy
if j in black_list:
continue
if prefix in j:
d.attr("node", shape="box")
else:
d.attr("node", shape="ellipse")
d.edge(i, j)
d.render(file_name)
def compute_dependency_graph(
package_name, channel=None, selected_packages=[], prefix="bob.", dependencies=dict()
):
"""
Given a target package, returns an adjacency matrix with its dependencies returned via the command `conda search xxxx --info`
**Parameters**
package_name:
Name of the package
channel:
Name of the channel to be sent via `-c` option. If None `conda search` will use what is in .condarc
selected_packages:
List of target packages. If set, the returned adjacency matrix will be in terms of this list.
prefix:
Only seach for deep dependencies under the prefix. This would avoid to go deeper in
dependencies not maintained by us, such as, numpy, matplotlib, etc..
dependencies:
Dictionary controlling the state of each search
"""
if package_name in dependencies:
return dependencies
dependencies[package_name] = fetch_dependencies(
package_name, channel, selected_packages
)
logger.info(f" >> Searching dependencies of {package_name}")
for d in dependencies[package_name]:
if prefix in d:
compute_dependency_graph(
d, channel, selected_packages, prefix, dependencies
)
return dependencies
def fetch_dependencies(package_name, channel=None, selected_packages=[]):
"""
conda search the dependencies of a package
**Parameters**
packge_name:
channel:
selected_packages:
"""
# Running conda search and returns to a json file
if channel is None:
package_description = conda.cli.python_api.run_command(
conda.cli.python_api.Commands.SEARCH, package_name, "--info", "--json"
)
else:
package_description = conda.cli.python_api.run_command(
conda.cli.python_api.Commands.SEARCH,
package_name,
"--info",
"-c",
channel,
"--json",
)
# TODO: Fix that
package_description = json.loads(package_description[0])
# Fetching the dependencies of the most updated package
all_dependencies = [
p.split(" ")[0] for p in package_description[package_name][-1]["depends"]
]
if len(selected_packages) > 0:
# Filtering the dependencies
return [d for d in selected_packages if d in all_dependencies]
return all_dependencies
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import click
from click_plugins import with_plugins
from ..graph import compute_dependency_graph, get_graphviz_dependency_graph
from ..log import verbosity_option, get_logger, echo_info
logger = get_logger(__name__)
@click.command(
epilog="""
Example:
bdt graph bob.bio.face graph
"""
)
@click.argument("package_name", required=True)
@click.argument("output_file", required=True)
@click.option(
"-c",
"--channel",
default=None,
help="Define a target channel for conda serch. If not set, will use what is set in .condarc",
)
@click.option(
"-p",
"--prefix",
default="bob.",
help="It will recursivelly look into dependencies whose package name matches the prefix. Default 'bob.'",
)
@verbosity_option()
def graph(package_name, output_file, channel, prefix):
"""
Compute the dependency graph of a conda package and save it in an SVG file using graphviz.
"""
logger.info(f"Computing dependency graph")
graph_dict = compute_dependency_graph(package_name, channel=channel, prefix=prefix)
logger.info("Generating SVG")
get_graphviz_dependency_graph(graph_dict, output_file, prefix=prefix)
......@@ -49,6 +49,7 @@ requirements:
- termcolor
- psutil
- tabulate
- python-graphviz
test:
requires:
......@@ -104,6 +105,7 @@ test:
- bdt dav upload --help
- bdt gitlab process-pipelines --help
- bdt gitlab get-pipelines --help
- bdt graph --help
- sphinx-build -aEW ${PREFIX}/share/doc/{{ name }}/doc sphinx
- if [ -n "${CI_PROJECT_DIR}" ]; then mv sphinx "${CI_PROJECT_DIR}/"; fi
......
......@@ -56,6 +56,7 @@ setup(
'dav = bob.devtools.scripts.dav:dav',
'local = bob.devtools.scripts.local:local',
'gitlab = bob.devtools.scripts.gitlab:gitlab',
'graph = bob.devtools.scripts.graph:graph'
],
'bdt.gitlab.cli': [
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment