Builds a plan from a list of steps.
    Args:
        description (str): an arbitrary string to
            describe the plan.
        graph (:class:`Graph`): a list of :class:`Graph` to execute.
        targets (list): an optional list of step names to filter the graph to.
            If provided, only these steps, and their transitive dependencies
            will be executed. If no targets are specified, every node in the
            graph will be executed.
        reverse (bool): If provided, the graph will be walked in reverse order
            (dependencies last).

def build_plan(description, graph,
               targets=None, reverse=False):
    """Builds a plan from a list of steps.
    Args:
        description (str): an arbitrary string to
            describe the plan.
        graph (:class:`Graph`): a list of :class:`Graph` to execute.
        targets (list): an optional list of step names to filter the graph to.
            If provided, only these steps, and their transitive dependencies
            will be executed. If no targets are specified, every node in the
            graph will be executed.
        reverse (bool): If provided, the graph will be walked in reverse order
            (dependencies last).
    """

    # If we want to execute the plan in reverse (e.g. Destroy), transpose the
    # graph.
    if reverse:
        graph = graph.transposed()

    # If we only want to build a specific target, filter the graph.
    if targets:
        nodes = []
        for target in targets:
            for k, step in graph.steps.items():
                if step.name == target:
                    nodes.append(step.name)
        graph = graph.filtered(nodes)

    return Plan(description=description, graph=graph)