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