opentofu/internal/tofu/transform_root.go

93 lines
2.7 KiB
Go
Raw Normal View History

// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2023-09-20 07:16:53 -05:00
package tofu
2015-02-04 19:02:18 -06:00
import (
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/dag"
)
2015-02-04 19:02:18 -06:00
const rootNodeName = "root"
2015-02-04 19:02:18 -06:00
// RootTransformer is a GraphTransformer that adds a root to the graph.
type RootTransformer struct{}
func (t *RootTransformer) Transform(g *Graph) error {
2022-09-27 18:25:04 -05:00
addRootNodeToGraph(g)
return nil
}
2015-02-04 19:02:18 -06:00
2022-09-27 18:25:04 -05:00
// addRootNodeToGraph modifies the given graph in-place so that it has a root
// node if it didn't already have one and so that any other node which doesn't
// already depend on something will depend on that root node.
//
// After this function returns, the graph will have only one node that doesn't
// depend on any other nodes.
func addRootNodeToGraph(g *Graph) {
// We always add the root node. This is a singleton so if it's already
// in the graph this will do nothing and just retain the existing root node.
//
2022-09-27 18:25:04 -05:00
// Note that rootNode is intentionally added by value and not by pointer
// so that all root nodes will be equal to one another and therefore
// coalesce when two valid graphs get merged together into a single graph.
g.Add(rootNode)
2015-02-04 19:02:18 -06:00
2022-09-27 18:25:04 -05:00
// Everything that doesn't already depend on at least one other node will
// depend on the root node, except the root node itself.
2015-02-04 19:02:18 -06:00
for _, v := range g.Vertices() {
2022-09-27 18:25:04 -05:00
if v == dag.Vertex(rootNode) {
2015-02-04 19:02:18 -06:00
continue
}
if g.UpEdges(v).Len() == 0 {
2022-09-27 18:25:04 -05:00
g.Connect(dag.BasicEdge(rootNode, v))
2015-02-04 19:02:18 -06:00
}
}
}
type graphNodeRoot struct{}
2022-09-27 18:25:04 -05:00
// rootNode is the singleton value representing all root graph nodes.
//
// The root node for all graphs should be this value directly, and in particular
// _not_ a pointer to this value. Using the value directly here means that
// multiple root nodes will always coalesce together when subsuming one graph
// into another.
var rootNode graphNodeRoot
2015-02-04 19:02:18 -06:00
func (n graphNodeRoot) Name() string {
return rootNodeName
2015-02-04 19:02:18 -06:00
}
// CloseRootModuleTransformer is a GraphTransformer that adds a root to the graph.
type CloseRootModuleTransformer struct {
RootConfig *configs.Config
}
func (t *CloseRootModuleTransformer) Transform(g *Graph) error {
// close the root module
closeRoot := &nodeCloseModule{
RootConfig: t.RootConfig,
}
g.Add(closeRoot)
// since this is closing the root module, make it depend on everything in
// the root module.
for _, v := range g.Vertices() {
if v == closeRoot {
continue
}
// since this is closing the root module, and must be last, we can
// connect to anything that doesn't have any up edges.
if g.UpEdges(v).Len() == 0 {
g.Connect(dag.BasicEdge(closeRoot, v))
}
}
return nil
}