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 }