Commit e1863341 authored by Jérome Perrin's avatar Jérome Perrin

New experimental "graph" command

Produce a graphviz compatible graph of the parts dependencies.
fdp layout option seems to produce more readable graphs in this case.
Example invocation:
  buildout graph | fdp -t svg -o buildout.svg
parent 3f32153f
...@@ -1271,6 +1271,69 @@ class Buildout(DictMixin): ...@@ -1271,6 +1271,69 @@ class Buildout(DictMixin):
def annotate(self, args=None): def annotate(self, args=None):
_print_annotate(self._annotated) _print_annotate(self._annotated)
def graph(self, args=None):
nodes = set([])
edges = set([])
def getRecipe(part):
recipe = self._raw[part].get('recipe')
if recipe:
return recipe
macro = self._raw[part].get('<')
if macro:
return getRecipe(macro)
_template_split = re.compile('([$]{[^}]*})').split
print_("digraph {")
for part in self._raw['buildout']['parts'].splitlines():
if part:
nodes.add(part)
print_(' buildout -> "%s"' % part)
for option, value in self._raw[part].items():
if value == '<': # XXX macro
nodes.add(option)
edges.add((part, option))
if "${" in value:
for sub in _template_split(value):
if sub.startswith("${"):
dependency = sub[2:].split(":")[0]
if dependency and dependency != 'buildout':
nodes.add(dependency)
edges.add((part, dependency))
for (part, dependency) in edges:
print_(
' "%s" -> "%s"' % (
part,
dependency))
recipe_colors = {
'slapos.recipe.cmmi': '#00AA00',
'slapos.recipe.build': '#FF0000',
'slapos.recipe.build:gitclone': '#996666',
'slapos.recipe.build:download-unpacked': '#FF00FF',
'zc.recipe.egg': '#333399',
'zc.recipe.egg:custom': '#444499',
'zc.recipe.egg:scripts': '#666699',
}
for node in nodes:
recipe = getRecipe(node) or ''
print_(
'''"{part_name}" [
shape=record
label="{{{part_name}|{recipe}}}"
style=filled
fillcolor="{color}"
]
'''.format(part_name=node,
recipe=recipe,
color=recipe_colors.get(recipe, "#FFFFFF")))
print_("}")
def print_options(self): def print_options(self):
for section in sorted(self._data): for section in sorted(self._data):
if section == 'buildout' or section == self['buildout']['versions']: if section == 'buildout' or section == self['buildout']['versions']:
...@@ -2122,6 +2185,13 @@ Commands: ...@@ -2122,6 +2185,13 @@ Commands:
The script can be given either as a script path or a path to a The script can be given either as a script path or a path to a
directory containing a setup.py script. directory containing a setup.py script.
graph
Produce a graphviz compatible graph of the parts dependencies.
fdp layout option seems to produce more readable graphs in this case.
Example invocation:
buildout graph | fdp -t svg -o buildout.svg
annotate annotate
Display annotated sections. All sections are displayed, sorted Display annotated sections. All sections are displayed, sorted
...@@ -2229,7 +2299,7 @@ def main(args=None): ...@@ -2229,7 +2299,7 @@ def main(args=None):
command = args.pop(0) command = args.pop(0)
if command not in ( if command not in (
'install', 'bootstrap', 'runsetup', 'setup', 'init', 'install', 'bootstrap', 'runsetup', 'setup', 'init',
'annotate', 'annotate', 'graph'
): ):
_error('invalid command:', command) _error('invalid command:', command)
else: else:
......
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