def _exclude_task(task):
    return task.id[0] in [
        'module_check',
        'scan_deps',
    ]

def render_graph(ctx):
    import graphviz

    dot = graphviz.Digraph(name = 'erect.deps')
    dot.attr(rankdir = 'LR')

    for path, file in ctx.files.items():
        # Exclude source files.
        if file.generator_task is None:
            continue

        # Exclude file generated by excluded tasks.
        if file.generator_task is not None and _exclude_task(file.generator_task):
            continue

        dot.node(str(path), color = 'blue')

        if file.generator_task is not None:
            dot.edge(file.generator_task.id.str, str(path))

    for id, task in ctx.tasks.items():
        if _exclude_task(task):
            continue

        dot.node(id.str, color = 'red')

        for dep in task.dependencies:
            if _exclude_task(dep):
                continue
            dot.edge(dep.id.str, id.str)

        for file in task._input_files:
            if file.generator_task is None:
                continue

            dot.edge(str(file.path), id.str)

    dot.render(view = True)
