11package module
22
33import (
4+ "fmt"
5+ "sync"
6+
47 "github.com/hashicorp/terraform/config"
58)
69
@@ -10,8 +13,9 @@ import (
1013// all the modules without getting, flatten the tree into something
1114// Terraform can use, etc.
1215type Tree struct {
13- Config * config.Config
14- Children []* Tree
16+ config * config.Config
17+ children []* Tree
18+ lock sync.Mutex
1519}
1620
1721// GetMode is an enum that describes how modules are loaded.
@@ -35,7 +39,15 @@ const (
3539
3640// NewTree returns a new Tree for the given config structure.
3741func NewTree (c * config.Config ) * Tree {
38- return & Tree {Config : c }
42+ return & Tree {config : c }
43+ }
44+
45+ // Children returns the children of this tree (the modules that are
46+ // imported by this root).
47+ //
48+ // This will only return a non-nil value after Load is called.
49+ func (t * Tree ) Children () []* Tree {
50+ return nil
3951}
4052
4153// Flatten takes the entire module tree and flattens it into a single
@@ -54,10 +66,10 @@ func (t *Tree) Flatten() (*config.Config, error) {
5466// This is only the imports of _this_ level of the tree. To retrieve the
5567// full nested imports, you'll have to traverse the tree.
5668func (t * Tree ) Modules () []* Module {
57- result := make ([]* Module , len (t .Config .Modules ))
58- for i , m := range t .Config .Modules {
69+ result := make ([]* Module , len (t .config .Modules ))
70+ for i , m := range t .config .Modules {
5971 result [i ] = & Module {
60- Name : m .Name ,
72+ Name : m .Name ,
6173 Source : m .Source ,
6274 }
6375 }
@@ -70,11 +82,66 @@ func (t *Tree) Modules() []*Module {
7082// The parameters are used to tell the tree where to find modules and
7183// whether it can download/update modules along the way.
7284//
85+ // Calling this multiple times will reload the tree.
86+ //
7387// Various semantic-like checks are made along the way of loading since
7488// module trees inherently require the configuration to be in a reasonably
7589// sane state: no circular dependencies, proper module sources, etc. A full
7690// suite of validations can be done by running Validate (after loading).
7791func (t * Tree ) Load (s Storage , mode GetMode ) error {
92+ t .lock .Lock ()
93+ defer t .lock .Unlock ()
94+
95+ // Reset the children if we have any
96+ t .children = nil
97+
98+ modules := t .Modules ()
99+ children := make ([]* Tree , len (modules ))
100+
101+ // Go through all the modules and get the directory for them.
102+ update := mode == GetModeUpdate
103+ for i , m := range modules {
104+ source , err := Detect (m .Source , m .Dir )
105+ if err != nil {
106+ return fmt .Errorf ("module %s: %s" , m .Name , err )
107+ }
108+
109+ if mode > GetModeNone {
110+ // Get the module since we specified we should
111+ if err := s .Get (source , update ); err != nil {
112+ return err
113+ }
114+ }
115+
116+ // Get the directory where this module is so we can load it
117+ dir , ok , err := s .Dir (source )
118+ if err != nil {
119+ return err
120+ }
121+ if ! ok {
122+ return fmt .Errorf (
123+ "module %s: not found, may need to be downloaded" , m .Name )
124+ }
125+
126+ // Load the configuration
127+ c , err := config .LoadDir (dir )
128+ if err != nil {
129+ return fmt .Errorf (
130+ "module %s: %s" , m .Name , err )
131+ }
132+ children [i ] = NewTree (c )
133+ }
134+
135+ // Go through all the children and load them.
136+ for _ , c := range children {
137+ if err := c .Load (s , mode ); err != nil {
138+ return err
139+ }
140+ }
141+
142+ // Set our tree up
143+ t .children = children
144+
78145 return nil
79146}
80147
0 commit comments