github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/terraform/transform_root.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package terraform
     5  
     6  import (
     7  	"github.com/terramate-io/tf/dag"
     8  )
     9  
    10  const rootNodeName = "root"
    11  
    12  // RootTransformer is a GraphTransformer that adds a root to the graph.
    13  type RootTransformer struct{}
    14  
    15  func (t *RootTransformer) Transform(g *Graph) error {
    16  	addRootNodeToGraph(g)
    17  	return nil
    18  }
    19  
    20  // addRootNodeToGraph modifies the given graph in-place so that it has a root
    21  // node if it didn't already have one and so that any other node which doesn't
    22  // already depend on something will depend on that root node.
    23  //
    24  // After this function returns, the graph will have only one node that doesn't
    25  // depend on any other nodes.
    26  func addRootNodeToGraph(g *Graph) {
    27  	// We always add the root node. This is a singleton so if it's already
    28  	// in the graph this will do nothing and just retain the existing root node.
    29  	//
    30  	// Note that rootNode is intentionally added by value and not by pointer
    31  	// so that all root nodes will be equal to one another and therefore
    32  	// coalesce when two valid graphs get merged together into a single graph.
    33  	g.Add(rootNode)
    34  
    35  	// Everything that doesn't already depend on at least one other node will
    36  	// depend on the root node, except the root node itself.
    37  	for _, v := range g.Vertices() {
    38  		if v == dag.Vertex(rootNode) {
    39  			continue
    40  		}
    41  
    42  		if g.UpEdges(v).Len() == 0 {
    43  			g.Connect(dag.BasicEdge(rootNode, v))
    44  		}
    45  	}
    46  }
    47  
    48  type graphNodeRoot struct{}
    49  
    50  // rootNode is the singleton value representing all root graph nodes.
    51  //
    52  // The root node for all graphs should be this value directly, and in particular
    53  // _not_ a pointer to this value. Using the value directly here means that
    54  // multiple root nodes will always coalesce together when subsuming one graph
    55  // into another.
    56  var rootNode graphNodeRoot
    57  
    58  func (n graphNodeRoot) Name() string {
    59  	return rootNodeName
    60  }
    61  
    62  // CloseRootModuleTransformer is a GraphTransformer that adds a root to the graph.
    63  type CloseRootModuleTransformer struct{}
    64  
    65  func (t *CloseRootModuleTransformer) Transform(g *Graph) error {
    66  	// close the root module
    67  	closeRoot := &nodeCloseModule{}
    68  	g.Add(closeRoot)
    69  
    70  	// since this is closing the root module, make it depend on everything in
    71  	// the root module.
    72  	for _, v := range g.Vertices() {
    73  		if v == closeRoot {
    74  			continue
    75  		}
    76  
    77  		// since this is closing the root module,  and must be last, we can
    78  		// connect to anything that doesn't have any up edges.
    79  		if g.UpEdges(v).Len() == 0 {
    80  			g.Connect(dag.BasicEdge(closeRoot, v))
    81  		}
    82  	}
    83  
    84  	return nil
    85  }