github.com/cycloidio/terraform@v1.1.10-0.20220513142504-76d5c768dc63/addrs/module.go (about)

     1  package addrs
     2  
     3  import (
     4  	"strings"
     5  )
     6  
     7  // Module is an address for a module call within configuration. This is
     8  // the static counterpart of ModuleInstance, representing a traversal through
     9  // the static module call tree in configuration and does not take into account
    10  // the potentially-multiple instances of a module that might be created by
    11  // "count" and "for_each" arguments within those calls.
    12  //
    13  // This type should be used only in very specialized cases when working with
    14  // the static module call tree. Type ModuleInstance is appropriate in more cases.
    15  //
    16  // Although Module is a slice, it should be treated as immutable after creation.
    17  type Module []string
    18  
    19  // RootModule is the module address representing the root of the static module
    20  // call tree, which is also the zero value of Module.
    21  //
    22  // Note that this is not the root of the dynamic module tree, which is instead
    23  // represented by RootModuleInstance.
    24  var RootModule Module
    25  
    26  // IsRoot returns true if the receiver is the address of the root module,
    27  // or false otherwise.
    28  func (m Module) IsRoot() bool {
    29  	return len(m) == 0
    30  }
    31  
    32  func (m Module) String() string {
    33  	if len(m) == 0 {
    34  		return ""
    35  	}
    36  	var steps []string
    37  	for _, s := range m {
    38  		steps = append(steps, "module", s)
    39  	}
    40  	return strings.Join(steps, ".")
    41  }
    42  
    43  func (m Module) Equal(other Module) bool {
    44  	if len(m) != len(other) {
    45  		return false
    46  	}
    47  	for i := range m {
    48  		if m[i] != other[i] {
    49  			return false
    50  		}
    51  	}
    52  	return true
    53  }
    54  
    55  func (m Module) targetableSigil() {
    56  	// Module is targetable
    57  }
    58  
    59  // TargetContains implements Targetable for Module by returning true if the given other
    60  // address either matches the receiver, is a sub-module-instance of the
    61  // receiver, or is a targetable absolute address within a module that
    62  // is contained within the receiver.
    63  func (m Module) TargetContains(other Targetable) bool {
    64  	switch to := other.(type) {
    65  
    66  	case Module:
    67  		if len(to) < len(m) {
    68  			// Can't be contained if the path is shorter
    69  			return false
    70  		}
    71  		// Other is contained if its steps match for the length of our own path.
    72  		for i, ourStep := range m {
    73  			otherStep := to[i]
    74  			if ourStep != otherStep {
    75  				return false
    76  			}
    77  		}
    78  		// If we fall out here then the prefixed matched, so it's contained.
    79  		return true
    80  
    81  	case ModuleInstance:
    82  		return m.TargetContains(to.Module())
    83  
    84  	case ConfigResource:
    85  		return m.TargetContains(to.Module)
    86  
    87  	case AbsResource:
    88  		return m.TargetContains(to.Module)
    89  
    90  	case AbsResourceInstance:
    91  		return m.TargetContains(to.Module)
    92  
    93  	default:
    94  		return false
    95  	}
    96  }
    97  
    98  func (m Module) AddrType() TargetableAddrType {
    99  	return ModuleAddrType
   100  }
   101  
   102  // Child returns the address of a child call in the receiver, identified by the
   103  // given name.
   104  func (m Module) Child(name string) Module {
   105  	ret := make(Module, 0, len(m)+1)
   106  	ret = append(ret, m...)
   107  	return append(ret, name)
   108  }
   109  
   110  // Parent returns the address of the parent module of the receiver, or the
   111  // receiver itself if there is no parent (if it's the root module address).
   112  func (m Module) Parent() Module {
   113  	if len(m) == 0 {
   114  		return m
   115  	}
   116  	return m[:len(m)-1]
   117  }
   118  
   119  // Call returns the module call address that corresponds to the given module
   120  // instance, along with the address of the module that contains it.
   121  //
   122  // There is no call for the root module, so this method will panic if called
   123  // on the root module address.
   124  //
   125  // In practice, this just turns the last element of the receiver into a
   126  // ModuleCall and then returns a slice of the receiever that excludes that
   127  // last part. This is just a convenience for situations where a call address
   128  // is required, such as when dealing with *Reference and Referencable values.
   129  func (m Module) Call() (Module, ModuleCall) {
   130  	if len(m) == 0 {
   131  		panic("cannot produce ModuleCall for root module")
   132  	}
   133  
   134  	caller, callName := m[:len(m)-1], m[len(m)-1]
   135  	return caller, ModuleCall{
   136  		Name: callName,
   137  	}
   138  }
   139  
   140  // Ancestors returns a slice containing the receiver and all of its ancestor
   141  // modules, all the way up to (and including) the root module.  The result is
   142  // ordered by depth, with the root module always first.
   143  //
   144  // Since the result always includes the root module, a caller may choose to
   145  // ignore it by slicing the result with [1:].
   146  func (m Module) Ancestors() []Module {
   147  	ret := make([]Module, 0, len(m)+1)
   148  	for i := 0; i <= len(m); i++ {
   149  		ret = append(ret, m[:i])
   150  	}
   151  	return ret
   152  }
   153  
   154  func (m Module) configMoveableSigil() {
   155  	// ModuleInstance is moveable
   156  }